From 8b1f9d6059ab181108f37ea8a5574278e01c1d3a Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 19 Feb 2023 12:57:29 -0800 Subject: [PATCH 1/4] Add test --- ...spuriousCircularityOnTypeImport.errors.txt | 37 ++++++++++ .../spuriousCircularityOnTypeImport.js | 28 ++++++++ .../spuriousCircularityOnTypeImport.symbols | 67 +++++++++++++++++++ .../spuriousCircularityOnTypeImport.types | 35 ++++++++++ .../spuriousCircularityOnTypeImport.ts | 20 ++++++ 5 files changed, 187 insertions(+) create mode 100644 tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt 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 diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt b/tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt new file mode 100644 index 0000000000000..54fbf8e4779fa --- /dev/null +++ b/tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt @@ -0,0 +1,37 @@ +tests/cases/compiler/index.ts(6,38): error TS2313: Type parameter 'FuncMap' has a circular constraint. +tests/cases/compiler/index.ts(6,68): error TS2344: Type 'FuncMap' does not satisfy the constraint 'Record unknown>'. +tests/cases/compiler/index.ts(6,143): error TS2344: Type 'FuncMap[P]' does not satisfy the constraint '(...args: any) => any'. + Type 'FuncMap[keyof FuncMap]' is not assignable to type '(...args: any) => any'. + Type 'FuncMap[string] | FuncMap[number] | FuncMap[symbol]' is not assignable to type '(...args: any) => any'. + Type 'FuncMap[string]' is not assignable to type '(...args: any) => any'. + + +==== tests/cases/compiler/types.ts (0 errors) ==== + export type SelectorMap unknown>> = { + [key in keyof T]: T[key]; + }; + +==== tests/cases/compiler/index.ts (3 errors) ==== + export type SelectorMap unknown>> = { + [key in keyof T]: T[key]; + }; + + export declare const value2: { + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2313: Type parameter 'FuncMap' has a circular constraint. + ~~~~~~~ +!!! error TS2344: Type 'FuncMap' does not satisfy the constraint 'Record unknown>'. +!!! related TS2208 tests/cases/compiler/index.ts:6:22: This type parameter might need an `extends Record unknown>` constraint. + ~~~~~~~~~~ +!!! error TS2344: Type 'FuncMap[P]' does not satisfy the constraint '(...args: any) => any'. +!!! error TS2344: Type 'FuncMap[keyof FuncMap]' is not assignable to type '(...args: any) => any'. +!!! error TS2344: Type 'FuncMap[string] | FuncMap[number] | FuncMap[symbol]' is not assignable to type '(...args: any) => any'. +!!! error TS2344: Type 'FuncMap[string]' is not assignable to type '(...args: any) => any'. + }; + + export declare const value3: { + sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; + }; + + \ No newline at end of file diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.js b/tests/baselines/reference/spuriousCircularityOnTypeImport.js new file mode 100644 index 0000000000000..53ccf9f8a3f14 --- /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 0000000000000..a786b23d24f41 --- /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 0000000000000..14c4f35a9950b --- /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 0000000000000..16dc9820a0e41 --- /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 }; +}; + From 99e71739060b4b69be437a5b4224254ac1473327 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:51:51 -0800 Subject: [PATCH 2/4] Check type argument constraints for import nodes after resolvedType is set --- src/compiler/checker.ts | 16 ++++---- ...spuriousCircularityOnTypeImport.errors.txt | 37 ------------------- .../spuriousCircularityOnTypeImport.types | 4 +- 3 files changed, 11 insertions(+), 46 deletions(-) delete mode 100644 tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 50cf05bad962d..251c10b295033 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17932,6 +17932,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links.resolvedType = errorType; } } + + if (node.typeArguments && !isErrorType(links.resolvedType)) { + addLazyDiagnostic(() => { + const typeParameters = getTypeParametersForTypeAndSymbol(links.resolvedType!, links.resolvedSymbol!); + if (typeParameters) { + checkTypeArgumentConstraints(node, typeParameters); + } + }); + } } return links.resolvedType; } @@ -17943,13 +17952,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 } } diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt b/tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt deleted file mode 100644 index 54fbf8e4779fa..0000000000000 --- a/tests/baselines/reference/spuriousCircularityOnTypeImport.errors.txt +++ /dev/null @@ -1,37 +0,0 @@ -tests/cases/compiler/index.ts(6,38): error TS2313: Type parameter 'FuncMap' has a circular constraint. -tests/cases/compiler/index.ts(6,68): error TS2344: Type 'FuncMap' does not satisfy the constraint 'Record unknown>'. -tests/cases/compiler/index.ts(6,143): error TS2344: Type 'FuncMap[P]' does not satisfy the constraint '(...args: any) => any'. - Type 'FuncMap[keyof FuncMap]' is not assignable to type '(...args: any) => any'. - Type 'FuncMap[string] | FuncMap[number] | FuncMap[symbol]' is not assignable to type '(...args: any) => any'. - Type 'FuncMap[string]' is not assignable to type '(...args: any) => any'. - - -==== tests/cases/compiler/types.ts (0 errors) ==== - export type SelectorMap unknown>> = { - [key in keyof T]: T[key]; - }; - -==== tests/cases/compiler/index.ts (3 errors) ==== - export type SelectorMap unknown>> = { - [key in keyof T]: T[key]; - }; - - export declare const value2: { - sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2313: Type parameter 'FuncMap' has a circular constraint. - ~~~~~~~ -!!! error TS2344: Type 'FuncMap' does not satisfy the constraint 'Record unknown>'. -!!! related TS2208 tests/cases/compiler/index.ts:6:22: This type parameter might need an `extends Record unknown>` constraint. - ~~~~~~~~~~ -!!! error TS2344: Type 'FuncMap[P]' does not satisfy the constraint '(...args: any) => any'. -!!! error TS2344: Type 'FuncMap[keyof FuncMap]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'FuncMap[string] | FuncMap[number] | FuncMap[symbol]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'FuncMap[string]' is not assignable to type '(...args: any) => any'. - }; - - export declare const value3: { - sliceSelectors: >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters }; - }; - - \ No newline at end of file diff --git a/tests/baselines/reference/spuriousCircularityOnTypeImport.types b/tests/baselines/reference/spuriousCircularityOnTypeImport.types index 14c4f35a9950b..5422e4cfae2f5 100644 --- a/tests/baselines/reference/spuriousCircularityOnTypeImport.types +++ b/tests/baselines/reference/spuriousCircularityOnTypeImport.types @@ -15,10 +15,10 @@ export type SelectorMap unkno }; export declare const value2: { ->value2 : { sliceSelectors: (selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters; }; } +>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; } +>sliceSelectors : >(selectorsBySlice: FuncMap) => { [P in keyof FuncMap]: Parameters; } >selectorsBySlice : FuncMap }; From f85cc4435cb2aed06cc4b215d90cf58c8e16946e Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 19 Feb 2023 14:37:48 -0800 Subject: [PATCH 3/4] Deprecated test --- .../typeReferenceAndImportDeprecated.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/cases/fourslash/typeReferenceAndImportDeprecated.ts diff --git a/tests/cases/fourslash/typeReferenceAndImportDeprecated.ts b/tests/cases/fourslash/typeReferenceAndImportDeprecated.ts new file mode 100644 index 0000000000000..18e5a849db9d7 --- /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] + }, +]); From 59ce29c7d0a160f71f2b62d3c2ec410d63dcfdd7 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 19 Feb 2023 14:39:37 -0800 Subject: [PATCH 4/4] Share code between between type references and import nodes --- src/compiler/checker.ts | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 251c10b295033..eedb0515d0250 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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) { @@ -17932,15 +17932,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links.resolvedType = errorType; } } - - if (node.typeArguments && !isErrorType(links.resolvedType)) { - addLazyDiagnostic(() => { - const typeParameters = getTypeParametersForTypeAndSymbol(links.resolvedType!, links.resolvedSymbol!); - if (typeParameters) { - checkTypeArgumentConstraints(node, typeParameters); - } - }); - } } return links.resolvedType; } @@ -38327,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) { @@ -38348,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); } @@ -38374,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))); @@ -38577,7 +38572,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - getTypeFromTypeNode(node); + checkTypeReferenceOrImport(node); } function checkNamedTupleMember(node: NamedTupleMember) {