From 927fe3eb631d7536a211bec9e3c46efbaac87798 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 13 Mar 2018 16:26:51 -0700 Subject: [PATCH 1/7] Combine keyof T inferences --- src/compiler/checker.ts | 13 +++-- src/compiler/types.ts | 7 +-- .../reference/api/tsserverlibrary.d.ts | 7 +-- tests/baselines/reference/api/typescript.d.ts | 7 +-- .../keyofInferenceIntersectsResults.js | 17 ++++++ .../keyofInferenceIntersectsResults.symbols | 43 +++++++++++++++ .../keyofInferenceIntersectsResults.types | 52 +++++++++++++++++++ .../keyofInferenceIntersectsResults.ts | 11 ++++ 8 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/keyofInferenceIntersectsResults.js create mode 100644 tests/baselines/reference/keyofInferenceIntersectsResults.symbols create mode 100644 tests/baselines/reference/keyofInferenceIntersectsResults.types create mode 100644 tests/cases/compiler/keyofInferenceIntersectsResults.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7c29f9adfbb52..4664d875b8031 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11724,7 +11724,10 @@ namespace ts { else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { const empty = createEmptyObjectTypeFromStringLiteral(source); contravariant = !contravariant; + const savePriority = priority; + priority |= InferencePriority.LiteralKeyof; inferFromTypes(empty, (target as IndexType).type); + priority = savePriority; contravariant = !contravariant; } else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { @@ -11967,6 +11970,10 @@ namespace ts { return candidates; } + function getContravariantInference(inference: InferenceInfo) { + return inference.priority & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates) : getCommonSubtype(inference.contraCandidates); + } + function getInferredType(context: InferenceContext, index: number): Type { const inference = context.inferences[index]; let inferredType = inference.inferredType; @@ -11987,19 +11994,19 @@ namespace ts { // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if // union types were requested or if all inferences were made from the return type position, infer a // union type. Otherwise, infer a common supertype. - const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.PriorityImpliesUnion ? + const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.PriorityImpliesCombination ? getUnionType(baseCandidates, UnionReduction.Subtype) : getCommonSupertype(baseCandidates); inferredType = getWidenedType(unwidenedType); // If we have inferred 'never' but have contravariant candidates. To get a more specific type we // infer from the contravariant candidates instead. if (inferredType.flags & TypeFlags.Never && inference.contraCandidates) { - inferredType = getCommonSubtype(inference.contraCandidates); + inferredType = getContravariantInference(inference); } } else if (inference.contraCandidates) { // We only have contravariant inferences, infer the best common subtype of those - inferredType = getCommonSubtype(inference.contraCandidates); + inferredType = getContravariantInference(inference); } else if (context.flags & InferenceFlags.NoDefault) { // We use silentNeverType as the wildcard that signals no inferences. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 235f5cab674ad..753d46e0248c0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3929,10 +3929,11 @@ namespace ts { HomomorphicMappedType = 1 << 1, // Reverse inference for homomorphic mapped type MappedTypeConstraint = 1 << 2, // Reverse inference for mapped type ReturnType = 1 << 3, // Inference made from return type of generic function - NoConstraints = 1 << 4, // Don't infer from constraints of instantiable types - AlwaysStrict = 1 << 5, // Always use strict rules for contravariant inferences + LiteralKeyof = 1 << 4, // Inference made from a string literal to a keyof T + NoConstraints = 1 << 5, // Don't infer from constraints of instantiable types + AlwaysStrict = 1 << 6, // Always use strict rules for contravariant inferences - PriorityImpliesUnion = ReturnType | MappedTypeConstraint, // These priorities imply that the resulting type should be a union of all candidates + PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates } /* @internal */ diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 7034909f6dbaa..d2bb4511d91b0 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2241,9 +2241,10 @@ declare namespace ts { HomomorphicMappedType = 2, MappedTypeConstraint = 4, ReturnType = 8, - NoConstraints = 16, - AlwaysStrict = 32, - PriorityImpliesUnion = 12, + LiteralKeyof = 16, + NoConstraints = 32, + AlwaysStrict = 64, + PriorityImpliesCombination = 28, } interface JsFileExtensionInfo { extension: string; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 1908eb1114a27..e44f5f13edb45 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2241,9 +2241,10 @@ declare namespace ts { HomomorphicMappedType = 2, MappedTypeConstraint = 4, ReturnType = 8, - NoConstraints = 16, - AlwaysStrict = 32, - PriorityImpliesUnion = 12, + LiteralKeyof = 16, + NoConstraints = 32, + AlwaysStrict = 64, + PriorityImpliesCombination = 28, } interface JsFileExtensionInfo { extension: string; diff --git a/tests/baselines/reference/keyofInferenceIntersectsResults.js b/tests/baselines/reference/keyofInferenceIntersectsResults.js new file mode 100644 index 0000000000000..8267417ad422f --- /dev/null +++ b/tests/baselines/reference/keyofInferenceIntersectsResults.js @@ -0,0 +1,17 @@ +//// [keyofInferenceIntersectsResults.ts] +interface X { + a: string; + b: string; +} + +declare function foo(x: keyof T, y: keyof T): T; +declare function bar(x: keyof T, y: keyof T): T; + +const a = foo('a', 'b'); // compiles cleanly +const b = foo('a', 'b'); // also clean +const c = bar('a', 'b'); // still clean + +//// [keyofInferenceIntersectsResults.js] +var a = foo('a', 'b'); // compiles cleanly +var b = foo('a', 'b'); // also clean +var c = bar('a', 'b'); // still clean diff --git a/tests/baselines/reference/keyofInferenceIntersectsResults.symbols b/tests/baselines/reference/keyofInferenceIntersectsResults.symbols new file mode 100644 index 0000000000000..ccdad6bb3acbe --- /dev/null +++ b/tests/baselines/reference/keyofInferenceIntersectsResults.symbols @@ -0,0 +1,43 @@ +=== tests/cases/compiler/keyofInferenceIntersectsResults.ts === +interface X { +>X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0)) + + a: string; +>a : Symbol(X.a, Decl(keyofInferenceIntersectsResults.ts, 0, 13)) + + b: string; +>b : Symbol(X.b, Decl(keyofInferenceIntersectsResults.ts, 1, 14)) +} + +declare function foo(x: keyof T, y: keyof T): T; +>foo : Symbol(foo, Decl(keyofInferenceIntersectsResults.ts, 3, 1)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21)) +>X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0)) +>x : Symbol(x, Decl(keyofInferenceIntersectsResults.ts, 5, 28)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21)) +>y : Symbol(y, Decl(keyofInferenceIntersectsResults.ts, 5, 39)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 5, 21)) + +declare function bar(x: keyof T, y: keyof T): T; +>bar : Symbol(bar, Decl(keyofInferenceIntersectsResults.ts, 5, 55)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21)) +>x : Symbol(x, Decl(keyofInferenceIntersectsResults.ts, 6, 24)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21)) +>y : Symbol(y, Decl(keyofInferenceIntersectsResults.ts, 6, 35)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21)) +>T : Symbol(T, Decl(keyofInferenceIntersectsResults.ts, 6, 21)) + +const a = foo('a', 'b'); // compiles cleanly +>a : Symbol(a, Decl(keyofInferenceIntersectsResults.ts, 8, 5)) +>foo : Symbol(foo, Decl(keyofInferenceIntersectsResults.ts, 3, 1)) +>X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0)) + +const b = foo('a', 'b'); // also clean +>b : Symbol(b, Decl(keyofInferenceIntersectsResults.ts, 9, 5)) +>foo : Symbol(foo, Decl(keyofInferenceIntersectsResults.ts, 3, 1)) + +const c = bar('a', 'b'); // still clean +>c : Symbol(c, Decl(keyofInferenceIntersectsResults.ts, 10, 5)) +>bar : Symbol(bar, Decl(keyofInferenceIntersectsResults.ts, 5, 55)) + diff --git a/tests/baselines/reference/keyofInferenceIntersectsResults.types b/tests/baselines/reference/keyofInferenceIntersectsResults.types new file mode 100644 index 0000000000000..42099caf4bd8e --- /dev/null +++ b/tests/baselines/reference/keyofInferenceIntersectsResults.types @@ -0,0 +1,52 @@ +=== tests/cases/compiler/keyofInferenceIntersectsResults.ts === +interface X { +>X : X + + a: string; +>a : string + + b: string; +>b : string +} + +declare function foo(x: keyof T, y: keyof T): T; +>foo : (x: keyof T, y: keyof T) => T +>T : T +>X : X +>x : keyof T +>T : T +>y : keyof T +>T : T +>T : T + +declare function bar(x: keyof T, y: keyof T): T; +>bar : (x: keyof T, y: keyof T) => T +>T : T +>x : keyof T +>T : T +>y : keyof T +>T : T +>T : T + +const a = foo('a', 'b'); // compiles cleanly +>a : X +>foo('a', 'b') : X +>foo : (x: keyof T, y: keyof T) => T +>X : X +>'a' : "a" +>'b' : "b" + +const b = foo('a', 'b'); // also clean +>b : { a: any; } & { b: any; } +>foo('a', 'b') : { a: any; } & { b: any; } +>foo : (x: keyof T, y: keyof T) => T +>'a' : "a" +>'b' : "b" + +const c = bar('a', 'b'); // still clean +>c : { a: any; } & { b: any; } +>bar('a', 'b') : { a: any; } & { b: any; } +>bar : (x: keyof T, y: keyof T) => T +>'a' : "a" +>'b' : "b" + diff --git a/tests/cases/compiler/keyofInferenceIntersectsResults.ts b/tests/cases/compiler/keyofInferenceIntersectsResults.ts new file mode 100644 index 0000000000000..7bd11ed2ae39e --- /dev/null +++ b/tests/cases/compiler/keyofInferenceIntersectsResults.ts @@ -0,0 +1,11 @@ +interface X { + a: string; + b: string; +} + +declare function foo(x: keyof T, y: keyof T): T; +declare function bar(x: keyof T, y: keyof T): T; + +const a = foo('a', 'b'); // compiles cleanly +const b = foo('a', 'b'); // also clean +const c = bar('a', 'b'); // still clean \ No newline at end of file From 27c171ecc85c0a0cfede45c50cb8b46f2080194a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 13 Mar 2018 18:45:40 -0700 Subject: [PATCH 2/7] Extract covariant inference derivation into function --- src/compiler/checker.ts | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4664d875b8031..ae9757cb07bef 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11974,6 +11974,26 @@ namespace ts { return inference.priority & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates) : getCommonSubtype(inference.contraCandidates); } + function getCovariantInference(inference: InferenceInfo, context: InferenceContext, signature: Signature) { + // Extract all object literal types and replace them with a single widened and normalized type. + const candidates = widenObjectLiteralCandidates(inference.candidates); + // We widen inferred literal types if + // all inferences were made to top-level ocurrences of the type parameter, and + // the type parameter has no constraint or its constraint includes no primitive or literal types, and + // the type parameter was fixed during inference or does not occur at top-level in the return type. + const widenLiteralTypes = inference.topLevel && + !hasPrimitiveConstraint(inference.typeParameter) && + (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); + const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; + // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if + // union types were requested or if all inferences were made from the return type position, infer a + // union type. Otherwise, infer a common supertype. + const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.PriorityImpliesCombination ? + getUnionType(baseCandidates, UnionReduction.Subtype) : + getCommonSupertype(baseCandidates); + return getWidenedType(unwidenedType); + } + function getInferredType(context: InferenceContext, index: number): Type { const inference = context.inferences[index]; let inferredType = inference.inferredType; @@ -11981,23 +12001,7 @@ namespace ts { const signature = context.signature; if (signature) { if (inference.candidates) { - // Extract all object literal types and replace them with a single widened and normalized type. - const candidates = widenObjectLiteralCandidates(inference.candidates); - // We widen inferred literal types if - // all inferences were made to top-level ocurrences of the type parameter, and - // the type parameter has no constraint or its constraint includes no primitive or literal types, and - // the type parameter was fixed during inference or does not occur at top-level in the return type. - const widenLiteralTypes = inference.topLevel && - !hasPrimitiveConstraint(inference.typeParameter) && - (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); - const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; - // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if - // union types were requested or if all inferences were made from the return type position, infer a - // union type. Otherwise, infer a common supertype. - const unwidenedType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.PriorityImpliesCombination ? - getUnionType(baseCandidates, UnionReduction.Subtype) : - getCommonSupertype(baseCandidates); - inferredType = getWidenedType(unwidenedType); + inferredType = getCovariantInference(inference, context, signature); // If we have inferred 'never' but have contravariant candidates. To get a more specific type we // infer from the contravariant candidates instead. if (inferredType.flags & TypeFlags.Never && inference.contraCandidates) { From 2938bbbee0f7ab434b54fd4f8ddda08905501de3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 14 Mar 2018 10:05:28 -0700 Subject: [PATCH 3/7] Test:keyof inference lower priority than return inference for #22376 --- .../keyofInferenceLowerPriorityThanReturn.js | 57 +++++++ ...ofInferenceLowerPriorityThanReturn.symbols | 138 +++++++++++++++++ ...eyofInferenceLowerPriorityThanReturn.types | 146 ++++++++++++++++++ .../keyofInferenceLowerPriorityThanReturn.ts | 46 ++++++ 4 files changed, 387 insertions(+) create mode 100644 tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js create mode 100644 tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols create mode 100644 tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types create mode 100644 tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js new file mode 100644 index 0000000000000..ddde947821906 --- /dev/null +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js @@ -0,0 +1,57 @@ +//// [keyofInferenceLowerPriorityThanReturn.ts] +// #22736 +declare class Write { + protected dummy: Write; +} + +declare class Col { + protected dummy: [Col, s, a]; +} + +declare class Table { + protected dummy: [Table, Req, Def]; +} + +type MakeTable = { + [P in keyof T1]: Col; +} & { + [P in keyof T2]: Col; + }; + +declare class ConflictTarget { + public static tableColumns(cols: (keyof Cols)[]): ConflictTarget; + protected dummy: [ConflictTarget, Cols]; +} + + + +const bookTable: Table = null as any + +interface BookReq { + readonly title: string; + readonly serial: number; +} + +interface BookDef { + readonly author: string; + readonly numPages: number | null; +} + + +function insertOnConflictDoNothing(_table: Table, _conflictTarget: ConflictTarget): boolean { + throw new Error(); +} + +function f() { + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here +} + + +//// [keyofInferenceLowerPriorityThanReturn.js] +var bookTable = null; +function insertOnConflictDoNothing(_table, _conflictTarget) { + throw new Error(); +} +function f() { + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here +} diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols new file mode 100644 index 0000000000000..6ee4e54cb11d6 --- /dev/null +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols @@ -0,0 +1,138 @@ +=== tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts === +// #22736 +declare class Write { +>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0)) + + protected dummy: Write; +>dummy : Symbol(Write.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 1, 21)) +>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0)) +} + +declare class Col { +>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1)) +>s : Symbol(s, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 18)) +>a : Symbol(a, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 20)) + + protected dummy: [Col, s, a]; +>dummy : Symbol(Col.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 25)) +>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1)) +>s : Symbol(s, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 18)) +>a : Symbol(a, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 20)) +>s : Symbol(s, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 18)) +>a : Symbol(a, Decl(keyofInferenceLowerPriorityThanReturn.ts, 5, 20)) +} + +declare class Table { +>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1)) +>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 20)) +>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 24)) + + protected dummy: [Table, Req, Def]; +>dummy : Symbol(Table.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 31)) +>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1)) +>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 20)) +>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 24)) +>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 20)) +>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 9, 24)) +} + +type MakeTable = { +>MakeTable : Symbol(MakeTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 11, 1)) +>T1 : Symbol(T1, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 15)) +>T2 : Symbol(T2, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 33)) + + [P in keyof T1]: Col; +>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 14, 5)) +>T1 : Symbol(T1, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 15)) +>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1)) +>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0)) +>T1 : Symbol(T1, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 15)) +>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 14, 5)) + +} & { + [P in keyof T2]: Col; +>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 16, 9)) +>T2 : Symbol(T2, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 33)) +>Col : Symbol(Col, Decl(keyofInferenceLowerPriorityThanReturn.ts, 3, 1)) +>Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0)) +>T2 : Symbol(T2, Decl(keyofInferenceLowerPriorityThanReturn.ts, 13, 33)) +>P : Symbol(P, Decl(keyofInferenceLowerPriorityThanReturn.ts, 16, 9)) + + }; + +declare class ConflictTarget { +>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6)) +>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 29)) + + public static tableColumns(cols: (keyof Cols)[]): ConflictTarget; +>tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36)) +>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 31)) +>cols : Symbol(cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 37)) +>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 31)) +>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6)) +>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 31)) + + protected dummy: [ConflictTarget, Cols]; +>dummy : Symbol(ConflictTarget.dummy, Decl(keyofInferenceLowerPriorityThanReturn.ts, 20, 81)) +>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6)) +>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 29)) +>Cols : Symbol(Cols, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 29)) +} + + + +const bookTable: Table = null as any +>bookTable : Symbol(bookTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 5)) +>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1)) +>BookReq : Symbol(BookReq, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 54)) +>BookDef : Symbol(BookDef, Decl(keyofInferenceLowerPriorityThanReturn.ts, 31, 1)) + +interface BookReq { +>BookReq : Symbol(BookReq, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 54)) + + readonly title: string; +>title : Symbol(BookReq.title, Decl(keyofInferenceLowerPriorityThanReturn.ts, 28, 19)) + + readonly serial: number; +>serial : Symbol(BookReq.serial, Decl(keyofInferenceLowerPriorityThanReturn.ts, 29, 27)) +} + +interface BookDef { +>BookDef : Symbol(BookDef, Decl(keyofInferenceLowerPriorityThanReturn.ts, 31, 1)) + + readonly author: string; +>author : Symbol(BookDef.author, Decl(keyofInferenceLowerPriorityThanReturn.ts, 33, 19)) + + readonly numPages: number | null; +>numPages : Symbol(BookDef.numPages, Decl(keyofInferenceLowerPriorityThanReturn.ts, 34, 28)) +} + + +function insertOnConflictDoNothing(_table: Table, _conflictTarget: ConflictTarget): boolean { +>insertOnConflictDoNothing : Symbol(insertOnConflictDoNothing, Decl(keyofInferenceLowerPriorityThanReturn.ts, 36, 1)) +>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 35)) +>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 54)) +>_table : Symbol(_table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 75)) +>Table : Symbol(Table, Decl(keyofInferenceLowerPriorityThanReturn.ts, 7, 1)) +>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 35)) +>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 54)) +>_conflictTarget : Symbol(_conflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 99)) +>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6)) +>Req : Symbol(Req, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 35)) +>Def : Symbol(Def, Decl(keyofInferenceLowerPriorityThanReturn.ts, 39, 54)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +} + +function f() { +>f : Symbol(f, Decl(keyofInferenceLowerPriorityThanReturn.ts, 41, 1)) + + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here +>insertOnConflictDoNothing : Symbol(insertOnConflictDoNothing, Decl(keyofInferenceLowerPriorityThanReturn.ts, 36, 1)) +>bookTable : Symbol(bookTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 5)) +>ConflictTarget.tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36)) +>ConflictTarget : Symbol(ConflictTarget, Decl(keyofInferenceLowerPriorityThanReturn.ts, 17, 6)) +>tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36)) +} + diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types new file mode 100644 index 0000000000000..ae3ba287a30df --- /dev/null +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types @@ -0,0 +1,146 @@ +=== tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts === +// #22736 +declare class Write { +>Write : Write + + protected dummy: Write; +>dummy : Write +>Write : Write +} + +declare class Col { +>Col : Col +>s : s +>a : a + + protected dummy: [Col, s, a]; +>dummy : [Col, s, a] +>Col : Col +>s : s +>a : a +>s : s +>a : a +} + +declare class Table { +>Table : Table +>Req : Req +>Def : Def + + protected dummy: [Table, Req, Def]; +>dummy : [Table, Req, Def] +>Table : Table +>Req : Req +>Def : Def +>Req : Req +>Def : Def +} + +type MakeTable = { +>MakeTable : MakeTable +>T1 : T1 +>T2 : T2 + + [P in keyof T1]: Col; +>P : P +>T1 : T1 +>Col : Col +>Write : Write +>T1 : T1 +>P : P + +} & { + [P in keyof T2]: Col; +>P : P +>T2 : T2 +>Col : Col +>Write : Write +>T2 : T2 +>P : P + + }; + +declare class ConflictTarget { +>ConflictTarget : ConflictTarget +>Cols : Cols + + public static tableColumns(cols: (keyof Cols)[]): ConflictTarget; +>tableColumns : (cols: (keyof Cols)[]) => ConflictTarget +>Cols : Cols +>cols : (keyof Cols)[] +>Cols : Cols +>ConflictTarget : ConflictTarget +>Cols : Cols + + protected dummy: [ConflictTarget, Cols]; +>dummy : [ConflictTarget, Cols] +>ConflictTarget : ConflictTarget +>Cols : Cols +>Cols : Cols +} + + + +const bookTable: Table = null as any +>bookTable : Table +>Table : Table +>BookReq : BookReq +>BookDef : BookDef +>null as any : any +>null : null + +interface BookReq { +>BookReq : BookReq + + readonly title: string; +>title : string + + readonly serial: number; +>serial : number +} + +interface BookDef { +>BookDef : BookDef + + readonly author: string; +>author : string + + readonly numPages: number | null; +>numPages : number +>null : null +} + + +function insertOnConflictDoNothing(_table: Table, _conflictTarget: ConflictTarget): boolean { +>insertOnConflictDoNothing : (_table: Table, _conflictTarget: ConflictTarget) => boolean +>Req : Req +>Def : Def +>_table : Table +>Table : Table +>Req : Req +>Def : Def +>_conflictTarget : ConflictTarget +>ConflictTarget : ConflictTarget +>Req : Req +>Def : Def + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor +} + +function f() { +>f : () => void + + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here +>insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])) : boolean +>insertOnConflictDoNothing : (_table: Table, _conflictTarget: ConflictTarget) => boolean +>bookTable : Table +>ConflictTarget.tableColumns(["serial"]) : ConflictTarget +>ConflictTarget.tableColumns : (cols: (keyof Cols)[]) => ConflictTarget +>ConflictTarget : typeof ConflictTarget +>tableColumns : (cols: (keyof Cols)[]) => ConflictTarget +>["serial"] : "serial"[] +>"serial" : "serial" +} + diff --git a/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts b/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts new file mode 100644 index 0000000000000..6c8b6edee8f0d --- /dev/null +++ b/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts @@ -0,0 +1,46 @@ +// #22736 +declare class Write { + protected dummy: Write; +} + +declare class Col { + protected dummy: [Col, s, a]; +} + +declare class Table { + protected dummy: [Table, Req, Def]; +} + +type MakeTable = { + [P in keyof T1]: Col; +} & { + [P in keyof T2]: Col; + }; + +declare class ConflictTarget { + public static tableColumns(cols: (keyof Cols)[]): ConflictTarget; + protected dummy: [ConflictTarget, Cols]; +} + + + +const bookTable: Table = null as any + +interface BookReq { + readonly title: string; + readonly serial: number; +} + +interface BookDef { + readonly author: string; + readonly numPages: number | null; +} + + +function insertOnConflictDoNothing(_table: Table, _conflictTarget: ConflictTarget): boolean { + throw new Error(); +} + +function f() { + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here +} From 4fd8bf3951b27dd302a88736e7fd3af4d6996043 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 14 Mar 2018 10:12:21 -0700 Subject: [PATCH 4/7] Update 'expected' comment in keyofInferenceLowerPriorityThanReturn --- .../reference/keyofInferenceLowerPriorityThanReturn.js | 4 ++-- .../reference/keyofInferenceLowerPriorityThanReturn.symbols | 2 +- .../reference/keyofInferenceLowerPriorityThanReturn.types | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js index ddde947821906..581e01729d9d7 100644 --- a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.js @@ -43,7 +43,7 @@ function insertOnConflictDoNothing(_tabl } function f() { - insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns` } @@ -53,5 +53,5 @@ function insertOnConflictDoNothing(_table, _conflictTarget) { throw new Error(); } function f() { - insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns` } diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols index 6ee4e54cb11d6..ecd8b1fbf8824 100644 --- a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols @@ -128,7 +128,7 @@ function insertOnConflictDoNothing(_tabl function f() { >f : Symbol(f, Decl(keyofInferenceLowerPriorityThanReturn.ts, 41, 1)) - insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns` >insertOnConflictDoNothing : Symbol(insertOnConflictDoNothing, Decl(keyofInferenceLowerPriorityThanReturn.ts, 36, 1)) >bookTable : Symbol(bookTable, Decl(keyofInferenceLowerPriorityThanReturn.ts, 26, 5)) >ConflictTarget.tableColumns : Symbol(ConflictTarget.tableColumns, Decl(keyofInferenceLowerPriorityThanReturn.ts, 19, 36)) diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types index ae3ba287a30df..3aa4dc42b8bb0 100644 --- a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types @@ -132,7 +132,7 @@ function insertOnConflictDoNothing(_tabl function f() { >f : () => void - insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns` >insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])) : boolean >insertOnConflictDoNothing : (_table: Table, _conflictTarget: ConflictTarget) => boolean >bookTable : Table From c6c41d351be8ea8d614bb7d35ce8f42a8fe36b6b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 14 Mar 2018 10:15:04 -0700 Subject: [PATCH 5/7] Update comment in test too, not just baselines --- tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts b/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts index 6c8b6edee8f0d..9de110bd1e95e 100644 --- a/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts +++ b/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts @@ -42,5 +42,5 @@ function insertOnConflictDoNothing(_tabl } function f() { - insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- Compile error here + insertOnConflictDoNothing(bookTable, ConflictTarget.tableColumns(["serial"])); // <-- No error here; should use the type inferred for the return type of `tableColumns` } From 515439a981f16017a19a9ba3a0b55efc65f432c9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 14 Mar 2018 10:56:55 -0700 Subject: [PATCH 6/7] Fix typo --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ae9757cb07bef..aded1fcbbba6f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11978,7 +11978,7 @@ namespace ts { // Extract all object literal types and replace them with a single widened and normalized type. const candidates = widenObjectLiteralCandidates(inference.candidates); // We widen inferred literal types if - // all inferences were made to top-level ocurrences of the type parameter, and + // all inferences were made to top-level occurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. const widenLiteralTypes = inference.topLevel && From acde7070573fa37621de6b2f0523694fcc5f7b5d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 14 Mar 2018 11:19:29 -0700 Subject: [PATCH 7/7] Move tests --- .../baselines/reference/keyofInferenceIntersectsResults.symbols | 2 +- tests/baselines/reference/keyofInferenceIntersectsResults.types | 2 +- .../reference/keyofInferenceLowerPriorityThanReturn.symbols | 2 +- .../reference/keyofInferenceLowerPriorityThanReturn.types | 2 +- .../typeInference}/keyofInferenceIntersectsResults.ts | 0 .../typeInference}/keyofInferenceLowerPriorityThanReturn.ts | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename tests/cases/{compiler => conformance/types/typeRelationships/typeInference}/keyofInferenceIntersectsResults.ts (100%) rename tests/cases/{compiler => conformance/types/typeRelationships/typeInference}/keyofInferenceLowerPriorityThanReturn.ts (100%) diff --git a/tests/baselines/reference/keyofInferenceIntersectsResults.symbols b/tests/baselines/reference/keyofInferenceIntersectsResults.symbols index ccdad6bb3acbe..88340b821d2a8 100644 --- a/tests/baselines/reference/keyofInferenceIntersectsResults.symbols +++ b/tests/baselines/reference/keyofInferenceIntersectsResults.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/keyofInferenceIntersectsResults.ts === +=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceIntersectsResults.ts === interface X { >X : Symbol(X, Decl(keyofInferenceIntersectsResults.ts, 0, 0)) diff --git a/tests/baselines/reference/keyofInferenceIntersectsResults.types b/tests/baselines/reference/keyofInferenceIntersectsResults.types index 42099caf4bd8e..ff7c3da19a685 100644 --- a/tests/baselines/reference/keyofInferenceIntersectsResults.types +++ b/tests/baselines/reference/keyofInferenceIntersectsResults.types @@ -1,4 +1,4 @@ -=== tests/cases/compiler/keyofInferenceIntersectsResults.ts === +=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceIntersectsResults.ts === interface X { >X : X diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols index ecd8b1fbf8824..c4c6b0c3cc33c 100644 --- a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts === +=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceLowerPriorityThanReturn.ts === // #22736 declare class Write { >Write : Symbol(Write, Decl(keyofInferenceLowerPriorityThanReturn.ts, 0, 0)) diff --git a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types index 3aa4dc42b8bb0..cf0c3cb6a319b 100644 --- a/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types +++ b/tests/baselines/reference/keyofInferenceLowerPriorityThanReturn.types @@ -1,4 +1,4 @@ -=== tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts === +=== tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceLowerPriorityThanReturn.ts === // #22736 declare class Write { >Write : Write diff --git a/tests/cases/compiler/keyofInferenceIntersectsResults.ts b/tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceIntersectsResults.ts similarity index 100% rename from tests/cases/compiler/keyofInferenceIntersectsResults.ts rename to tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceIntersectsResults.ts diff --git a/tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts b/tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceLowerPriorityThanReturn.ts similarity index 100% rename from tests/cases/compiler/keyofInferenceLowerPriorityThanReturn.ts rename to tests/cases/conformance/types/typeRelationships/typeInference/keyofInferenceLowerPriorityThanReturn.ts