Skip to content

Commit 001aa99

Browse files
authored
Fix crash when importsNotUsedAsValues is set alongside verbatimModuleSyntax (#53386)
1 parent af00915 commit 001aa99

6 files changed

+91
-9
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14721472
var argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String);
14731473
var requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String);
14741474
var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules";
1475+
// It is an error to use `importsNotUsedAsValues` alongside `verbatimModuleSyntax`, but we still need to not crash.
1476+
// Given that, in such a scenario, `verbatimModuleSyntax` is basically disabled, as least as far as alias visibility tracking goes.
1477+
var canCollectSymbolAliasAccessabilityData = !compilerOptions.verbatimModuleSyntax || !!compilerOptions.importsNotUsedAsValues;
14751478

14761479
/** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
14771480
var apparentArgumentCount: number | undefined;
@@ -4540,7 +4543,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
45404543
}
45414544

45424545
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportSpecifier) {
4543-
if (compilerOptions.verbatimModuleSyntax) {
4546+
if (!canCollectSymbolAliasAccessabilityData) {
45444547
return;
45454548
}
45464549
const symbol = getSymbolOfDeclaration(node);
@@ -4559,7 +4562,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
45594562
// we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of
45604563
// the alias as an expression (which recursively takes us back here if the target references another alias).
45614564
function markAliasSymbolAsReferenced(symbol: Symbol) {
4562-
Debug.assert(!compilerOptions.verbatimModuleSyntax);
4565+
Debug.assert(canCollectSymbolAliasAccessabilityData);
45634566
const links = getSymbolLinks(symbol);
45644567
if (!links.referenced) {
45654568
links.referenced = true;
@@ -27636,7 +27639,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2763627639
}
2763727640

2763827641
function markAliasReferenced(symbol: Symbol, location: Node) {
27639-
if (compilerOptions.verbatimModuleSyntax) {
27642+
if (!canCollectSymbolAliasAccessabilityData) {
2764027643
return;
2764127644
}
2764227645
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) {
@@ -30786,7 +30789,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3078630789
jsxFactorySym.isReferenced = SymbolFlags.All;
3078730790

3078830791
// If react/jsxFactory symbol is alias, mark it as refereced
30789-
if (!compilerOptions.verbatimModuleSyntax && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
30792+
if (canCollectSymbolAliasAccessabilityData && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
3079030793
markAliasSymbolAsReferenced(jsxFactorySym);
3079130794
}
3079230795
}
@@ -39723,7 +39726,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3972339726
const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias;
3972439727
const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isReference*/ true);
3972539728
if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) {
39726-
if (!compilerOptions.verbatimModuleSyntax
39729+
if (canCollectSymbolAliasAccessabilityData
3972739730
&& symbolIsValue(rootSymbol)
3972839731
&& !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol))
3972939732
&& !getTypeOnlyAliasDeclaration(rootSymbol)) {
@@ -44240,6 +44243,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4424044243
}
4424144244

4424244245
function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) {
44246+
if (!canCollectSymbolAliasAccessabilityData) {
44247+
return;
44248+
}
4424344249
for (const statement of sourceFile.statements) {
4424444250
if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) {
4424544251
error(
@@ -45962,7 +45968,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4596245968
}
4596345969

4596445970
function isValueAliasDeclaration(node: Node): boolean {
45965-
Debug.assert(!compilerOptions.verbatimModuleSyntax);
45971+
Debug.assert(canCollectSymbolAliasAccessabilityData);
4596645972
switch (node.kind) {
4596745973
case SyntaxKind.ImportEqualsDeclaration:
4596845974
return isAliasResolvedToValue(getSymbolOfDeclaration(node as ImportEqualsDeclaration));
@@ -46016,7 +46022,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4601646022
}
4601746023

4601846024
function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean {
46019-
Debug.assert(!compilerOptions.verbatimModuleSyntax);
46025+
Debug.assert(canCollectSymbolAliasAccessabilityData);
4602046026
if (isAliasSymbolDeclaration(node)) {
4602146027
const symbol = getSymbolOfDeclaration(node as Declaration);
4602246028
const links = symbol && getSymbolLinks(symbol);
@@ -46390,13 +46396,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4639046396
isValueAliasDeclaration: nodeIn => {
4639146397
const node = getParseTreeNode(nodeIn);
4639246398
// Synthesized nodes are always treated like values.
46393-
return node ? isValueAliasDeclaration(node) : true;
46399+
return node && canCollectSymbolAliasAccessabilityData ? isValueAliasDeclaration(node) : true;
4639446400
},
4639546401
hasGlobalName,
4639646402
isReferencedAliasDeclaration: (nodeIn, checkChildren?) => {
4639746403
const node = getParseTreeNode(nodeIn);
4639846404
// Synthesized nodes are always treated as referenced.
46399-
return node ? isReferencedAliasDeclaration(node, checkChildren) : true;
46405+
return node && canCollectSymbolAliasAccessabilityData ? isReferencedAliasDeclaration(node, checkChildren) : true;
4640046406
},
4640146407
getNodeCheckFlags: nodeIn => {
4640246408
const node = getParseTreeNode(nodeIn);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'.
2+
tests/cases/compiler/file.ts(1,1): error TS1287: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.
3+
tests/cases/compiler/index.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
4+
tests/cases/compiler/index.ts(1,9): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
5+
6+
7+
!!! error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'.
8+
==== tests/cases/compiler/file.ts (1 errors) ====
9+
export class A {}
10+
~~~~~~
11+
!!! error TS1287: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.
12+
==== tests/cases/compiler/index.ts (2 errors) ====
13+
import {A} from "./file";
14+
~~~~~~~~~~~~~~~~~~~~~~~~~
15+
!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
16+
~
17+
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
18+
19+
const a: A = null as any;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [tests/cases/compiler/noCrashWithVerbatimModuleSyntaxAndImportsNotUsedAsValues.ts] ////
2+
3+
//// [file.ts]
4+
export class A {}
5+
//// [index.ts]
6+
import {A} from "./file";
7+
8+
const a: A = null as any;
9+
10+
//// [file.js]
11+
"use strict";
12+
Object.defineProperty(exports, "__esModule", { value: true });
13+
exports.A = void 0;
14+
var A = /** @class */ (function () {
15+
function A() {
16+
}
17+
return A;
18+
}());
19+
exports.A = A;
20+
//// [index.js]
21+
"use strict";
22+
Object.defineProperty(exports, "__esModule", { value: true });
23+
var file_1 = require("./file");
24+
var a = null;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/compiler/file.ts ===
2+
export class A {}
3+
>A : Symbol(A, Decl(file.ts, 0, 0))
4+
5+
=== tests/cases/compiler/index.ts ===
6+
import {A} from "./file";
7+
>A : Symbol(A, Decl(index.ts, 0, 8))
8+
9+
const a: A = null as any;
10+
>a : Symbol(a, Decl(index.ts, 2, 5))
11+
>A : Symbol(A, Decl(index.ts, 0, 8))
12+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/compiler/file.ts ===
2+
export class A {}
3+
>A : A
4+
5+
=== tests/cases/compiler/index.ts ===
6+
import {A} from "./file";
7+
>A : typeof A
8+
9+
const a: A = null as any;
10+
>a : A
11+
>null as any : any
12+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @verbatimModuleSyntax: true
2+
// @importsNotUsedAsValues: error
3+
// @ignoreDeprecations: 5.0
4+
// @filename: file.ts
5+
export class A {}
6+
// @filename: index.ts
7+
import {A} from "./file";
8+
9+
const a: A = null as any;

0 commit comments

Comments
 (0)