Skip to content

Commit f1b793f

Browse files
committed
fix(isolated-declarations): function overloads reaching unreachable (#3739)
1 parent 256acc9 commit f1b793f

File tree

2 files changed

+139
-88
lines changed

2 files changed

+139
-88
lines changed

crates/oxc_isolated_declarations/src/inferrer.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,10 @@ impl<'a> IsolatedDeclarations<'a> {
105105
return None;
106106
}
107107

108-
FunctionReturnType::infer(
109-
self,
110-
function
111-
.body
112-
.as_ref()
113-
.unwrap_or_else(|| unreachable!("Only declare function can have no body")),
114-
)
115-
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
108+
function.body.as_ref().and_then(|body| {
109+
FunctionReturnType::infer(self, body)
110+
.map(|type_annotation| self.ast.ts_type_annotation(SPAN, type_annotation))
111+
})
116112
}
117113

118114
pub fn infer_arrow_function_return_type(

crates/oxc_isolated_declarations/src/lib.rs

+135-80
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use oxc_allocator::Allocator;
2222
#[allow(clippy::wildcard_imports)]
2323
use oxc_ast::{ast::*, AstBuilder, Visit};
2424
use oxc_diagnostics::OxcDiagnostic;
25-
use oxc_span::{SourceType, SPAN};
25+
use oxc_span::{Atom, SourceType, SPAN};
2626

2727
use crate::scope::ScopeTree;
2828

@@ -86,27 +86,16 @@ impl<'a> IsolatedDeclarations<'a> {
8686
if has_import_or_export {
8787
self.transform_statements_on_demand(&program.body)
8888
} else {
89-
self.transform_program_without_module_declaration(program)
90-
}
91-
}
92-
93-
pub fn modifiers_declare(&self) -> Modifiers<'a> {
94-
if self.scope.is_ts_module_block_flag() {
95-
// If we are in a module block, we don't need to add declare
96-
Modifiers::empty()
97-
} else {
98-
Modifiers::new(
99-
self.ast.new_vec_single(Modifier { span: SPAN, kind: ModifierKind::Declare }),
100-
)
89+
self.transform_program_without_module_declaration(&program.body)
10190
}
10291
}
10392

