diff --git a/crates/oxc_semantic/src/binder.rs b/crates/oxc_semantic/src/binder.rs index 0fab93931..298e9e4d0 100644 --- a/crates/oxc_semantic/src/binder.rs +++ b/crates/oxc_semantic/src/binder.rs @@ -2,7 +2,7 @@ #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; -use oxc_ast::{syntax_directed_operations::BoundNames, AstKind}; +use oxc_ast::{syntax_directed_operations::BoundNames, AstKind, SourceType}; use crate::{ scope::{Scope, ScopeFlags, ScopeId}, @@ -80,9 +80,9 @@ impl<'a> Binder for Class<'a> { // and the duplicate entries are only bound by FunctionDeclarations. // https://tc39.es/ecma262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics #[must_use] -fn function_as_var(scope: &Scope, is_script: bool) -> bool { +fn function_as_var(scope: &Scope, source_type: SourceType) -> bool { scope.flags.intersects(ScopeFlags::Function) - || (is_script && scope.flags.intersects(ScopeFlags::Top)) + || (source_type.is_script() && scope.flags.intersects(ScopeFlags::Top)) } impl<'a> Binder for Function<'a> { @@ -93,35 +93,22 @@ impl<'a> Binder for Function<'a> { if !scope.strict_mode && matches!(builder.parent_kind(), AstKind::IfStatement(_)) { // Do not declare in if single statements, // if (false) function f() {} else function g() { } - } else if matches!(self.r#type, FunctionType::FunctionDeclaration) { - // the visitor is already inside the function scope, + } else if self.r#type == FunctionType::FunctionDeclaration { + // The visitor is already inside the function scope, // retrieve the parent scope for the function id to bind to. let parent_scope_id = builder.scope.scopes[*current_scope_id].parent().unwrap().into(); let parent_scope: &Scope = &builder.scope.scopes[parent_scope_id]; let (includes, excludes) = - if parent_scope.strict_mode || self.r#async || self.generator { - if function_as_var(parent_scope, builder.source_type.is_script()) { - ( - SymbolFlags::FunctionScopedVariable | SymbolFlags::Function, - SymbolFlags::FunctionScopedVariableExcludes, - ) - } else { - ( - SymbolFlags::BlockScopedVariable | SymbolFlags::Function, - SymbolFlags::BlockScopedVariableExcludes, - ) - } - } else if function_as_var(parent_scope, builder.source_type.is_script()) { - ( - SymbolFlags::Function, - SymbolFlags::FunctionScopedVariableExcludes - SymbolFlags::Function, - ) + if (parent_scope.strict_mode || self.r#async || self.generator) + && !function_as_var(parent_scope, builder.source_type) + { + (SymbolFlags::BlockScopedVariable, SymbolFlags::BlockScopedVariableExcludes) } else { ( - SymbolFlags::Function, - SymbolFlags::BlockScopedVariableExcludes - SymbolFlags::Function, + SymbolFlags::FunctionScopedVariable, + SymbolFlags::FunctionScopedVariableExcludes, ) }; diff --git a/crates/oxc_semantic/src/symbol/mod.rs b/crates/oxc_semantic/src/symbol/mod.rs index 32bcd80b3..f1b9b8cff 100644 --- a/crates/oxc_semantic/src/symbol/mod.rs +++ b/crates/oxc_semantic/src/symbol/mod.rs @@ -39,10 +39,9 @@ bitflags! { const BlockScopedVariable = 1 << 1; const Class = 1 << 5; const CatchVariable = 1 << 6; // try {} catch(catch_variable) {} - const Function = 1 << 7; const Variable = Self::FunctionScopedVariable.bits | Self::BlockScopedVariable.bits; - const Value = Self::Variable.bits | Self::Function.bits | Self::Class.bits; + const Value = Self::Variable.bits | Self::Class.bits; /// Variables can be redeclared, but can not redeclare a block-scoped declaration with the /// same name, or any other value that is not a variable, e.g. ValueModule or Class @@ -52,8 +51,7 @@ bitflags! { /// they can not merge with anything in the value space const BlockScopedVariableExcludes = Self::Value.bits; - const FunctionExcludes = Self::Value.bits - (Self::Function.bits | Self::Class.bits); - const ClassExcludes = Self::Value.bits - Self::Function.bits; + const ClassExcludes = Self::Value.bits; } } diff --git a/tasks/coverage/babel.snap b/tasks/coverage/babel.snap index 9f79a01eb..a2bd77156 100644 --- a/tasks/coverage/babel.snap +++ b/tasks/coverage/babel.snap @@ -1,7 +1,7 @@ Babel Summary: -AST Parsed : 2052/2071 (99.08%) -Positive Passed: 2052/2071 (99.08%) -Negative Passed: 1335/1502 (88.88%) +AST Parsed : 2054/2071 (99.18%) +Positive Passed: 2054/2071 (99.18%) +Negative Passed: 1333/1502 (88.75%) Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-multiple-labels/input.js" @@ -13,6 +13,8 @@ Expect Syntax Error: "annex-b/disabled/3.5-for-in-initializer/input.js" Expect Syntax Error: "annex-b/enabled/3.1-sloppy-labeled-functions-if-body/input.js" Expect Syntax Error: "core/categorized/invalid-fn-decl-labeled-inside-if/input.js" Expect Syntax Error: "core/categorized/invalid-fn-decl-labeled-inside-loop/input.js" +Expect Syntax Error: "core/scope/dupl-bind-catch-func/input.js" +Expect Syntax Error: "core/scope/dupl-bind-func-var-sloppy/input.js" Expect Syntax Error: "es2015/class-methods/direct-super-in-object-method/input.js" Expect Syntax Error: "es2015/destructuring/error-operator-for-default/input.js" Expect Syntax Error: "es2015/for-of/invalid-let-as-identifier/input.js" @@ -218,28 +220,6 @@ Expect to Parse: "core/opts/allowNewTargetOutsideFunction-true/input.js" · ────────── ╰──── help: new.target is only allowed in constructors and functions invoked using thew `new` operator -Expect to Parse: "core/scope/dupl-bind-func-var/input.js" - - × Identifier `foo` has already been declared - ╭─[core/scope/dupl-bind-func-var/input.js:1:1] - 1 │ function foo() {} - · ─┬─ - · ╰── `foo` has already been declared here - 2 │ var foo = 1; - · ─┬─ - · ╰── It can not be redeclared here - ╰──── -Expect to Parse: "core/scope/dupl-bind-gen-gen-script/input.js" - - × Identifier `foo` has already been declared - ╭─[core/scope/dupl-bind-gen-gen-script/input.js:1:1] - 1 │ function *foo() {}; - · ─┬─ - · ╰── `foo` has already been declared here - 2 │ function *foo() {}; - · ─┬─ - · ╰── It can not be redeclared here - ╰──── Expect to Parse: "core/uncategorised/327/input.js" × TS1108: A 'return' statement can only be used within a function body @@ -904,18 +884,6 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" · ╰── `foo` has already been declared here ╰──── - × Identifier `foo` has already been declared - ╭─[core/scope/dupl-bind-catch-func/input.js:1:1] - 1 │ try { - 2 │ } catch (foo) { - · ─┬─ - · ╰── `foo` has already been declared here - 3 │ function foo() {} - · ─┬─ - · ╰── It can not be redeclared here - 4 │ } - ╰──── - × Identifier `foo` has already been declared ╭─[core/scope/dupl-bind-catch-let/input.js:1:1] 1 │ try { @@ -1046,18 +1014,6 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" · ╰── It can not be redeclared here ╰──── - × Identifier `foo` has already been declared - ╭─[core/scope/dupl-bind-func-var-sloppy/input.js:1:1] - 1 │ { - 2 │ function foo() {} - · ─┬─ - · ╰── `foo` has already been declared here - 3 │ var foo = 1; - · ─┬─ - · ╰── It can not be redeclared here - 4 │ } - ╰──── - × Identifier `f` has already been declared ╭─[core/scope/dupl-bind-gen-func/input.js:1:1] 1 │ { function* f() {} function f() {} } diff --git a/tasks/coverage/test262.snap b/tasks/coverage/test262.snap index 0ead8ffb9..51f7bb324 100644 --- a/tasks/coverage/test262.snap +++ b/tasks/coverage/test262.snap @@ -1,31 +1,7 @@ Test262 Summary: -AST Parsed : 44015/44024 (99.98%) -Positive Passed: 44015/44024 (99.98%) +AST Parsed : 44022/44024 (100.00%) +Positive Passed: 44022/44024 (100.00%) Negative Passed: 3915/3915 (100.00%) -Expect to Parse: "language/block-scope/syntax/redeclaration-global/allowed-to-redeclare-function-declaration-with-var.js" - - × Identifier `f` has already been declared - ╭─[language/block-scope/syntax/redeclaration-global/allowed-to-redeclare-function-declaration-with-var.js:8:1] - 8 │ ---*/ - 9 │ function f() {} var f; - · ┬ ┬ - · │ ╰── It can not be redeclared here - · ╰── `f` has already been declared here - 10 │ - ╰──── -Expect to Parse: "language/destructuring/binding/syntax/recursive-array-and-object-patterns.js" - - × Identifier `fn4` has already been declared - ╭─[language/destructuring/binding/syntax/recursive-array-and-object-patterns.js:22:1] - 22 │ - 23 │ function fn4([], [[]], [[[[[[[[[x]]]]]]]]]) {} - · ─┬─ - · ╰── `fn4` has already been declared here - 24 │ - 25 │ function fn4([[x, y, ...z]]) {} - · ─┬─ - · ╰── It can not be redeclared here - ╰──── Expect to Parse: "language/expressions/class/decorator/syntax/class-valid/decorator-member-expr-private-identifier.js" × Unexpected token @@ -35,17 +11,6 @@ Expect to Parse: "language/expressions/class/decorator/syntax/class-valid/decora · ── 45 │ @#_ ╰──── -Expect to Parse: "language/global-code/decl-func-dup.js" - - × Identifier `f` has already been declared - ╭─[language/global-code/decl-func-dup.js:8:1] - 8 │ ---*/ - 9 │ function f() { return 1; } function f() { return 2; } - · ┬ ┬ - · │ ╰── It can not be redeclared here - · ╰── `f` has already been declared here - 10 │ - ╰──── Expect to Parse: "language/statements/class/decorator/syntax/class-valid/decorator-member-expr-private-identifier.js" × Unexpected token @@ -55,83 +20,6 @@ Expect to Parse: "language/statements/class/decorator/syntax/class-valid/decorat · ── 46 │ @#_ ╰──── -Expect to Parse: "language/statements/function/S13_A6_T1.js" - - × Identifier `__func` has already been declared - ╭─[language/statements/function/S13_A6_T1.js:11:1] - 11 │ - 12 │ function __func(){return 1}; - · ───┬── - · ╰── `__func` has already been declared here - 13 │ - 14 │ var __store__func = __func; - 15 │ - 16 │ var __1 = __func(); - 17 │ - 18 │ function __func(){return 'A'}; - · ───┬── - · ╰── It can not be redeclared here - 19 │ - ╰──── -Expect to Parse: "language/statements/function/S13_A6_T2.js" - - × Identifier `__func` has already been declared - ╭─[language/statements/function/S13_A6_T2.js:24:1] - 24 │ - 25 │ function __func(){return "FIRST";}; - · ───┬── - · ╰── `__func` has already been declared here - 26 │ - 27 │ ////////////////////////////////////////////////////////////////////////////// - 28 │ //CHECK#2 - 29 │ __result = __func(); - 30 │ if (__result !== "SECOND") { - 31 │ throw new Test262Error('#2: __result === "SECOND". Actual: __result ==='+__result); - 32 │ } - 33 │ // - 34 │ ////////////////////////////////////////////////////////////////////////////// - 35 │ - 36 │ function __func(){return "SECOND";}; - · ───┬── - · ╰── It can not be redeclared here - ╰──── -Expect to Parse: "language/statements/function/S14_A5_T1.js" - - × Identifier `__func` has already been declared - ╭─[language/statements/function/S14_A5_T1.js:21:1] - 21 │ - 22 │ function __func(){return "ascii"}; - · ───┬── - · ╰── `__func` has already been declared here - 23 │ function \u005f\u005f\u0066\u0075\u006e\u0063(){return "unicode"};//__func in unicode - · ──────────────────┬───────────────── - · ╰── It can not be redeclared here - 24 │ function __\u0066\u0075\u006e\u0063(){return "both"};//__func in unicode - ╰──── - - × Identifier `__func` has already been declared - ╭─[language/statements/function/S14_A5_T1.js:21:1] - 21 │ - 22 │ function __func(){return "ascii"}; - · ───┬── - · ╰── `__func` has already been declared here - 23 │ function \u005f\u005f\u0066\u0075\u006e\u0063(){return "unicode"};//__func in unicode - 24 │ function __\u0066\u0075\u006e\u0063(){return "both"};//__func in unicode - · ─────────────┬──────────── - · ╰── It can not be redeclared here - ╰──── -Expect to Parse: "language/statements/function/S14_A5_T2.js" - - × Identifier `__func` has already been declared - ╭─[language/statements/function/S14_A5_T2.js:21:1] - 21 │ - 22 │ function __func(){return "ascii"}; - · ───┬── - · ╰── `__func` has already been declared here - 23 │ function \u005f\u005f\u0066\u0075\u006e\u0063(){return "unicode"};//__func in unicode - · ──────────────────┬───────────────── - · ╰── It can not be redeclared here - ╰──── × '0'-prefixed octal literals and octal escape sequences are deprecated ╭─[annexB/language/expressions/template-literal/legacy-octal-escape-sequence-strict.js:17:1] diff --git a/tasks/coverage/typescript b/tasks/coverage/typescript index 7f292bf2a..b8c71685f 160000 --- a/tasks/coverage/typescript +++ b/tasks/coverage/typescript @@ -1 +1 @@ -Subproject commit 7f292bf2a19aa14ed69a55e646111af9533d8f1c +Subproject commit b8c71685f910230a9dca864d403e370a27ea1041 diff --git a/tasks/coverage/typescript.snap b/tasks/coverage/typescript.snap index 6af982e35..efb369854 100644 --- a/tasks/coverage/typescript.snap +++ b/tasks/coverage/typescript.snap @@ -1,7 +1,7 @@ TypeScript Summary: AST Parsed : 2323/2340 (99.27%) Positive Passed: 2323/2340 (99.27%) -Negative Passed: 681/2532 (26.90%) +Negative Passed: 680/2532 (26.86%) Expect Syntax Error: "Symbols/ES5SymbolProperty2.ts" Expect Syntax Error: "Symbols/ES5SymbolProperty6.ts" Expect Syntax Error: "additionalChecks/noPropertyAccessFromIndexSignature1.ts" @@ -829,6 +829,7 @@ Expect Syntax Error: "externalModules/verbatimModuleSyntaxInternalImportEquals.t Expect Syntax Error: "fixSignatureCaching.ts" Expect Syntax Error: "functions/functionImplementationErrors.ts" Expect Syntax Error: "functions/functionImplementations.ts" +Expect Syntax Error: "functions/functionNameConflicts.ts" Expect Syntax Error: "functions/functionOverloadCompatibilityWithVoid01.ts" Expect Syntax Error: "functions/functionOverloadErrors.ts" Expect Syntax Error: "functions/parameterInitializersForwardReferencing.2.ts" @@ -8267,54 +8268,6 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 15 │ } ╰──── - × Identifier `fn1` has already been declared - ╭─[functions/functionNameConflicts.ts:4:1] - 4 │ module M { - 5 │ function fn1() { } - · ─┬─ - · ╰── `fn1` has already been declared here - 6 │ var fn1; - · ─┬─ - · ╰── It can not be redeclared here - 7 │ - ╰──── - - × Identifier `fn2` has already been declared - ╭─[functions/functionNameConflicts.ts:7:1] - 7 │ - 8 │ var fn2; - · ─┬─ - · ╰── `fn2` has already been declared here - 9 │ function fn2() { } - · ─┬─ - · ╰── It can not be redeclared here - 10 │ } - ╰──── - - × Identifier `fn3` has already been declared - ╭─[functions/functionNameConflicts.ts:11:1] - 11 │ - 12 │ function fn3() { } - · ─┬─ - · ╰── `fn3` has already been declared here - 13 │ var fn3; - · ─┬─ - · ╰── It can not be redeclared here - 14 │ - ╰──── - - × Identifier `fn5` has already been declared - ╭─[functions/functionNameConflicts.ts:18:1] - 18 │ - 19 │ function fn5() { } - · ─┬─ - · ╰── `fn5` has already been declared here - 20 │ var fn5; - · ─┬─ - · ╰── It can not be redeclared here - 21 │ } - ╰──── - × Rest element must be last element ╭─[functions/functionOverloadErrorsSyntax.ts:8:1] 8 │ //Function overload signature with rest param followed by non-optional parameter