From 3471bd7d867364af93e9c2f67264d6c75ec93cd5 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:42:15 -0800 Subject: [PATCH] Fix type import node circularity errors in eager diagnostic mode, deprecations (#52861) --- src/compiler/checker.ts | 25 +++---- .../spuriousCircularityOnTypeImport.js | 28 ++++++++ .../spuriousCircularityOnTypeImport.symbols | 67 +++++++++++++++++++ .../spuriousCircularityOnTypeImport.types | 35 ++++++++++ .../spuriousCircularityOnTypeImport.ts | 20 ++++++ .../typeReferenceAndImportDeprecated.ts | 38 +++++++++++ 6 files changed, 199 insertions(+), 14 deletions(-) create mode 100644 tests/baselines/reference/spuriousCircularityOnTypeImport.js create mode 100644 tests/baselines/reference/spuriousCircularityOnTypeImport.symbols create mode 100644 tests/baselines/reference/spuriousCircularityOnTypeImport.types create mode 100644 tests/cases/compiler/spuriousCircularityOnTypeImport.ts create mode 100644 tests/cases/fourslash/typeReferenceAndImportDeprecated.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 38d20826097..358a44f5e05 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14915,7 +14915,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) { @@ -17944,13 +17944,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 } } @@ -38326,8 +38319,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) { @@ -38347,11 +38340,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); } @@ -38373,7 +38370,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))); @@ -38576,7 +38573,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - getTypeFromTypeNode(node); + checkTypeReferenceOrImport(node); } function checkNamedTupleMember(node: NamedTupleMember) { diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.js b/tests/baselines/reference/spuriousCircularityOnTypeImport.js new file mode 100644 index 00000000000..53ccf9f8a3f --- /dev/null +++ b/tests/baselines/reference/spuriousCircularityOnTypeImport.js @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/spuriousCircularityOnTypeImport.ts] //// + +//// [types.ts] +export type SelectorMap unknown>> = { + [key in keyof T]: T[key]; +}; + +//// [index.ts] +export type SelectorMap unknown>> = { + [key in keyof T]: T[key]; +}; + +export declare const value2: { + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +}; + +export declare const value3: { + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +}; + + + +//// [types.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.symbols b/tests/baselines/reference/spuriousCircularityOnTypeImport.symbols new file mode 100644 index 00000000000..a786b23d24f --- /dev/null +++ b/tests/baselines/reference/spuriousCircularityOnTypeImport.symbols @@ -0,0 +1,67 @@ +=== tests/cases/compiler/types.ts === +export type SelectorMap 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 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: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +>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: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +>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)) + +}; + + diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.types b/tests/baselines/reference/spuriousCircularityOnTypeImport.types new file mode 100644 index 00000000000..5422e4cfae2 --- /dev/null +++ b/tests/baselines/reference/spuriousCircularityOnTypeImport.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/types.ts === +export type SelectorMap unknown>> = { +>SelectorMap : SelectorMap +>params : unknown[] + + [key in keyof T]: T[key]; +}; + +=== tests/cases/compiler/index.ts === +export type SelectorMap unknown>> = { +>SelectorMap : SelectorMap +>params : unknown[] + + [key in keyof T]: T[key]; +}; + +export declare const value2: { +>value2 : { sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters; }; } + + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +>sliceSelectors : >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters; } +>selectorsBySlice : FuncMap + +}; + +export declare const value3: { +>value3 : { sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters; }; } + + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +>sliceSelectors : >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters; } +>selectorsBySlice : FuncMap + +}; + + diff --git a/tests/cases/compiler/spuriousCircularityOnTypeImport.ts b/tests/cases/compiler/spuriousCircularityOnTypeImport.ts new file mode 100644 index 00000000000..16dc9820a0e --- /dev/null +++ b/tests/cases/compiler/spuriousCircularityOnTypeImport.ts @@ -0,0 +1,20 @@ +// @strict: true + +// @filename: types.ts +export type SelectorMap unknown>> = { + [key in keyof T]: T[key]; +}; + +// @filename: index.ts +export type SelectorMap unknown>> = { + [key in keyof T]: T[key]; +}; + +export declare const value2: { + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +}; + +export declare const value3: { + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +}; + diff --git a/tests/cases/fourslash/typeReferenceAndImportDeprecated.ts b/tests/cases/fourslash/typeReferenceAndImportDeprecated.ts new file mode 100644 index 00000000000..18e5a849db9 --- /dev/null +++ b/tests/cases/fourslash/typeReferenceAndImportDeprecated.ts @@ -0,0 +1,38 @@ +/// + +// @filename: types.ts +//// /** @deprecated */ +//// export type SelectorMap unknown>> = { +//// [key in keyof T]: T[key]; +//// }; + +// @filename: index.ts +//// /** @deprecated */ +//// export type SelectorMap unknown>> = { +//// [key in keyof T]: T[key]; +//// }; +//// +//// export declare const value2: { +//// sliceSelectors: |]>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +//// }; +//// +//// export declare const value3: { +//// sliceSelectors: |]>(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; +//// }; + +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] + }, +]);