mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(semantic): report redeclaration error for function a() {} var a in module mode (#19041)
## Summary Fixes #18719. - In module mode, function declarations are lexically scoped (part of `LexicallyDeclaredNames`), so `function a() {} var a = ''` is a redeclaration error per the ECMAScript spec - The checker was only reporting the error when the `var` appeared **before** the function (`var a = ''; function a() {}`) but not the other way around, due to AST visit ordering - `check_variable_declarator_redeclaration` unconditionally skipped the check at `Top | Function` scopes — now it falls through to the redeclaration check when in module mode at the top scope 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
2 files changed
+20
-4
No files matched your search
@@ -614,10 +614,17 @@ pub fn check_variable_declarator_redeclaration(
|
||||
decl: &VariableDeclarator,
|
||||
ctx: &SemanticBuilder<'_>,
|
||||
) {
|
||||
if decl.kind != VariableDeclarationKind::Var
|
||||
|| ctx.current_scope_flags().intersects(ScopeFlags::Top | ScopeFlags::Function)
|
||||
if decl.kind != VariableDeclarationKind::Var {
|
||||
return;
|
||||
}
|
||||
|
||||
let scope_flags = ctx.current_scope_flags();
|
||||
// `function a() {}; var a;` and `function b() { function a() {}; var a; }` are valid
|
||||
// in script mode, but in module mode at the top level, function declarations are
|
||||
// lexically scoped, so `function a() {}; var a;` is a redeclaration error.
|
||||
if scope_flags.intersects(ScopeFlags::Top | ScopeFlags::Function)
|
||||
&& !(ctx.source_type.is_module() && scope_flags.is_top())
|
||||
{
|
||||
// `function a() {}; var a;` and `function b() { function a() {}; var a; }` are valid
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -625,7 +632,8 @@ pub fn check_variable_declarator_redeclaration(
|
||||
let redeclarations = ctx.scoping.symbol_redeclarations(ident.symbol_id());
|
||||
let Some(rd) = redeclarations.iter().nth_back(1) else { return };
|
||||
|
||||
// `{ function f() {}; var f; }` is invalid in both strict and non-strict mode
|
||||
// `{ function f() {}; var f; }` is invalid in both strict and non-strict mode.
|
||||
// In module mode at the top level, `function f() {}; var f;` is also invalid.
|
||||
if rd.flags.is_function() {
|
||||
ctx.error(diagnostics::redeclaration(&ident.name, rd.span, decl.span));
|
||||
}
|
||||
|
||||
@@ -444,3 +444,11 @@ fn test_redeclaration() {
|
||||
.has_number_of_references(0) // no references to the function
|
||||
.test();
|
||||
}
|
||||
|
||||
// https://github.com/oxc-project/oxc/issues/18719
|
||||
#[test]
|
||||
fn test_function_var_redeclaration_in_module() {
|
||||
// Both orderings should produce a redeclaration error in module mode
|
||||
SemanticTester::js("function a() {} var a = ''").has_error("already been declared");
|
||||
SemanticTester::js("var a = ''; function a() {}").has_error("already been declared");
|
||||
}
|
||||
Reference in new issue
Block a user