10493
pub fn transform_program_without_module_declaration(
10594
&mut self,
106-
program: &Program<'a>,
95+
stmts: &oxc_allocator::Vec<'a, Statement<'a>>,
10796
) -> oxc_allocator::Vec<'a, Statement<'a>> {
10897
let mut new_ast_stmts = self.ast.new_vec::<Statement<'a>>();
109-
for stmt in &program.body {
98+
for stmt in Self::remove_function_overloads_implementation(self.ast.copy(stmts)) {
11099
if let Some(decl) = stmt.as_declaration() {
111100
if let Some(decl) = self.transform_declaration(decl, false) {
112101
new_ast_stmts.push(Statement::from(decl));
@@ -130,68 +119,75 @@ impl<'a> IsolatedDeclarations<'a> {
130119
// 2. Transform export declarations
131120
// 3. Collect all bindings / reference from module declarations
132121
// 4. Collect transformed indexes
133-
stmts.iter().for_each(|stmt| match stmt {
134-
match_declaration!(Statement) => {
135-
match stmt.to_declaration() {
136-
Declaration::VariableDeclaration(decl) => {
137-
variables_declarations.push_back(
138-
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
139-
);
140-
variable_transformed_indexes.push_back(Vec::default());
141-
}
142-
Declaration::UsingDeclaration(decl) => {
143-
variables_declarations.push_back(
144-
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
145-
);
146-
variable_transformed_indexes.push_back(Vec::default());
122+
for stmt in Self::remove_function_overloads_implementation(self.ast.copy(stmts)) {
123+
match stmt {
124+
match_declaration!(Statement) => {
125+
match stmt.to_declaration() {
126+
Declaration::VariableDeclaration(decl) => {
127+
variables_declarations.push_back(
128+
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
129+
);
130+
variable_transformed_indexes.push_back(Vec::default());
131+
}
132+
Declaration::UsingDeclaration(decl) => {
133+
variables_declarations.push_back(
134+
self.ast.copy(&decl.declarations).into_iter().collect::<Vec<_>>(),
135+
);
136+
variable_transformed_indexes.push_back(Vec::default());
137+
}
138+
_ => {}
147139
}
148-
_ => {}
140+
new_stmts.push(stmt);
149141
}
150-
new_stmts.push(self.ast.copy(stmt));
151-
}
152-
match_module_declaration!(Statement) => {
153-
transformed_indexes.push(new_stmts.len());
154-
match stmt.to_module_declaration() {
155-
ModuleDeclaration::ExportDefaultDeclaration(decl) => {
156-
if let Some((var_decl, new_decl)) =
157-
self.transform_export_default_declaration(decl)
158-
{
159-
if let Some(var_decl) = var_decl {
160-
self.scope.visit_variable_declaration(&var_decl);
161-
new_stmts
162-
.push(Statement::VariableDeclaration(self.ast.alloc(var_decl)));
163-
transformed_indexes.push(new_stmts.len());
142+
match_module_declaration!(Statement) => {
143+
transformed_indexes.push(new_stmts.len());
144+
match stmt.to_module_declaration() {
145+
ModuleDeclaration::ExportDefaultDeclaration(decl) => {
146+
if let Some((var_decl, new_decl)) =
147+
self.transform_export_default_declaration(decl)
148+
{
149+
if let Some(var_decl) = var_decl {
150+
self.scope.visit_variable_declaration(&var_decl);
151+
new_stmts.push(Statement::VariableDeclaration(
152+
self.ast.alloc(var_decl),
153+
));
154+
transformed_indexes.push(new_stmts.len());
155+
}
156+
157+
self.scope.visit_export_default_declaration(&new_decl);
158+
new_stmts.push(Statement::ExportDefaultDeclaration(
159+
self.ast.alloc(new_decl),
160+
));
161+
continue;
164162
}
165163

166-
self.scope.visit_export_default_declaration(&new_decl);
167-
new_stmts.push(Statement::ExportDefaultDeclaration(
168-
self.ast.alloc(new_decl),
169-
));
170-
return;
164+
self.scope.visit_export_default_declaration(decl);
171165
}
172166

173-
self.scope.visit_export_default_declaration(decl);
174-
}
175-
ModuleDeclaration::ExportNamedDeclaration(decl) => {
176-
if let Some(new_decl) = self.transform_export_named_declaration(decl) {
177-
self.scope.visit_declaration(
178-
new_decl.declaration.as_ref().unwrap_or_else(|| unreachable!()),
179-
);
167+
ModuleDeclaration::ExportNamedDeclaration(decl) => {
168+
if let Some(new_decl) = self.transform_export_named_declaration(decl) {
169+
self.scope.visit_declaration(
170+
new_decl.declaration.as_ref().unwrap_or_else(|| unreachable!()),
171+
);
180172

181-
new_stmts
182-
.push(Statement::ExportNamedDeclaration(self.ast.alloc(new_decl)));
183-
return;
184-
}
173+
new_stmts.push(Statement::ExportNamedDeclaration(
174+
self.ast.alloc(new_decl),
175+
));
176+
continue;
177+
}
185178

186-
self.scope.visit_export_named_declaration(decl);
179+
self.scope.visit_export_named_declaration(decl);
180+
}
181+
module_declaration => {
182+
self.scope.visit_module_declaration(module_declaration);
183+
}
187184
}
188-
module_declaration => self.scope.visit_module_declaration(module_declaration),
189-
}
190185

191-
new_stmts.push(self.ast.copy(stmt));
186+
new_stmts.push(stmt);
187+
}
188+
_ => {}
192189
}
193-
_ => {}
194-
});
190+
}
195191

196192
// 5. Transform statements until no more transformation can be done
197193
let mut last_reference_len = 0;
@@ -201,13 +197,11 @@ impl<'a> IsolatedDeclarations<'a> {
201197
let mut variables_declarations_iter = variables_declarations.iter_mut();
202198
let mut variable_transformed_indexes_iter = variable_transformed_indexes.iter_mut();
203199

204-
(0..new_stmts.len()).for_each(|i| {
200+
for (i, stmt) in new_stmts.iter_mut().enumerate() {
205201
if transformed_indexes.contains(&i) {
206-
return;
202+
continue;
207203
}
208-
let Some(decl) = new_stmts[i].as_declaration() else {
209-
return;
210-
};
204+
let Some(decl) = stmt.as_declaration() else { continue };
211205

212206
if let Declaration::VariableDeclaration(_) | Declaration::UsingDeclaration(_) = decl
213207
{
@@ -219,25 +213,23 @@ impl<'a> IsolatedDeclarations<'a> {
219213
unreachable!()
220214
};
221215

222-
(0..cur_variable_declarations.len()).for_each(|ii| {
216+
for (ii, declarator) in cur_variable_declarations.iter_mut().enumerate() {
223217
if cur_transformed_indexes.contains(&ii) {
224-
return;
218+
continue;
225219
}
226220

227-
if let Some(decl) =
228-
self.transform_variable_declarator(&cur_variable_declarations[ii], true)
229-
{
221+
if let Some(decl) = self.transform_variable_declarator(declarator, true) {
230222
self.scope.visit_variable_declarator(&decl);
231223
cur_transformed_indexes.push(ii);
232-
cur_variable_declarations[ii] = decl;
224+
*declarator = decl;
233225
}
234-
});
226+
}
235227
} else if let Some(decl) = self.transform_declaration(decl, true) {
236228
self.scope.visit_declaration(&decl);
237229
transformed_indexes.push(i);
238-
new_stmts[i] = Statement::from(decl);
230+
*stmt = Statement::from(decl);
239231
}
240-
});
232+
}
241233
}
242234

243235
// 6. Transform variable/using declarations, import statements, remove unused imports
@@ -304,4 +296,67 @@ impl<'a> IsolatedDeclarations<'a> {
304296

305297
new_ast_stmts
306298
}
299+
300+
pub fn remove_function_overloads_implementation(
301+
stmts: oxc_allocator::Vec<'a, Statement<'a>>,
302+
) -> impl Iterator<Item = Statement<'a>> + '_ {
303+
let mut last_function_name: Option<Atom<'a>> = None;
304+
305+
stmts.into_iter().filter_map(move |stmt| match stmt {
306+
Statement::FunctionDeclaration(ref func) => {
307+
let name = &func
308+
.id
309+
.as_ref()
310+
.unwrap_or_else(|| {
311+
unreachable!(
312+
"Only export default function declaration is allowed to have no name"
313+
)
314+
})
315+
.name;
316+
if last_function_name.as_ref().is_some_and(|last_name| last_name == name)
317+
&& func.body.is_some()
318+
{
319+
None
320+
} else {
321+
last_function_name = Some(name.clone());
322+
Some(stmt)
323+
}
324+
}
325+
Statement::ExportNamedDeclaration(ref decl) => {
326+
if let Some(Declaration::FunctionDeclaration(ref func)) = decl.declaration {
327+
let name = &func
328+
.id
329+
.as_ref()
330+
.unwrap_or_else(|| {
331+
unreachable!(
332+
"Only export default function declaration is allowed to have no name"
333+
)
334+
})
335+
.name;
336+
if last_function_name.as_ref().is_some_and(|last_name| last_name == name)
337+
&& func.body.is_some()
338+
{
339+
None
340+
} else {
341+
last_function_name = Some(name.clone());
342+
Some(stmt)
343+
}
344+
} else {
345+
Some(stmt)
346+
}
347+
}
348+
_ => Some(stmt),
349+
})
350+
}
351+
352+
pub fn modifiers_declare(&self) -> Modifiers<'a> {
353+
if self.scope.is_ts_module_block_flag() {
354+
// If we are in a module block, we don't need to add declare
355+
Modifiers::empty()
356+
} else {
357+
Modifiers::new(
358+
self.ast.new_vec_single(Modifier { span: SPAN, kind: ModifierKind::Declare }),
359+
)
360+
}
361+
}
307362
}

0 commit comments

Comments
 (0)