fix(isolated-declarations): function overloads reaching unreachable (#3739)

This commit is contained in:
Dunqing 2024-06-18 16:14:14 +00:00
parent 256acc949b
commit f1b793fbba
2 changed files with 139 additions and 88 deletions

View file

@ -105,14 +105,10 @@ impl<'a> IsolatedDeclarations<'a> {
return None; return None;
} }
FunctionReturnType::infer( function.body.as_ref().and_then(|body| {
self, FunctionReturnType::infer(self, body)
function .map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
.body })
.as_ref()
.unwrap_or_else(|| unreachable!("Only declare function can have no body")),
)
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
} }
pub fn infer_arrow_function_return_type( pub fn infer_arrow_function_return_type(

View file

@ -22,7 +22,7 @@ use oxc_allocator::Allocator;
#[allow(clippy::wildcard_imports)] #[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, AstBuilder, Visit}; use oxc_ast::{ast::*, AstBuilder, Visit};
use oxc_diagnostics::OxcDiagnostic; use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{SourceType, SPAN}; use oxc_span::{Atom, SourceType, SPAN};
use crate::scope::ScopeTree; use crate::scope::ScopeTree;
@ -86,27 +86,16 @@ impl<'a> IsolatedDeclarations<'a> {
if has_import_or_export { if has_import_or_export {
self.transform_statements_on_demand(&program.body) self.transform_statements_on_demand(&program.body)
} else { } else {
self.transform_program_without_module_declaration(program) self.transform_program_without_module_declaration(&program.body)
}
}
pub fn modifiers_declare(&self) -> Modifiers<'a> {
if self.scope.is_ts_module_block_flag() {
// If we are in a module block, we don't need to add declare
Modifiers::empty()
} else {
Modifiers::new(
self.ast.new_vec_single(Modifier { span: SPAN, kind: ModifierKind::Declare }),
)
} }
} }
pub fn transform_program_without_module_declaration( pub fn transform_program_without_module_declaration(
&mut self, &mut self,
program: &Program<'a>, stmts: &oxc_allocator::Vec<'a, Statement<'a>>,
) -> oxc_allocator::Vec<'a, Statement<'a>> { ) -> oxc_allocator::Vec<'a, Statement<'a>> {
let mut new_ast_stmts = self.ast.new_vec::<Statement<'a>>(); let mut new_ast_stmts = self.ast.new_vec::<Statement<'a>>();
for stmt in &program.body { for stmt in Self::remove_function_overloads_implementation(self.ast.copy(stmts)) {
if let Some(decl) = stmt.as_declaration() { if let Some(decl) = stmt.as_declaration() {
if let Some(decl) = self.transform_declaration(decl, false) { if let Some(decl) = self.transform_declaration(decl, false) {
new_ast_stmts.push(Statement::from(decl)); new_ast_stmts.push(Statement::from(decl));
@ -130,68 +119,75 @@ impl<'a> IsolatedDeclarations<'a> {
// 2. Transform export declarations // 2. Transform export declarations
// 3. Collect all bindings / reference from module declarations // 3. Collect all bindings / reference from module declarations
// 4. Collect transformed indexes // 4. Collect transformed indexes
stmts.iter().for_each(|stmt| match stmt { for stmt in Self::remove_function_overloads_implementation(self.ast.copy(stmts)) {
match_declaration!(Statement) => { match stmt {
match stmt.to_declaration() { match_declaration!(Statement) => {
Declaration::VariableDeclaration(decl) => { match stmt.to_declaration() {
variables_declarations.push_back( Declaration::VariableDeclaration(decl) => {
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(), variables_declarations.push_back(
); self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
variable_transformed_indexes.push_back(Vec::default()); );
variable_transformed_indexes.push_back(Vec::default());
}
Declaration::UsingDeclaration(decl) => {
variables_declarations.push_back(
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
);
variable_transformed_indexes.push_back(Vec::default());
}
_ => {}
} }
Declaration::UsingDeclaration(decl) => { new_stmts.push(stmt);
variables_declarations.push_back(
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
);
variable_transformed_indexes.push_back(Vec::default());
}
_ => {}
} }
new_stmts.push(self.ast.copy(stmt)); match_module_declaration!(Statement) => {
} transformed_indexes.push(new_stmts.len());
match_module_declaration!(Statement) => { match stmt.to_module_declaration() {
transformed_indexes.push(new_stmts.len()); ModuleDeclaration::ExportDefaultDeclaration(decl) => {
match stmt.to_module_declaration() { if let Some((var_decl, new_decl)) =
ModuleDeclaration::ExportDefaultDeclaration(decl) => { self.transform_export_default_declaration(decl)
if let Some((var_decl, new_decl)) = {
self.transform_export_default_declaration(decl) if let Some(var_decl) = var_decl {
{ self.scope.visit_variable_declaration(&var_decl);
if let Some(var_decl) = var_decl { new_stmts.push(Statement::VariableDeclaration(
self.scope.visit_variable_declaration(&var_decl); self.ast.alloc(var_decl),
new_stmts ));
.push(Statement::VariableDeclaration(self.ast.alloc(var_decl))); transformed_indexes.push(new_stmts.len());
transformed_indexes.push(new_stmts.len()); }
self.scope.visit_export_default_declaration(&new_decl);
new_stmts.push(Statement::ExportDefaultDeclaration(
self.ast.alloc(new_decl),
));
continue;
} }
self.scope.visit_export_default_declaration(&new_decl); self.scope.visit_export_default_declaration(decl);
new_stmts.push(Statement::ExportDefaultDeclaration(
self.ast.alloc(new_decl),
));
return;
} }
self.scope.visit_export_default_declaration(decl); ModuleDeclaration::ExportNamedDeclaration(decl) => {
} if let Some(new_decl) = self.transform_export_named_declaration(decl) {
ModuleDeclaration::ExportNamedDeclaration(decl) => { self.scope.visit_declaration(
if let Some(new_decl) = self.transform_export_named_declaration(decl) { new_decl.declaration.as_ref().unwrap_or_else(|| unreachable!()),
self.scope.visit_declaration( );
new_decl.declaration.as_ref().unwrap_or_else(|| unreachable!()),
);
new_stmts new_stmts.push(Statement::ExportNamedDeclaration(
.push(Statement::ExportNamedDeclaration(self.ast.alloc(new_decl))); self.ast.alloc(new_decl),
return; ));
continue;
}
self.scope.visit_export_named_declaration(decl);
}
module_declaration => {
self.scope.visit_module_declaration(module_declaration);
} }
self.scope.visit_export_named_declaration(decl);
} }
module_declaration => self.scope.visit_module_declaration(module_declaration),
new_stmts.push(stmt);
} }
_ => {}
new_stmts.push(self.ast.copy(stmt));
} }
_ => {} }
});
// 5. Transform statements until no more transformation can be done // 5. Transform statements until no more transformation can be done
let mut last_reference_len = 0; let mut last_reference_len = 0;
@ -201,13 +197,11 @@ impl<'a> IsolatedDeclarations<'a> {
let mut variables_declarations_iter = variables_declarations.iter_mut(); let mut variables_declarations_iter = variables_declarations.iter_mut();
let mut variable_transformed_indexes_iter = variable_transformed_indexes.iter_mut(); let mut variable_transformed_indexes_iter = variable_transformed_indexes.iter_mut();
(0..new_stmts.len()).for_each(|i| { for (i, stmt) in new_stmts.iter_mut().enumerate() {
if transformed_indexes.contains(&i) { if transformed_indexes.contains(&i) {
return; continue;
} }
let Some(decl) = new_stmts[i].as_declaration() else { let Some(decl) = stmt.as_declaration() else { continue };
return;
};
if let Declaration::VariableDeclaration(_) | Declaration::UsingDeclaration(_) = decl if let Declaration::VariableDeclaration(_) | Declaration::UsingDeclaration(_) = decl
{ {
@ -219,25 +213,23 @@ impl<'a> IsolatedDeclarations<'a> {
unreachable!() unreachable!()
}; };
(0..cur_variable_declarations.len()).for_each(|ii| { for (ii, declarator) in cur_variable_declarations.iter_mut().enumerate() {
if cur_transformed_indexes.contains(&ii) { if cur_transformed_indexes.contains(&ii) {
return; continue;
} }
if let Some(decl) = if let Some(decl) = self.transform_variable_declarator(declarator, true) {
self.transform_variable_declarator(&cur_variable_declarations[ii], true)
{
self.scope.visit_variable_declarator(&decl); self.scope.visit_variable_declarator(&decl);
cur_transformed_indexes.push(ii); cur_transformed_indexes.push(ii);
cur_variable_declarations[ii] = decl; *declarator = decl;
} }
}); }
} else if let Some(decl) = self.transform_declaration(decl, true) { } else if let Some(decl) = self.transform_declaration(decl, true) {
self.scope.visit_declaration(&decl); self.scope.visit_declaration(&decl);
transformed_indexes.push(i); transformed_indexes.push(i);
new_stmts[i] = Statement::from(decl); *stmt = Statement::from(decl);
} }
}); }
} }
// 6. Transform variable/using declarations, import statements, remove unused imports // 6. Transform variable/using declarations, import statements, remove unused imports
@ -304,4 +296,67 @@ impl<'a> IsolatedDeclarations<'a> {
new_ast_stmts new_ast_stmts
} }
pub fn remove_function_overloads_implementation(
stmts: oxc_allocator::Vec<'a, Statement<'a>>,
) -> impl Iterator<Item = Statement<'a>> + '_ {
let mut last_function_name: Option<Atom<'a>> = None;
stmts.into_iter().filter_map(move |stmt| match stmt {
Statement::FunctionDeclaration(ref func) => {
let name = &func
.id
.as_ref()
.unwrap_or_else(|| {
unreachable!(
"Only export default function declaration is allowed to have no name"
)
})
.name;
if last_function_name.as_ref().is_some_and(|last_name| last_name == name)
&& func.body.is_some()
{
None
} else {
last_function_name = Some(name.clone());
Some(stmt)
}
}
Statement::ExportNamedDeclaration(ref decl) => {
if let Some(Declaration::FunctionDeclaration(ref func)) = decl.declaration {
let name = &func
.id
.as_ref()
.unwrap_or_else(|| {
unreachable!(
"Only export default function declaration is allowed to have no name"
)
})
.name;
if last_function_name.as_ref().is_some_and(|last_name| last_name == name)
&& func.body.is_some()
{
None
} else {
last_function_name = Some(name.clone());
Some(stmt)
}
} else {
Some(stmt)
}
}
_ => Some(stmt),
})
}
pub fn modifiers_declare(&self) -> Modifiers<'a> {
if self.scope.is_ts_module_block_flag() {
// If we are in a module block, we don't need to add declare
Modifiers::empty()
} else {
Modifiers::new(
self.ast.new_vec_single(Modifier { span: SPAN, kind: ModifierKind::Declare }),
)
}
}
} }