Skip to content

Commit

Permalink
Move ambient const enum error from use site to import in verbatimModu…
Browse files Browse the repository at this point in the history
…leSyntax (#86338)
  • Loading branch information
andrewbranch committed Jul 30, 2024
1 parent 3568679 commit 3404817
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 1 deletion.
30 changes: 29 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40710,7 40710,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query);
}

if (getIsolatedModules(compilerOptions)) {
// --verbatimModuleSyntax only gets checked here when the enum usage does not
// resolve to an import, because imports of ambient const enums get checked
// separately in `checkAliasSymbol`.
if (
compilerOptions.isolatedModules
|| compilerOptions.verbatimModuleSyntax
&& ok
&& !resolveName(
node,
getFirstIdentifier(node as EntityNameOrEntityNameExpression),
SymbolFlags.Alias,
/*nameNotFoundMessage*/ undefined,
/*isUse*/ false,
/*excludeGlobals*/ true,
)
) {
Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum));
const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration;
const redirect = host.getRedirectReferenceForResolutionFromSourceOfProject(getSourceFileOfNode(constEnumDeclaration).resolvedPath);
Expand Down Expand Up @@ -47264,6 47279,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// in files that are unambiguously CommonJS in this mode.
error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve);
}

if (
compilerOptions.verbatimModuleSyntax &&
!isTypeOnlyImportOrExportDeclaration(node) &&
!(node.flags & NodeFlags.Ambient) &&
targetFlags & SymbolFlags.ConstEnum
) {
const constEnumDeclaration = target.valueDeclaration as EnumDeclaration;
const redirect = host.getRedirectReferenceForResolutionFromSourceOfProject(getSourceFileOfNode(constEnumDeclaration).resolvedPath);
if (constEnumDeclaration.flags & NodeFlags.Ambient && (!redirect || !shouldPreserveConstEnums(redirect.commandLine.options))) {
error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName);
}
}
}

if (isImportSpecifier(node)) {
Expand Down
38 changes: 38 additions & 0 deletions src/testRunner/unittests/tsc/projectReferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 115,42 @@ describe("unittests:: tsc:: projectReferences::", () => {
}),
commandLineArgs: ["--p", "src/project"],
});

verifyTsc({
scenario: "projectReferences",
subScenario: "importing const enum from referenced project with preserveConstEnums and verbatimModuleSyntax",
fs: () =>
loadProjectFromFiles({
"/src/preserve/index.ts": "export const enum E { A = 1 }",
"/src/preserve/index.d.ts": "export declare const enum E { A = 1 }",
"/src/preserve/tsconfig.json": jsonToReadableText({
compilerOptions: {
composite: true,
declaration: true,
preserveConstEnums: true,
},
}),
"/src/no-preserve/index.ts": "export const enum E { A = 1 }",
"/src/no-preserve/index.d.ts": "export declare const enum F { A = 1 }",
"/src/no-preserve/tsconfig.json": jsonToReadableText({
compilerOptions: {
composite: true,
declaration: true,
preserveConstEnums: false,
},
}),
"/src/project/index.ts": `import { E } from "../preserve";\nimport { F } from "../no-preserve";\nE.A; F.A;`,
"/src/project/tsconfig.json": jsonToReadableText({
compilerOptions: {
module: "preserve",
verbatimModuleSyntax: true,
},
references: [
{ path: "../preserve" },
{ path: "../no-preserve" },
],
}),
}),
commandLineArgs: ["--p", "src/project", "--pretty", "false"],
});
});
Original file line number Diff line number Diff line change
@@ -0,0 1,83 @@
currentDirectory:: / useCaseSensitiveFileNames: false
Input::
//// [/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }
interface ReadonlyArray<T> {}
declare const console: { log(msg: any): void; };

//// [/src/no-preserve/index.d.ts]
export declare const enum F { A = 1 }

//// [/src/no-preserve/index.ts]
export const enum E { A = 1 }

//// [/src/no-preserve/tsconfig.json]
{
"compilerOptions": {
"composite": true,
"declaration": true,
"preserveConstEnums": false
}
}

//// [/src/preserve/index.d.ts]
export declare const enum E { A = 1 }

//// [/src/preserve/index.ts]
export const enum E { A = 1 }

//// [/src/preserve/tsconfig.json]
{
"compilerOptions": {
"composite": true,
"declaration": true,
"preserveConstEnums": true
}
}

//// [/src/project/index.ts]
import { E } from "../preserve";
import { F } from "../no-preserve";
E.A; F.A;

//// [/src/project/tsconfig.json]
{
"compilerOptions": {
"module": "preserve",
"verbatimModuleSyntax": true
},
"references": [
{
"path": "../preserve"
},
{
"path": "../no-preserve"
}
]
}



Output::
/lib/tsc --p src/project --pretty false
src/project/index.ts(2,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated


//// [/src/project/index.js]
import { E } from "../preserve";
import { F } from "../no-preserve";
E.A;
F.A;


Original file line number Diff line number Diff line change
@@ -0,0 1,27 @@
/a.ts(1,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
/a.ts(4,1): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
/b.ts(1,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.


==== /node_modules/pkg/index.d.ts (0 errors) ====
export declare const enum E { A, B, C }
declare global {
const enum F { A, B, C }
}

==== /a.ts (2 errors) ====
import { E } from "pkg"; // Error
~
!!! error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
import type { E as _E } from "pkg"; // Ok
console.log(E.A); // Ok
F.A; // Error
~
!!! error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.

==== /b.ts (1 errors) ====
export { E } from "pkg"; // Error
~
!!! error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
export type { E as _E } from "pkg"; // Ok

Original file line number Diff line number Diff line change
@@ -0,0 1,21 @@
// @verbatimModuleSyntax: true
// @target: esnext
// @module: preserve
// @noEmit: true
// @noTypesAndSymbols: true

// @Filename: /node_modules/pkg/index.d.ts
export declare const enum E { A, B, C }
declare global {
const enum F { A, B, C }
}

// @Filename: /a.ts
import { E } from "pkg"; // Error
import type { E as _E } from "pkg"; // Ok
console.log(E.A); // Ok
F.A; // Error

// @Filename: /b.ts
export { E } from "pkg"; // Error
export type { E as _E } from "pkg"; // Ok

0 comments on commit 3404817

Please sign in to comment.