Fix crash when importsNotUsedAsValues is set alongside verbatimModuleSyntax (#53386)

This commit is contained in:
Wesley Wigham 2023-03-20 12:30:11 -07:00 committed by GitHub
parent af00915d71
commit 001aa99734
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 9 deletions

View File

@ -1472,6 +1472,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String);
var requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String);
var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules";
// It is an error to use `importsNotUsedAsValues` alongside `verbatimModuleSyntax`, but we still need to not crash.
// Given that, in such a scenario, `verbatimModuleSyntax` is basically disabled, as least as far as alias visibility tracking goes.
var canCollectSymbolAliasAccessabilityData = !compilerOptions.verbatimModuleSyntax || !!compilerOptions.importsNotUsedAsValues;
/** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
var apparentArgumentCount: number | undefined;
@ -4540,7 +4543,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function markExportAsReferenced(node: ImportEqualsDeclaration | ExportSpecifier) {
if (compilerOptions.verbatimModuleSyntax) {
if (!canCollectSymbolAliasAccessabilityData) {
return;
}
const symbol = getSymbolOfDeclaration(node);
@ -4559,7 +4562,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of
// the alias as an expression (which recursively takes us back here if the target references another alias).
function markAliasSymbolAsReferenced(symbol: Symbol) {
Debug.assert(!compilerOptions.verbatimModuleSyntax);
Debug.assert(canCollectSymbolAliasAccessabilityData);
const links = getSymbolLinks(symbol);
if (!links.referenced) {
links.referenced = true;
@ -27636,7 +27639,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function markAliasReferenced(symbol: Symbol, location: Node) {
if (compilerOptions.verbatimModuleSyntax) {
if (!canCollectSymbolAliasAccessabilityData) {
return;
}
if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) {
@ -30786,7 +30789,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
jsxFactorySym.isReferenced = SymbolFlags.All;
// If react/jsxFactory symbol is alias, mark it as refereced
if (!compilerOptions.verbatimModuleSyntax && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
if (canCollectSymbolAliasAccessabilityData && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) {
markAliasSymbolAsReferenced(jsxFactorySym);
}
}
@ -39723,7 +39726,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias;
const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isReference*/ true);
if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) {
if (!compilerOptions.verbatimModuleSyntax
if (canCollectSymbolAliasAccessabilityData
&& symbolIsValue(rootSymbol)
&& !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol))
&& !getTypeOnlyAliasDeclaration(rootSymbol)) {
@ -44240,6 +44243,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) {
if (!canCollectSymbolAliasAccessabilityData) {
return;
}
for (const statement of sourceFile.statements) {
if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) {
error(
@ -45962,7 +45968,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function isValueAliasDeclaration(node: Node): boolean {
Debug.assert(!compilerOptions.verbatimModuleSyntax);
Debug.assert(canCollectSymbolAliasAccessabilityData);
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
return isAliasResolvedToValue(getSymbolOfDeclaration(node as ImportEqualsDeclaration));
@ -46016,7 +46022,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean {
Debug.assert(!compilerOptions.verbatimModuleSyntax);
Debug.assert(canCollectSymbolAliasAccessabilityData);
if (isAliasSymbolDeclaration(node)) {
const symbol = getSymbolOfDeclaration(node as Declaration);
const links = symbol && getSymbolLinks(symbol);
@ -46390,13 +46396,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
isValueAliasDeclaration: nodeIn => {
const node = getParseTreeNode(nodeIn);
// Synthesized nodes are always treated like values.
return node ? isValueAliasDeclaration(node) : true;
return node && canCollectSymbolAliasAccessabilityData ? isValueAliasDeclaration(node) : true;
},
hasGlobalName,
isReferencedAliasDeclaration: (nodeIn, checkChildren?) => {
const node = getParseTreeNode(nodeIn);
// Synthesized nodes are always treated as referenced.
return node ? isReferencedAliasDeclaration(node, checkChildren) : true;
return node && canCollectSymbolAliasAccessabilityData ? isReferencedAliasDeclaration(node, checkChildren) : true;
},
getNodeCheckFlags: nodeIn => {
const node = getParseTreeNode(nodeIn);

View File

@ -0,0 +1,19 @@
error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'.
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.
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'.
tests/cases/compiler/index.ts(1,9): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
!!! error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'.
==== tests/cases/compiler/file.ts (1 errors) ====
export class A {}
~~~~~~
!!! error TS1287: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.
==== tests/cases/compiler/index.ts (2 errors) ====
import {A} from "./file";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
const a: A = null as any;

View File

@ -0,0 +1,24 @@
//// [tests/cases/compiler/noCrashWithVerbatimModuleSyntaxAndImportsNotUsedAsValues.ts] ////
//// [file.ts]
export class A {}
//// [index.ts]
import {A} from "./file";
const a: A = null as any;
//// [file.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.A = void 0;
var A = /** @class */ (function () {
function A() {
}
return A;
}());
exports.A = A;
//// [index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var file_1 = require("./file");
var a = null;

View File

@ -0,0 +1,12 @@
=== tests/cases/compiler/file.ts ===
export class A {}
>A : Symbol(A, Decl(file.ts, 0, 0))
=== tests/cases/compiler/index.ts ===
import {A} from "./file";
>A : Symbol(A, Decl(index.ts, 0, 8))
const a: A = null as any;
>a : Symbol(a, Decl(index.ts, 2, 5))
>A : Symbol(A, Decl(index.ts, 0, 8))

View File

@ -0,0 +1,12 @@
=== tests/cases/compiler/file.ts ===
export class A {}
>A : A
=== tests/cases/compiler/index.ts ===
import {A} from "./file";
>A : typeof A
const a: A = null as any;
>a : A
>null as any : any

View File

@ -0,0 +1,9 @@
// @verbatimModuleSyntax: true
// @importsNotUsedAsValues: error
// @ignoreDeprecations: 5.0
// @filename: file.ts
export class A {}
// @filename: index.ts
import {A} from "./file";
const a: A = null as any;