diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e3f4644b0b..ae597684d0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14250,6 +14250,14 @@ namespace ts { return getObjectFlags(source) & ObjectFlags.JsxAttributes && !isUnhyphenatedJsxName(sourceProp.escapedName); } + function getNormalizedType(type: Type, writing: boolean): Type { + return isFreshLiteralType(type) ? (type).regularType : + getObjectFlags(type) & ObjectFlags.Reference && (type).node ? createTypeReference((type).target, getTypeArguments(type)) : + type.flags & TypeFlags.Substitution ? writing ? (type).typeVariable : (type).substitute : + type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : + type; + } + /** * Checks if 'source' is related to 'target' (e.g.: is a assignable to). * @param source The left-hand-side of the relation. @@ -14555,25 +14563,13 @@ namespace ts { * * Ternary.Maybe if they are related with assumptions of other relationships, or * * Ternary.False if they are not related. */ - function isRelatedTo(source: Type, target: Type, reportErrors = false, headMessage?: DiagnosticMessage, isApparentIntersectionConstituent?: boolean): Ternary { - if (isFreshLiteralType(source)) { - source = (source).regularType; - } - if (isFreshLiteralType(target)) { - target = (target).regularType; - } - if (source.flags & TypeFlags.Substitution) { - source = (source).substitute; - } - if (target.flags & TypeFlags.Substitution) { - target = (target).typeVariable; - } - if (source.flags & TypeFlags.Simplifiable) { - source = getSimplifiedType(source, /*writing*/ false); - } - if (target.flags & TypeFlags.Simplifiable) { - target = getSimplifiedType(target, /*writing*/ true); - } + function isRelatedTo(originalSource: Type, originalTarget: Type, reportErrors = false, headMessage?: DiagnosticMessage, isApparentIntersectionConstituent?: boolean): Ternary { + // Normalize the source and target types: Turn fresh literal types into regular literal types, + // turn deferred type references into regular type references, simplify indexed access and + // conditional types, and resolve substitution types to either the substitution (on the source + // side) or the type variable (on the target side). + let source = getNormalizedType(originalSource, /*writing*/ false); + let target = getNormalizedType(originalTarget, /*writing*/ true); // Try to see if we're relating something like `Foo` -> `Bar | null | undefined`. // If so, reporting the `null` and `undefined` in the type is hardly useful. @@ -14706,6 +14702,8 @@ namespace ts { } if (!result && reportErrors) { + source = originalSource.aliasSymbol ? originalSource : source; + target = originalTarget.aliasSymbol ? originalTarget : target; let maybeSuppress = overrideNextErrorInfo > 0; if (maybeSuppress) { overrideNextErrorInfo--; diff --git a/tests/baselines/reference/unwitnessedTypeParameterVariance.js b/tests/baselines/reference/unwitnessedTypeParameterVariance.js new file mode 100644 index 0000000000..b5e4e10663 --- /dev/null +++ b/tests/baselines/reference/unwitnessedTypeParameterVariance.js @@ -0,0 +1,35 @@ +//// [unwitnessedTypeParameterVariance.ts] +// Repros from #33872 + +export interface CalcObj { + read: (origin: O) => CalcValue; +} + +export type CalcValue = CalcObj; + +function foo() { + const unk: CalcObj = { read: (origin: unknown) => unk } + const x: CalcObj = unk; +} + +type A = B; + +interface B { + prop: A; +} + +declare let a: A; +declare let b: A<3>; + +b = a; + + +//// [unwitnessedTypeParameterVariance.js] +"use strict"; +// Repros from #33872 +exports.__esModule = true; +function foo() { + var unk = { read: function (origin) { return unk; } }; + var x = unk; +} +b = a; diff --git a/tests/baselines/reference/unwitnessedTypeParameterVariance.symbols b/tests/baselines/reference/unwitnessedTypeParameterVariance.symbols new file mode 100644 index 0000000000..d63b2f1924 --- /dev/null +++ b/tests/baselines/reference/unwitnessedTypeParameterVariance.symbols @@ -0,0 +1,67 @@ +=== tests/cases/compiler/unwitnessedTypeParameterVariance.ts === +// Repros from #33872 + +export interface CalcObj { +>CalcObj : Symbol(CalcObj, Decl(unwitnessedTypeParameterVariance.ts, 0, 0)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 2, 25)) + + read: (origin: O) => CalcValue; +>read : Symbol(CalcObj.read, Decl(unwitnessedTypeParameterVariance.ts, 2, 29)) +>origin : Symbol(origin, Decl(unwitnessedTypeParameterVariance.ts, 3, 11)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 2, 25)) +>CalcValue : Symbol(CalcValue, Decl(unwitnessedTypeParameterVariance.ts, 4, 1)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 2, 25)) +} + +export type CalcValue = CalcObj; +>CalcValue : Symbol(CalcValue, Decl(unwitnessedTypeParameterVariance.ts, 4, 1)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 6, 22)) +>CalcObj : Symbol(CalcObj, Decl(unwitnessedTypeParameterVariance.ts, 0, 0)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 6, 22)) + +function foo() { +>foo : Symbol(foo, Decl(unwitnessedTypeParameterVariance.ts, 6, 38)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 8, 13)) + + const unk: CalcObj = { read: (origin: unknown) => unk } +>unk : Symbol(unk, Decl(unwitnessedTypeParameterVariance.ts, 9, 9)) +>CalcObj : Symbol(CalcObj, Decl(unwitnessedTypeParameterVariance.ts, 0, 0)) +>read : Symbol(read, Decl(unwitnessedTypeParameterVariance.ts, 9, 35)) +>origin : Symbol(origin, Decl(unwitnessedTypeParameterVariance.ts, 9, 43)) +>unk : Symbol(unk, Decl(unwitnessedTypeParameterVariance.ts, 9, 9)) + + const x: CalcObj = unk; +>x : Symbol(x, Decl(unwitnessedTypeParameterVariance.ts, 10, 9)) +>CalcObj : Symbol(CalcObj, Decl(unwitnessedTypeParameterVariance.ts, 0, 0)) +>O : Symbol(O, Decl(unwitnessedTypeParameterVariance.ts, 8, 13)) +>unk : Symbol(unk, Decl(unwitnessedTypeParameterVariance.ts, 9, 9)) +} + +type A = B; +>A : Symbol(A, Decl(unwitnessedTypeParameterVariance.ts, 11, 1)) +>T : Symbol(T, Decl(unwitnessedTypeParameterVariance.ts, 13, 7)) +>B : Symbol(B, Decl(unwitnessedTypeParameterVariance.ts, 13, 17)) +>T : Symbol(T, Decl(unwitnessedTypeParameterVariance.ts, 13, 7)) + +interface B { +>B : Symbol(B, Decl(unwitnessedTypeParameterVariance.ts, 13, 17)) +>T : Symbol(T, Decl(unwitnessedTypeParameterVariance.ts, 15, 12)) + + prop: A; +>prop : Symbol(B.prop, Decl(unwitnessedTypeParameterVariance.ts, 15, 16)) +>A : Symbol(A, Decl(unwitnessedTypeParameterVariance.ts, 11, 1)) +>T : Symbol(T, Decl(unwitnessedTypeParameterVariance.ts, 15, 12)) +} + +declare let a: A; +>a : Symbol(a, Decl(unwitnessedTypeParameterVariance.ts, 19, 11)) +>A : Symbol(A, Decl(unwitnessedTypeParameterVariance.ts, 11, 1)) + +declare let b: A<3>; +>b : Symbol(b, Decl(unwitnessedTypeParameterVariance.ts, 20, 11)) +>A : Symbol(A, Decl(unwitnessedTypeParameterVariance.ts, 11, 1)) + +b = a; +>b : Symbol(b, Decl(unwitnessedTypeParameterVariance.ts, 20, 11)) +>a : Symbol(a, Decl(unwitnessedTypeParameterVariance.ts, 19, 11)) + diff --git a/tests/baselines/reference/unwitnessedTypeParameterVariance.types b/tests/baselines/reference/unwitnessedTypeParameterVariance.types new file mode 100644 index 0000000000..4eb72cee07 --- /dev/null +++ b/tests/baselines/reference/unwitnessedTypeParameterVariance.types @@ -0,0 +1,47 @@ +=== tests/cases/compiler/unwitnessedTypeParameterVariance.ts === +// Repros from #33872 + +export interface CalcObj { + read: (origin: O) => CalcValue; +>read : (origin: O) => CalcValue +>origin : O +} + +export type CalcValue = CalcObj; +>CalcValue : CalcValue + +function foo() { +>foo : () => void + + const unk: CalcObj = { read: (origin: unknown) => unk } +>unk : CalcObj +>{ read: (origin: unknown) => unk } : { read: (origin: unknown) => CalcObj; } +>read : (origin: unknown) => CalcObj +>(origin: unknown) => unk : (origin: unknown) => CalcObj +>origin : unknown +>unk : CalcObj + + const x: CalcObj = unk; +>x : CalcObj +>unk : CalcObj +} + +type A = B; +>A : A + +interface B { + prop: A; +>prop : A +} + +declare let a: A; +>a : A + +declare let b: A<3>; +>b : A<3> + +b = a; +>b = a : A +>b : A<3> +>a : A + diff --git a/tests/cases/compiler/unwitnessedTypeParameterVariance.ts b/tests/cases/compiler/unwitnessedTypeParameterVariance.ts new file mode 100644 index 0000000000..0be2accdc3 --- /dev/null +++ b/tests/cases/compiler/unwitnessedTypeParameterVariance.ts @@ -0,0 +1,25 @@ +// @strict: true + +// Repros from #33872 + +export interface CalcObj { + read: (origin: O) => CalcValue; +} + +export type CalcValue = CalcObj; + +function foo() { + const unk: CalcObj = { read: (origin: unknown) => unk } + const x: CalcObj = unk; +} + +type A = B; + +interface B { + prop: A; +} + +declare let a: A; +declare let b: A<3>; + +b = a;