Skip to content

Commit 2191ae9

Browse files
committed
fix(semantic): allow reserved keywords in typescript ambient contexts (#15495)
Reserved keywords are allowed as an identifier in ambient contexts. ```ts declare const private: number ``` This is allowed.
1 parent b0be342 commit 2191ae9

File tree

10 files changed

+51
-40
lines changed

10 files changed

+51
-40
lines changed

crates/oxc_semantic/src/checker/javascript.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use oxc_syntax::{
1313
number::NumberBase,
1414
operator::{AssignmentOperator, UnaryOperator},
1515
scope::{ScopeFlags, ScopeId},
16-
symbol::SymbolFlags,
16+
symbol::{SymbolFlags, SymbolId},
1717
};
1818

1919
use crate::{IsGlobalReference, builder::SemanticBuilder, diagnostics::redeclaration};
@@ -98,9 +98,15 @@ pub const STRICT_MODE_NAMES: Set<&'static str> = phf_set! {
9898
"yield",
9999
};
100100

101-
pub fn check_identifier(name: &str, span: Span, ctx: &SemanticBuilder<'_>) {
102-
// ts module block allows revered keywords
103-
if ctx.current_scope_flags().is_ts_module_block() {
101+
pub fn check_identifier(
102+
name: &str,
103+
span: Span,
104+
symbol_id: Option<SymbolId>,
105+
ctx: &SemanticBuilder<'_>,
106+
) {
107+
// reserved keywords are allowed in ambient contexts
108+
if ctx.source_type.is_typescript_definition() || is_current_node_ambient_binding(symbol_id, ctx)
109+
{
104110
return;
105111
}
106112
if name == "await" {
@@ -120,6 +126,24 @@ pub fn check_identifier(name: &str, span: Span, ctx: &SemanticBuilder<'_>) {
120126
}
121127
}
122128

129+
fn is_current_node_ambient_binding(symbol_id: Option<SymbolId>, ctx: &SemanticBuilder<'_>) -> bool {
130+
if ctx.current_scope_flags().is_ts_module_block() {
131+
return true;
132+
}
133+
134+
if let Some(symbol_id) = symbol_id
135+
&& ctx.scoping.symbol_flags(symbol_id).contains(SymbolFlags::Ambient)
136+
{
137+
true
138+
} else if let AstKind::BindingIdentifier(id) = ctx.nodes.kind(ctx.current_node_id)
139+
&& let Some(symbol_id) = id.symbol_id.get()
140+
{
141+
ctx.scoping.symbol_flags(symbol_id).contains(SymbolFlags::Ambient)
142+
} else {
143+
false
144+
}
145+
}
146+
123147
fn unexpected_identifier_assign(x0: &str, span1: Span) -> OxcDiagnostic {
124148
OxcDiagnostic::error(format!("Cannot assign to '{x0}' in strict mode")).with_label(span1)
125149
}

crates/oxc_semantic/src/checker/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ pub fn check<'a>(kind: AstKind<'a>, ctx: &SemanticBuilder<'a>) {
1616
js::check_unresolved_exports(program, ctx);
1717
}
1818
AstKind::BindingIdentifier(ident) => {
19-
js::check_identifier(&ident.name, ident.span, ctx);
19+
js::check_identifier(&ident.name, ident.span, ident.symbol_id.get(), ctx);
2020
js::check_binding_identifier(ident, ctx);
2121
}
2222
AstKind::IdentifierReference(ident) => {
23-
js::check_identifier(&ident.name, ident.span, ctx);
23+
js::check_identifier(&ident.name, ident.span, None, ctx);
2424
js::check_identifier_reference(ident, ctx);
2525
}
26-
AstKind::LabelIdentifier(ident) => js::check_identifier(&ident.name, ident.span, ctx),
26+
AstKind::LabelIdentifier(ident) => js::check_identifier(&ident.name, ident.span, None, ctx),
2727
AstKind::PrivateIdentifier(ident) => js::check_private_identifier_outside_class(ident, ctx),
2828
AstKind::NumericLiteral(lit) => js::check_number_literal(lit, ctx),
2929
AstKind::StringLiteral(lit) => js::check_string_literal(lit, ctx),
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare let private: number;
2+
3+
export {};
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
codegen_misc Summary:
2-
AST Parsed : 50/50 (100.00%)
3-
Positive Passed: 50/50 (100.00%)
2+
AST Parsed : 51/51 (100.00%)
3+
Positive Passed: 51/51 (100.00%)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
formatter_misc Summary:
2-
AST Parsed : 50/50 (100.00%)
3-
Positive Passed: 50/50 (100.00%)
2+
AST Parsed : 51/51 (100.00%)
3+
Positive Passed: 51/51 (100.00%)

tasks/coverage/snapshots/parser_misc.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
parser_misc Summary:
2-
AST Parsed : 50/50 (100.00%)
3-
Positive Passed: 50/50 (100.00%)
2+
AST Parsed : 51/51 (100.00%)
3+
Positive Passed: 51/51 (100.00%)
44
Negative Passed: 118/118 (100.00%)
55

66
× Cannot assign to 'arguments' in strict mode

tasks/coverage/snapshots/parser_typescript.snap

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ commit: cc2610fd
22

33
parser_typescript Summary:
44
AST Parsed : 9821/9822 (99.99%)
5-
Positive Passed: 9809/9822 (99.87%)
5+
Positive Passed: 9810/9822 (99.88%)
66
Negative Passed: 1455/2545 (57.17%)
77
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment7.ts
88

@@ -2365,23 +2365,6 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/es6/moduleExp
23652365
65 │ var y = _;
23662366
╰────
23672367

2368-
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/externalModules/topLevelAwait.3.ts
2369-
2370-
× The keyword 'await' is reserved
2371-
╭─[typescript/tests/cases/conformance/externalModules/topLevelAwait.3.ts:3:15]
2372-
2 │ export {};
2373-
3 │ declare const await: any;
2374-
· ──────────
2375-
4 │ declare class C extends await {}
2376-
╰────
2377-
2378-
× The keyword 'await' is reserved
2379-
╭─[typescript/tests/cases/conformance/externalModules/topLevelAwait.3.ts:4:25]
2380-
3 │ declare const await: any;
2381-
4 │ declare class C extends await {}
2382-
· ─────
2383-
╰────
2384-
23852368
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName11.ts
23862369

23872370
× Function implementation is missing or not immediately following the declaration.

tasks/coverage/snapshots/semantic_misc.snap

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
semantic_misc Summary:
2-
AST Parsed : 50/50 (100.00%)
3-
Positive Passed: 32/50 (64.00%)
2+
AST Parsed : 51/51 (100.00%)
3+
Positive Passed: 32/51 (62.75%)
4+
semantic Error: tasks/coverage/misc/pass/declare-let-private.ts
5+
Bindings mismatch:
6+
after transform: ScopeId(0): ["private"]
7+
rebuilt : ScopeId(0): []
8+
49
semantic Error: tasks/coverage/misc/pass/oxc-11593.ts
510
Scope children mismatch:
611
after transform: ScopeId(0): [ScopeId(1)]

tasks/coverage/snapshots/semantic_typescript.snap

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ commit: cc2610fd
22

33
semantic_typescript Summary:
44
AST Parsed : 6148/6148 (100.00%)
5-
Positive Passed: 2661/6148 (43.28%)
5+
Positive Passed: 2662/6148 (43.30%)
66
semantic Error: tasks/coverage/typescript/tests/cases/compiler/2dArrays.ts
77
Symbol reference IDs mismatch for "Cell":
88
after transform: SymbolId(0): [ReferenceId(1)]
@@ -42824,10 +42824,6 @@ Scope children mismatch:
4282442824
after transform: ScopeId(0): [ScopeId(1)]
4282542825
rebuilt : ScopeId(0): []
4282642826

42827-
semantic Error: tasks/coverage/typescript/tests/cases/conformance/externalModules/topLevelAwait.3.ts
42828-
The keyword 'await' is reserved
42829-
The keyword 'await' is reserved
42830-
4283142827
semantic Error: tasks/coverage/typescript/tests/cases/conformance/externalModules/typeAndNamespaceExportMerge.ts
4283242828
Scope children mismatch:
4283342829
after transform: ScopeId(0): [ScopeId(1)]
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
transformer_misc Summary:
2-
AST Parsed : 50/50 (100.00%)
3-
Positive Passed: 50/50 (100.00%)
2+
AST Parsed : 51/51 (100.00%)
3+
Positive Passed: 51/51 (100.00%)

0 commit comments

Comments
 (0)