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:
Boshen committed 2026-02-06 09:12:12 +00:00
1 parent 1fb3bc3627
commit 3aeba7a7e6
2 files changed
+20 -4

No files matched your search

+12 -4
View File
@@ -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");
}