mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
fix(parser): reject declare in an already-ambient context (TS1038) (#22850)
A `declare` modifier is redundant and not allowed when its declaration is nested
directly inside an ambient `declare namespace` / `declare module` body (TS1038).
A top-level `declare` in a `.d.ts` file stays valid:
declare namespace N { declare function f(): void; } // now TS1038
declare module "m" { declare function f(): void; } // now TS1038
// foo.d.ts
declare function f(): void; // valid (top level)
namespace N { declare function f(): void; } // valid (non-ambient namespace)
Checked in `parse_ts_declaration_statement` against the enclosing context captured
before the declaration unions in its own ambient flag: `declare` modifier present,
`reserved_ctx.has_ambient()`, and `!reserved_ctx.has_top_level()`. The
`has_top_level()` guard is what exempts a `.d.ts` source file (whose parent is the
SourceFile, not a module block) while still covering internal namespaces and
external `declare module "x"` bodies. No valid construct has
`declare + ambient + !top_level`, so there is no positive regression.
Two linter fixtures used a redundant nested `declare` and are updated to valid TS
(`no_namespace`, `prefer_namespace_keyword`).
parser_typescript +9 negative-pass; positive/AST stay 100%.
This commit is contained in:
6 files changed
+175
-29
No files matched your search
@@ -348,7 +348,7 @@ fn test() {
|
||||
(
|
||||
"namespace A {
|
||||
export declare namespace B {
|
||||
declare namespace C {}
|
||||
namespace C {}
|
||||
}
|
||||
}",
|
||||
Some(serde_json::json!([{ "allowDeclarations": true }])),
|
||||
@@ -358,7 +358,7 @@ fn test() {
|
||||
(
|
||||
"namespace A {
|
||||
export declare namespace B {
|
||||
export declare namespace C {}
|
||||
export namespace C {}
|
||||
}
|
||||
}",
|
||||
Some(serde_json::json!([{ "allowDeclarations": true }])),
|
||||
@@ -428,7 +428,7 @@ fn test() {
|
||||
(
|
||||
"export namespace A {
|
||||
export declare namespace B {
|
||||
declare namespace C {}
|
||||
namespace C {}
|
||||
}
|
||||
}",
|
||||
Some(serde_json::json!([{ "allowDeclarations": true }])),
|
||||
@@ -438,7 +438,7 @@ fn test() {
|
||||
(
|
||||
"export namespace A {
|
||||
export declare namespace B {
|
||||
export declare namespace C {}
|
||||
export namespace C {}
|
||||
}
|
||||
}",
|
||||
Some(serde_json::json!([{ "allowDeclarations": true }])),
|
||||
|
||||
@@ -114,7 +114,7 @@ fn test() {
|
||||
"declare module foo {}",
|
||||
"
|
||||
declare module foo {
|
||||
declare module bar {}
|
||||
module bar {}
|
||||
}
|
||||
",
|
||||
"
|
||||
@@ -144,12 +144,12 @@ fn test() {
|
||||
(
|
||||
"
|
||||
declare module foo {
|
||||
declare module bar {}
|
||||
module bar {}
|
||||
}
|
||||
",
|
||||
"
|
||||
declare namespace foo {
|
||||
declare namespace bar {}
|
||||
namespace bar {}
|
||||
}
|
||||
",
|
||||
None,
|
||||
|
||||
@@ -30,7 +30,7 @@ source: crates/oxc_linter/src/tester.rs
|
||||
╭─[prefer_namespace_keyword.tsx:2:9]
|
||||
1 │
|
||||
2 │ ╭─▶ declare module foo {
|
||||
3 │ │ declare module bar {}
|
||||
3 │ │ module bar {}
|
||||
4 │ ╰─▶ }
|
||||
5 │
|
||||
╰────
|
||||
@@ -40,8 +40,8 @@ source: crates/oxc_linter/src/tester.rs
|
||||
⚠ typescript(prefer-namespace-keyword): Use `namespace` instead of `module` to declare custom TypeScript modules.
|
||||
╭─[prefer_namespace_keyword.tsx:3:11]
|
||||
2 │ declare module foo {
|
||||
3 │ declare module bar {}
|
||||
· ─────────────────────
|
||||
3 │ module bar {}
|
||||
· ─────────────
|
||||
4 │ }
|
||||
╰────
|
||||
help: Replace `module` with `namespace` for internal declarations.
|
||||
|
||||
@@ -313,6 +313,12 @@ pub fn statement_in_ambient_context(span: Span) -> OxcDiagnostic {
|
||||
ts_error("1036", "Statements are not allowed in ambient contexts.").with_label(span)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
pub fn declare_in_ambient_context(span: Span) -> OxcDiagnostic {
|
||||
ts_error("1038", "A 'declare' modifier cannot be used in an already ambient context.")
|
||||
.with_label(span)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
pub fn async_function_declaration(span: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error("Async functions can only be declared at the top level or inside a block")
|
||||
|
||||
@@ -458,6 +458,12 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
pub(crate) fn parse_ts_declaration_statement(&mut self, start_span: u32) -> Statement<'a> {
|
||||
let reserved_ctx = self.ctx;
|
||||
let modifiers = self.eat_modifiers_before_declaration();
|
||||
if let Some(modifier) = modifiers.get(ModifierKind::Declare)
|
||||
&& reserved_ctx.has_ambient()
|
||||
&& !reserved_ctx.has_top_level()
|
||||
{
|
||||
self.error(diagnostics::declare_in_ambient_context(modifier.span()));
|
||||
}
|
||||
self.ctx = self
|
||||
.ctx
|
||||
.union_ambient_if(modifiers.contains_declare())
|
||||
|
||||
@@ -3,7 +3,7 @@ commit: e5509e21
|
||||
parser_typescript Summary:
|
||||
AST Parsed : 9779/9779 (100.00%)
|
||||
Positive Passed: 9779/9779 (100.00%)
|
||||
Negative Passed: 1611/2640 (61.02%)
|
||||
Negative Passed: 1620/2640 (61.36%)
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration3.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration4.ts
|
||||
@@ -182,10 +182,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/crashDeclare
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/crashRegressionTest.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFile.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFileWithOut.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/declarationEmitCommonJsModuleReferencedType.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/declarationEmitComputedPropertyNameEnum3.ts
|
||||
@@ -1758,14 +1754,10 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration12.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration7.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName4.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ConstructorDeclarations/parserConstructorDeclaration2.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/EnumDeclarations/parserEnumDeclaration2.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/EnumDeclarations/parserEnumDeclaration3.d.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserCommaInTypeMemberList2.ts
|
||||
@@ -1776,8 +1768,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/FunctionDeclarations/parserFunctionDeclaration1.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/FunctionDeclarations/parserFunctionDeclaration3.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/FunctionDeclarations/parserFunctionDeclaration4.ts
|
||||
@@ -1806,12 +1796,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration2.d.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration3.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration4.d.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration5.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ParameterLists/parserParameterList14.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/ParameterLists/parserParameterList15.ts
|
||||
@@ -1850,8 +1834,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ec
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/Symbols/parserES5SymbolProperty5.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/VariableDeclarations/parserVariableDeclaration4.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/parserNoASIOnCallAfterFunctionExpression1.ts
|
||||
|
||||
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/parserRealSource13.ts
|
||||
@@ -5633,6 +5615,70 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
2 │
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFile.ts:2:5]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare var x;
|
||||
· ───────
|
||||
3 │ declare function f();
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFile.ts:3:5]
|
||||
2 │ declare var x;
|
||||
3 │ declare function f();
|
||||
· ───────
|
||||
4 │
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFile.ts:5:5]
|
||||
4 │
|
||||
5 │ declare namespace N { }
|
||||
· ───────
|
||||
6 │
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFile.ts:7:5]
|
||||
6 │
|
||||
7 │ declare class C { }
|
||||
· ───────
|
||||
8 │ }
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFileWithOut.ts:2:5]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare var x;
|
||||
· ───────
|
||||
3 │ declare function f();
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFileWithOut.ts:3:5]
|
||||
2 │ declare var x;
|
||||
3 │ declare function f();
|
||||
· ───────
|
||||
4 │
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFileWithOut.ts:5:5]
|
||||
4 │
|
||||
5 │ declare namespace N { }
|
||||
· ───────
|
||||
6 │
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/declFileWithErrorsInInputDeclarationFileWithOut.ts:7:5]
|
||||
6 │
|
||||
7 │ declare class C { }
|
||||
· ───────
|
||||
8 │ }
|
||||
╰────
|
||||
|
||||
× Identifier `a` has already been declared
|
||||
╭─[typescript/tests/cases/compiler/declarationEmitDestructuring2.ts:3:13]
|
||||
2 │ function g([a, b, c, d] = [1, 2, 3, 4]) { }
|
||||
@@ -7757,6 +7803,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
7 │ var b: a;
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/importDeclWithDeclareModifierInAmbientContext.ts:6:5]
|
||||
5 │ }
|
||||
6 │ declare export import a = x.c;
|
||||
· ───────
|
||||
7 │ var b: a;
|
||||
╰────
|
||||
|
||||
× TS(2309): An export assignment cannot be used in a module with other exported elements
|
||||
╭─[typescript/tests/cases/compiler/importDeclWithExportModifierAndExportAssignment.ts:6:1]
|
||||
5 │ export import a = x.c;
|
||||
@@ -10869,6 +10923,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
126 │ import m5_nonerrorImport = glo_M1_public;
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/privacyGloImportParseErrors.ts:133:9]
|
||||
132 │ namespace m2 {
|
||||
133 │ declare module "abc" {
|
||||
· ───────
|
||||
134 │ }
|
||||
╰────
|
||||
|
||||
× TS(1147): Import declarations in a namespace cannot reference a module.
|
||||
╭─[typescript/tests/cases/compiler/privacyGloImportParseErrors.ts:146:5]
|
||||
145 │ namespace m2 {
|
||||
@@ -10949,6 +11011,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
307 │ import m5_nonerrorImport = glo_M3_private;
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/privacyImportParseErrors.ts:314:9]
|
||||
313 │ namespace m2 {
|
||||
314 │ declare module "abc" {
|
||||
· ───────
|
||||
315 │ }
|
||||
╰────
|
||||
|
||||
× TS(1029): 'export' modifier must precede 'declare' modifier.
|
||||
╭─[typescript/tests/cases/compiler/privacyImportParseErrors.ts:326:9]
|
||||
325 │
|
||||
@@ -10957,6 +11027,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
327 │ namespace m2 {
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/compiler/privacyImportParseErrors.ts:328:9]
|
||||
327 │ namespace m2 {
|
||||
328 │ declare module "abc" {
|
||||
· ───────
|
||||
329 │ }
|
||||
╰────
|
||||
|
||||
× 'export' modifier cannot be used here.
|
||||
╭─[typescript/tests/cases/compiler/privacyImportParseErrors.ts:326:9]
|
||||
325 │
|
||||
@@ -24395,6 +24473,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
╰────
|
||||
help: Remove the extra base class or use interfaces for multiple inheritance
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration7.ts:2:3]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare class C {
|
||||
· ───────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(2390): Constructor implementation is missing.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ClassDeclarations/parserClassDeclaration8.ts:2:3]
|
||||
1 │ class C {
|
||||
@@ -24522,6 +24608,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/EnumDeclarations/parserEnumDeclaration2.ts:2:3]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare enum E {
|
||||
· ───────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× Identifier expected. 'void' is a reserved word that cannot be used here.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/EnumDeclarations/parserEnumDeclaration4.ts:1:6]
|
||||
1 │ enum void {
|
||||
@@ -25270,6 +25364,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/FunctionDeclarations/parserFunctionDeclaration1.ts:2:3]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare function F();
|
||||
· ───────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1183): An implementation cannot be declared in ambient contexts.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/FunctionDeclarations/parserFunctionDeclaration2.d.ts:1:14]
|
||||
1 │ function F() {
|
||||
@@ -25836,6 +25938,30 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
· ────
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration3.ts:2:3]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare namespace M2 {
|
||||
· ───────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration4.d.ts:2:3]
|
||||
1 │ namespace M {
|
||||
2 │ declare namespace M1 {
|
||||
· ───────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ModuleDeclarations/parserModuleDeclaration5.ts:3:5]
|
||||
2 │ declare namespace M2 {
|
||||
3 │ declare namespace M3 {
|
||||
· ───────
|
||||
4 │ }
|
||||
╰────
|
||||
|
||||
× Expected `(` but found `;`
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/ObjectTypes/parserObjectType5.ts:3:7]
|
||||
2 │ A: B
|
||||
@@ -26970,6 +27096,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
· ─
|
||||
╰────
|
||||
|
||||
× TS(1038): A 'declare' modifier cannot be used in an already ambient context.
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/VariableDeclarations/parserVariableDeclaration4.ts:2:4]
|
||||
1 │ declare namespace M {
|
||||
2 │ declare var v;
|
||||
· ───────
|
||||
3 │ }
|
||||
╰────
|
||||
|
||||
× Unexpected token
|
||||
╭─[typescript/tests/cases/conformance/parser/ecmascript5/VariableDeclarations/parserVariableDeclaration5.ts:1:7]
|
||||
1 │ var a,
|
||||
|
||||
Reference in new issue
Block a user