Skip to content

Check resolution of tslib per file #58654

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 29 additions & 30 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1461,9 +1461,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// they no longer need the information (for example, if the user started editing again).
var cancellationToken: CancellationToken | undefined;

var requestedExternalEmitHelperNames = new Set<string>();
var requestedExternalEmitHelpers: ExternalEmitHelpers;
var externalHelpersModule: Symbol;
var scanner: Scanner | undefined;

var Symbol = objectAllocator.getSymbolConstructor();
Expand Down Expand Up @@ -49508,42 +49505,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function checkExternalEmitHelpers(location: Node, helpers: ExternalEmitHelpers) {
if ((requestedExternalEmitHelpers & helpers) !== helpers && compilerOptions.importHelpers) {
if (compilerOptions.importHelpers) {
const sourceFile = getSourceFileOfNode(location);
if (isEffectiveExternalModule(sourceFile, compilerOptions) && !(location.flags & NodeFlags.Ambient)) {
const helpersModule = resolveHelpersModule(sourceFile, location);
if (helpersModule !== unknownSymbol) {
const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers;
for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) {
if (uncheckedHelpers & helper) {
for (const name of getHelperNames(helper)) {
if (requestedExternalEmitHelperNames.has(name)) continue;
requestedExternalEmitHelperNames.add(name);

const symbol = resolveSymbol(getSymbol(getExportsOfModule(helpersModule), escapeLeadingUnderscores(name), SymbolFlags.Value));
if (!symbol) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name);
}
else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) {
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 4);
const links = getSymbolLinks(helpersModule);
links.requestedExternalEmitHelpers ??= 0 as ExternalEmitHelpers;
if ((links.requestedExternalEmitHelpers & helpers) !== helpers) {
const uncheckedHelpers = helpers & ~links.requestedExternalEmitHelpers;
for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) {
if (uncheckedHelpers & helper) {
for (const name of getHelperNames(helper)) {
const symbol = resolveSymbol(getSymbol(getExportsOfModule(helpersModule), escapeLeadingUnderscores(name), SymbolFlags.Value));
if (!symbol) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name);
}
}
else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) {
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 5);
else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) {
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 4);
}
}
}
else if (helper & ExternalEmitHelpers.SpreadArray) {
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 2)) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 3);
else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) {
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 5);
}
}
else if (helper & ExternalEmitHelpers.SpreadArray) {
if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 2)) {
error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 3);
}
}
}
}
}
}
links.requestedExternalEmitHelpers |= helpers;
}
requestedExternalEmitHelpers |= helpers;
}
}
}
Expand Down Expand Up @@ -49606,10 +49604,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function resolveHelpersModule(file: SourceFile, errorNode: Node) {
if (!externalHelpersModule) {
externalHelpersModule = resolveExternalModule(getImportHelpersImportSpecifier(file), externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol;
const links = getNodeLinks(file);
if (!links.externalHelpersModule) {
links.externalHelpersModule = resolveExternalModule(getImportHelpersImportSpecifier(file), externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol;
}
return externalHelpersModule;
return links.externalHelpersModule;
}

// GRAMMAR CHECKING
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5953,6 +5953,7 @@ export interface SymbolLinks {
tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label
accessibleChainCache?: Map<string, Symbol[] | undefined>;
filteredIndexSymbolCache?: Map<string, Symbol> //Symbol with applicable declarations
requestedExternalEmitHelpers?: ExternalEmitHelpers; // External emit helpers already checked for this symbol.
}

// dprint-ignore
Expand Down Expand Up @@ -6139,6 +6140,7 @@ export interface NodeLinks {
parameterInitializerContainsUndefined?: boolean; // True if this is a parameter declaration whose type annotation contains "undefined".
fakeScopeForSignatureDeclaration?: "params" | "typeParams"; // If present, this is a fake scope injected into an enclosing declaration chain.
assertionExpressionType?: Type; // Cached type of the expression of a type assertion
externalHelpersModule?: Symbol; // Resolved symbol for the external helpers module
}

/** @internal */
Expand Down
10 changes: 8 additions & 2 deletions tests/baselines/reference/esModuleInteropTslibHelpers.errors.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
file2.ts(1,1): error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
file3.ts(1,9): error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
file4.ts(1,14): error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.


==== refs.d.ts (0 errors) ====
Expand All @@ -13,11 +15,15 @@ file2.ts(1,1): error TS2354: This syntax requires an imported helper but module
!!! error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
path.resolve("", "../");
export class Foo2 { }
==== file3.ts (0 errors) ====
==== file3.ts (1 errors) ====
import {default as resolve} from "path";
~~~~~~~~~~~~~~~~~~
!!! error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
resolve("", "../");
export class Foo3 { }
==== file4.ts (0 errors) ====
==== file4.ts (1 errors) ====
import {Bar, default as resolve} from "path";
~~~~~~~~~~~~~~~~~~
!!! error TS2354: This syntax requires an imported helper but module 'tslib' cannot be found.
resolve("", "../");
export { Bar }
36 changes: 36 additions & 0 deletions tests/baselines/reference/tslibMissingHelper.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/package1/index.ts(2,16): error TS2343: This syntax requires an imported helper named '__awaiter' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.


==== /tsconfig.json (0 errors) ====
{
"compilerOptions": {
"strict": true,
"target": "ES2016",
"importHelpers": true,
"module": "commonjs",
}
}

==== /package1/index.ts (1 errors) ====
export {};
async function foo(): Promise<void> {}
~~~
!!! error TS2343: This syntax requires an imported helper named '__awaiter' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
async function bar(): Promise<void> {}

==== /package2/index.ts (0 errors) ====
export {};
async function foo(): Promise<void> {}

==== /node_modules/tslib/package.json (0 errors) ====
{
"name": "tslib",
"main": "tslib.js",
"typings": "tslib.d.ts"
}

==== /node_modules/tslib/tslib.d.ts (0 errors) ====
export const notAHelper: any;

==== /node_modules/tslib/tslib.js (0 errors) ====
module.exports.notAHelper = 3;
41 changes: 41 additions & 0 deletions tests/baselines/reference/tslibMissingHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//// [tests/cases/compiler/tslibMissingHelper.ts] ////

//// [package.json]
{
"name": "tslib",
"main": "tslib.js",
"typings": "tslib.d.ts"
}

//// [tslib.d.ts]
export const notAHelper: any;

//// [tslib.js]
module.exports.notAHelper = 3;
//// [index.ts]
export {};
async function foo(): Promise<void> {}
async function bar(): Promise<void> {}

//// [index.ts]
export {};
async function foo(): Promise<void> {}


//// [index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
function foo() {
return tslib_1.__awaiter(this, void 0, void 0, function* () { });
}
function bar() {
return tslib_1.__awaiter(this, void 0, void 0, function* () { });
}
//// [index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
function foo() {
return tslib_1.__awaiter(this, void 0, void 0, function* () { });
}
22 changes: 22 additions & 0 deletions tests/baselines/reference/tslibMissingHelper.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [tests/cases/compiler/tslibMissingHelper.ts] ////

=== /package1/index.ts ===
export {};
async function foo(): Promise<void> {}
>foo : Symbol(foo, Decl(index.ts, 0, 10))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))

async function bar(): Promise<void> {}
>bar : Symbol(bar, Decl(index.ts, 1, 38))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))

