mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(isolated-declarations): function overloads reaching unreachable (#3739)
This commit is contained in:
parent
256acc949b
commit
f1b793fbba
2 changed files with 139 additions and 88 deletions
|
|
@ -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
|
|
||||||
.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))
|
.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(
|
||||||
|
|
|
||||||
|
|
@ -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,7 +119,8 @@ 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 stmt {
|
||||||
match_declaration!(Statement) => {
|
match_declaration!(Statement) => {
|
||||||
match stmt.to_declaration() {
|
match stmt.to_declaration() {
|
||||||
Declaration::VariableDeclaration(decl) => {
|
Declaration::VariableDeclaration(decl) => {
|
||||||
|
|
@ -147,7 +137,7 @@ impl<'a> IsolatedDeclarations<'a> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
new_stmts.push(self.ast.copy(stmt));
|
new_stmts.push(stmt);
|
||||||
}
|
}
|
||||||
match_module_declaration!(Statement) => {
|
match_module_declaration!(Statement) => {
|
||||||
transformed_indexes.push(new_stmts.len());
|
transformed_indexes.push(new_stmts.len());
|
||||||
|
|
@ -158,8 +148,9 @@ impl<'a> IsolatedDeclarations<'a> {
|
||||||
{
|
{
|
||||||
if let Some(var_decl) = var_decl {
|
if let Some(var_decl) = var_decl {
|
||||||
self.scope.visit_variable_declaration(&var_decl);
|
self.scope.visit_variable_declaration(&var_decl);
|
||||||
new_stmts
|
new_stmts.push(Statement::VariableDeclaration(
|
||||||
.push(Statement::VariableDeclaration(self.ast.alloc(var_decl)));
|
self.ast.alloc(var_decl),
|
||||||
|
));
|
||||||
transformed_indexes.push(new_stmts.len());
|
transformed_indexes.push(new_stmts.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,31 +158,36 @@ impl<'a> IsolatedDeclarations<'a> {
|
||||||
new_stmts.push(Statement::ExportDefaultDeclaration(
|
new_stmts.push(Statement::ExportDefaultDeclaration(
|
||||||
self.ast.alloc(new_decl),
|
self.ast.alloc(new_decl),
|
||||||
));
|
));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.scope.visit_export_default_declaration(decl);
|
self.scope.visit_export_default_declaration(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
||||||
if let Some(new_decl) = self.transform_export_named_declaration(decl) {
|
if let Some(new_decl) = self.transform_export_named_declaration(decl) {
|
||||||
self.scope.visit_declaration(
|
self.scope.visit_declaration(
|
||||||
new_decl.declaration.as_ref().unwrap_or_else(|| unreachable!()),
|
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);
|
self.scope.visit_export_named_declaration(decl);
|
||||||
}
|
}
|
||||||
module_declaration => self.scope.visit_module_declaration(module_declaration),
|
module_declaration => {
|
||||||
|
self.scope.visit_module_declaration(module_declaration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new_stmts.push(self.ast.copy(stmt));
|
new_stmts.push(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 }),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue