Skip to content

Fix type import node circularity errors in eager diagnostic mode, deprecations #52861

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 4 commits into from
Feb 21, 2023
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
25 changes: 11 additions & 14 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14914,7 +14914,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent);
if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) {
const typeReference = grandParent as TypeReferenceNode;
const typeParameters = getTypeParametersForTypeReference(typeReference);
const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReference);
if (typeParameters) {
const index = typeReference.typeArguments!.indexOf(childTypeParameter as TypeNode);
if (index < typeParameters.length) {
Expand Down Expand Up @@ -17943,13 +17943,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getInstantiationExpressionType(getTypeOfSymbol(symbol), node); // intentionally doesn't use resolved symbol so type is cached as expected on the alias
}
else {
const type = tryGetDeclaredTypeOfSymbol(resolvedSymbol); // call this first to ensure typeParameters is populated (if applicable)
const typeParameters = type && getTypeParametersForTypeAndSymbol(type, resolvedSymbol);
if (node.typeArguments && typeParameters) {
addLazyDiagnostic(() => {
checkTypeArgumentConstraints(node, typeParameters);
});
}
return getTypeReferenceType(node, resolvedSymbol); // getTypeReferenceType doesn't handle aliases - it must get the resolved symbol
}
}
Expand Down Expand Up @@ -38325,8 +38318,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return undefined;
}

function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) {
const type = getTypeFromTypeReference(node);
function getTypeParametersForTypeReferenceOrImport(node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode) {
const type = getTypeFromTypeNode(node);
if (!isErrorType(type)) {
const symbol = getNodeLinks(node).resolvedSymbol;
if (symbol) {
Expand All @@ -38346,11 +38339,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
forEach(node.typeArguments, checkSourceElement);
const type = getTypeFromTypeReference(node);
checkTypeReferenceOrImport(node);
}

function checkTypeReferenceOrImport(node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode) {
const type = getTypeFromTypeNode(node);
if (!isErrorType(type)) {
if (node.typeArguments) {
addLazyDiagnostic(() => {
const typeParameters = getTypeParametersForTypeReference(node);
const typeParameters = getTypeParametersForTypeReferenceOrImport(node);
if (typeParameters) {
checkTypeArgumentConstraints(node, typeParameters);
}
Expand All @@ -38372,7 +38369,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function getTypeArgumentConstraint(node: TypeNode): Type | undefined {
const typeReferenceNode = tryCast(node.parent, isTypeReferenceType);
if (!typeReferenceNode) return undefined;
const typeParameters = getTypeParametersForTypeReference(typeReferenceNode);
const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReferenceNode);
if (!typeParameters) return undefined;
const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]);
return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
Expand Down Expand Up @@ -38575,7 +38572,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

getTypeFromTypeNode(node);
checkTypeReferenceOrImport(node);
}

function checkNamedTupleMember(node: NamedTupleMember) {
Expand Down
28 changes: 28 additions & 0 deletions tests/baselines/reference/spuriousCircularityOnTypeImport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//// [tests/cases/compiler/spuriousCircularityOnTypeImport.ts] ////

//// [types.ts]
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
[key in keyof T]: T[key];
};

//// [index.ts]
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
[key in keyof T]: T[key];
};

export declare const value2: {
sliceSelectors: <FuncMap extends import('./types').SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
};

export declare const value3: {
sliceSelectors: <FuncMap extends SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
};



//// [types.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//// [index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
67 changes: 67 additions & 0 deletions tests/baselines/reference/spuriousCircularityOnTypeImport.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
=== tests/cases/compiler/types.ts ===
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
>SelectorMap : Symbol(SelectorMap, Decl(types.ts, 0, 0))
>T : Symbol(T, Decl(types.ts, 0, 24))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>params : Symbol(params, Decl(types.ts, 0, 50))

[key in keyof T]: T[key];
>key : Symbol(key, Decl(types.ts, 1, 5))
>T : Symbol(T, Decl(types.ts, 0, 24))
>T : Symbol(T, Decl(types.ts, 0, 24))
>key : Symbol(key, Decl(types.ts, 1, 5))

};

=== tests/cases/compiler/index.ts ===
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
>SelectorMap : Symbol(SelectorMap, Decl(index.ts, 0, 0))
>T : Symbol(T, Decl(index.ts, 0, 24))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>params : Symbol(params, Decl(index.ts, 0, 50))

[key in keyof T]: T[key];
>key : Symbol(key, Decl(index.ts, 1, 5))
>T : Symbol(T, Decl(index.ts, 0, 24))
>T : Symbol(T, Decl(index.ts, 0, 24))
>key : Symbol(key, Decl(index.ts, 1, 5))

};

export declare const value2: {
>value2 : Symbol(value2, Decl(index.ts, 4, 20))

sliceSelectors: <FuncMap extends import('./types').SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
>sliceSelectors : Symbol(sliceSelectors, Decl(index.ts, 4, 30))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 5, 21))
>SelectorMap : Symbol(SelectorMap, Decl(types.ts, 0, 0))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 5, 21))
>selectorsBySlice : Symbol(selectorsBySlice, Decl(index.ts, 5, 77))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 5, 21))
>P : Symbol(P, Decl(index.ts, 5, 110))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 5, 21))
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 5, 21))
>P : Symbol(P, Decl(index.ts, 5, 110))

};

export declare const value3: {
>value3 : Symbol(value3, Decl(index.ts, 8, 20))

sliceSelectors: <FuncMap extends SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
>sliceSelectors : Symbol(sliceSelectors, Decl(index.ts, 8, 30))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 9, 21))
>SelectorMap : Symbol(SelectorMap, Decl(index.ts, 0, 0))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 9, 21))
>selectorsBySlice : Symbol(selectorsBySlice, Decl(index.ts, 9, 59))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 9, 21))
>P : Symbol(P, Decl(index.ts, 9, 92))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 9, 21))
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
>FuncMap : Symbol(FuncMap, Decl(index.ts, 9, 21))
>P : Symbol(P, Decl(index.ts, 9, 92))

};


35 changes: 35 additions & 0 deletions tests/baselines/reference/spuriousCircularityOnTypeImport.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
=== tests/cases/compiler/types.ts ===
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
>SelectorMap : SelectorMap<T>
>params : unknown[]

[key in keyof T]: T[key];
};

=== tests/cases/compiler/index.ts ===
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
>SelectorMap : SelectorMap<T>
>params : unknown[]

[key in keyof T]: T[key];
};

export declare const value2: {
>value2 : { sliceSelectors: <FuncMap extends import("tests/cases/compiler/types").SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]>; }; }

sliceSelectors: <FuncMap extends import('./types').SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
>sliceSelectors : <FuncMap extends import("tests/cases/compiler/types").SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]>; }
>selectorsBySlice : FuncMap

};

export declare const value3: {
>value3 : { sliceSelectors: <FuncMap extends SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]>; }; }

sliceSelectors: <FuncMap extends SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
>sliceSelectors : <FuncMap extends SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]>; }
>selectorsBySlice : FuncMap

};


20 changes: 20 additions & 0 deletions tests/cases/compiler/spuriousCircularityOnTypeImport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @strict: true

// @filename: types.ts
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
[key in keyof T]: T[key];
};

// @filename: index.ts
export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
[key in keyof T]: T[key];
};

export declare const value2: {
sliceSelectors: <FuncMap extends import('./types').SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
};

export declare const value3: {
sliceSelectors: <FuncMap extends SelectorMap<FuncMap>>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
};

38 changes: 38 additions & 0 deletions tests/cases/fourslash/typeReferenceAndImportDeprecated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// <reference path="fourslash.ts" />

// @filename: types.ts
//// /** @deprecated */
//// export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
//// [key in keyof T]: T[key];
//// };

// @filename: index.ts
//// /** @deprecated */
//// export type SelectorMap<T extends Record<string, (...params: unknown[]) => unknown>> = {
//// [key in keyof T]: T[key];
//// };
////
//// export declare const value2: {
//// sliceSelectors: <FuncMap extends [|import('./types').SelectorMap<FuncMap>|]>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
//// };
////
//// export declare const value3: {
//// sliceSelectors: <FuncMap extends [|SelectorMap<FuncMap>|]>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters<FuncMap[P]> };
//// };

goTo.file("index.ts");
const ranges = test.ranges();
verify.getSuggestionDiagnostics([
{
"code": 6385,
"message": "'SelectorMap' is deprecated.",
"reportsDeprecated": true,
"range": ranges[0]
},
{
"code": 6385,
"message": "'SelectorMap' is deprecated.",
"reportsDeprecated": true,
"range": ranges[1]
},
]);