=== /package2/index.ts ===
export {};
async function foo(): Promise<void> {}
>foo : Symbol(foo, Decl(index.ts, 0, 10))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))

=== /node_modules/tslib/tslib.d.ts ===
export const notAHelper: any;
>notAHelper : Symbol(notAHelper, Decl(tslib.d.ts, --, --))

23 changes: 23 additions & 0 deletions tests/baselines/reference/tslibMissingHelper.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//// [tests/cases/compiler/tslibMissingHelper.ts] ////

=== /package1/index.ts ===
export {};
async function foo(): Promise<void> {}
>foo : () => Promise<void>
> : ^^^^^^

async function bar(): Promise<void> {}
>bar : () => Promise<void>
> : ^^^^^^

=== /package2/index.ts ===
export {};
async function foo(): Promise<void> {}
>foo : () => Promise<void>
> : ^^^^^^

=== /node_modules/tslib/tslib.d.ts ===
export const notAHelper: any;
>notAHelper : any
> : ^^^

62 changes: 62 additions & 0 deletions tests/baselines/reference/tslibMultipleMissingHelper.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/package1/index.ts(2,16): error TS2343: This syntax requires an imported helper named '__awaiter' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
/package1/other.ts(3,32): error TS2343: This syntax requires an imported helper named '__rest' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
/package2/index.ts(2,16): error TS2343: This syntax requires an imported helper named '__awaiter' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.


==== /tsconfig.json (0 errors) ====
{
"compilerOptions": {
"strict": true,
"target": "ES2016",
"importHelpers": true,
"module": "commonjs",
}
}

==== /package1/index.ts (1 errors) ====
export {};
async function foo(): Promise<void> {}
~~~
!!! error TS2343: This syntax requires an imported helper named '__awaiter' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
async function bar(): Promise<void> {}

==== /package1/other.ts (1 errors) ====
export {};
export async function noop(): Promise<void> {}
export function spread({ a, ...rest }: { a: number, b: number}) {
~~~~
!!! error TS2343: This syntax requires an imported helper named '__rest' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.
return { c: "c", ...rest };
}

==== /package2/index.ts (1 errors) ====
export {};
async function foo(): Promise<void> {}
~~~
!!! error TS2343: This syntax requires an imported helper named '__awaiter' which does not exist in 'tslib'. Consider upgrading your version of 'tslib'.

==== /package1/node_modules/tslib/package.json (0 errors) ====
{
"name": "tslib",
"main": "tslib.js",
"typings": "tslib.d.ts"
}

==== /package1/node_modules/tslib/tslib.d.ts (0 errors) ====
export const notAHelper: any;

==== /package1/node_modules/tslib/tslib.js (0 errors) ====
module.exports.notAHelper = 3;

==== /package2/node_modules/tslib/package.json (0 errors) ====
{
"name": "tslib",
"main": "tslib.js",
"typings": "tslib.d.ts"
}

==== /package2/node_modules/tslib/tslib.d.ts (0 errors) ====
export const notAHelper: any;

==== /package2/node_modules/tslib/tslib.js (0 errors) ====
module.exports.notAHelper = 3;
Loading