diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4a5a85db1398b..c15a0ad2e5e82 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13284,13 +13284,18 @@ namespace ts { return result & ObjectFlags.PropagatingFlags; } + function containsMarkerType(typeArguments: readonly Type[] | undefined) { + return some(typeArguments, t => t === markerSuperType || t === markerSubType || t === markerOtherType); + } + function createTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined): TypeReference { const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { type = createObjectType(ObjectFlags.Reference, target.symbol) as TypeReference; target.instantiations.set(id, type); - type.objectFlags |= typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0; + type.objectFlags |= (typeArguments ? getPropagatingFlagsOfTypes(typeArguments, /*excludeKinds*/ 0) : 0) | + (containsMarkerType(typeArguments) ? ObjectFlags.MarkerType : 0); type.target = target; type.resolvedTypeArguments = typeArguments; } @@ -17945,7 +17950,9 @@ namespace ts { if (source.flags !== target.flags) return false; if (source.flags & TypeFlags.Singleton) return true; } - if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { + // We skip the cache lookup shortcut when we're in a variance computation so the outofbandVarianceMarkerHandler + // will get called for cached results that are unreliable or unmeasurable. + if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object && !outofbandVarianceMarkerHandler) { const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false)); if (related !== undefined) { return !!(related & RelationComparisonResult.Succeeded); @@ -19051,7 +19058,7 @@ namespace ts { // the order in which things were checked. if (sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol && - !(source.aliasTypeArgumentsContainsMarker || target.aliasTypeArgumentsContainsMarker)) { + !(containsMarkerType(source.aliasTypeArguments) || containsMarkerType(target.aliasTypeArguments))) { const variances = getAliasVariances(source.aliasSymbol); if (variances === emptyArray) { return Ternary.Unknown; @@ -20369,18 +20376,14 @@ namespace ts { // Return a type reference where the source type parameter is replaced with the target marker // type, and flag the result as a marker type reference. function getMarkerTypeReference(type: GenericType, source: TypeParameter, target: Type) { - const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t)); - result.objectFlags |= ObjectFlags.MarkerType; - return result; + return createTypeReference(type, map(type.typeParameters, t => t === source ? target : t)); } function getAliasVariances(symbol: Symbol) { const links = getSymbolLinks(symbol); - return getVariancesWorker(links.typeParameters, links, (_links, param, marker) => { - const type = getTypeAliasInstantiation(symbol, instantiateTypes(links.typeParameters!, makeUnaryTypeMapper(param, marker))); - type.aliasTypeArgumentsContainsMarker = true; - return type; - }); + return getVariancesWorker(links.typeParameters, links, (_links, param, marker) => + getTypeAliasInstantiation(symbol, instantiateTypes(links.typeParameters!, makeUnaryTypeMapper(param, marker))) + ); } // Return an array containing the variance of each type parameter. The variance is effectively diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 54936e787bc7a..9c4b2cf7f5105 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5227,7 +5227,6 @@ namespace ts { pattern?: DestructuringPattern; // Destructuring pattern represented by type (if any) aliasSymbol?: Symbol; // Alias associated with type aliasTypeArguments?: readonly Type[]; // Alias type arguments (if any) - /* @internal */ aliasTypeArgumentsContainsMarker?: boolean; // Alias type arguments (if any) /* @internal */ permissiveInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type /* @internal */ diff --git a/tests/baselines/reference/checkOrderDependenceGenericAssignability.errors.txt b/tests/baselines/reference/checkOrderDependenceGenericAssignability.errors.txt new file mode 100644 index 0000000000000..edf0961515262 --- /dev/null +++ b/tests/baselines/reference/checkOrderDependenceGenericAssignability.errors.txt @@ -0,0 +1,65 @@ +tests/cases/compiler/checkOrderDependenceGenericAssignability.ts(24,1): error TS2322: Type 'Parent1' is not assignable to type 'Parent1'. + Type 'unknown' is not assignable to type 'string'. +tests/cases/compiler/checkOrderDependenceGenericAssignability.ts(51,1): error TS2322: Type 'Parent2' is not assignable to type 'Parent2'. + Type 'unknown' is not assignable to type 'string'. + + +==== tests/cases/compiler/checkOrderDependenceGenericAssignability.ts (2 errors) ==== + // Repro from #44572 with interface types + + interface Parent1 { + child: Child1; + parent: Parent1; + } + + interface Child1 extends Parent1 { + readonly a: A; + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; + } + + function fn1(inp: Child1) { + // This assignability check defeats the later one + const a: Child1 = inp; + } + + declare let pu1: Parent1; + declare let ps1: Parent1; + + pu1 = ps1; // Ok + ps1 = pu1; // Error expected + ~~~ +!!! error TS2322: Type 'Parent1' is not assignable to type 'Parent1'. +!!! error TS2322: Type 'unknown' is not assignable to type 'string'. + + // Repro from #44572 with aliased object types + + type Parent2 = { + child: Child2; + parent: Parent2; + } + + type Child2 = { + child: Child2; + parent: Parent2; + readonly a: A; + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; + } + + function fn2(inp: Child2) { + // This assignability check defeats the later one + const a: Child2 = inp; + } + + declare let pu2: Parent2; + declare let ps2: Parent2; + + pu2 = ps2; // Ok + ps2 = pu2; // Error expected + ~~~ +!!! error TS2322: Type 'Parent2' is not assignable to type 'Parent2'. +!!! error TS2322: Type 'unknown' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/checkOrderDependenceGenericAssignability.js b/tests/baselines/reference/checkOrderDependenceGenericAssignability.js new file mode 100644 index 0000000000000..3e88b08098bb1 --- /dev/null +++ b/tests/baselines/reference/checkOrderDependenceGenericAssignability.js @@ -0,0 +1,69 @@ +//// [checkOrderDependenceGenericAssignability.ts] +// Repro from #44572 with interface types + +interface Parent1 { + child: Child1; + parent: Parent1; +} + +interface Child1 extends Parent1 { + readonly a: A; + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +} + +function fn1(inp: Child1) { + // This assignability check defeats the later one + const a: Child1 = inp; +} + +declare let pu1: Parent1; +declare let ps1: Parent1; + +pu1 = ps1; // Ok +ps1 = pu1; // Error expected + +// Repro from #44572 with aliased object types + +type Parent2 = { + child: Child2; + parent: Parent2; +} + +type Child2 = { + child: Child2; + parent: Parent2; + readonly a: A; + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +} + +function fn2(inp: Child2) { + // This assignability check defeats the later one + const a: Child2 = inp; +} + +declare let pu2: Parent2; +declare let ps2: Parent2; + +pu2 = ps2; // Ok +ps2 = pu2; // Error expected + + +//// [checkOrderDependenceGenericAssignability.js] +"use strict"; +// Repro from #44572 with interface types +function fn1(inp) { + // This assignability check defeats the later one + var a = inp; +} +pu1 = ps1; // Ok +ps1 = pu1; // Error expected +function fn2(inp) { + // This assignability check defeats the later one + var a = inp; +} +pu2 = ps2; // Ok +ps2 = pu2; // Error expected diff --git a/tests/baselines/reference/checkOrderDependenceGenericAssignability.symbols b/tests/baselines/reference/checkOrderDependenceGenericAssignability.symbols new file mode 100644 index 0000000000000..aeaa39264c773 --- /dev/null +++ b/tests/baselines/reference/checkOrderDependenceGenericAssignability.symbols @@ -0,0 +1,139 @@ +=== tests/cases/compiler/checkOrderDependenceGenericAssignability.ts === +// Repro from #44572 with interface types + +interface Parent1 { +>Parent1 : Symbol(Parent1, Decl(checkOrderDependenceGenericAssignability.ts, 0, 0)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 2, 18)) + + child: Child1; +>child : Symbol(Parent1.child, Decl(checkOrderDependenceGenericAssignability.ts, 2, 22)) +>Child1 : Symbol(Child1, Decl(checkOrderDependenceGenericAssignability.ts, 5, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 2, 18)) + + parent: Parent1; +>parent : Symbol(Parent1.parent, Decl(checkOrderDependenceGenericAssignability.ts, 3, 21)) +>Parent1 : Symbol(Parent1, Decl(checkOrderDependenceGenericAssignability.ts, 0, 0)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 2, 18)) +} + +interface Child1 extends Parent1 { +>Child1 : Symbol(Child1, Decl(checkOrderDependenceGenericAssignability.ts, 5, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 7, 17)) +>B : Symbol(B, Decl(checkOrderDependenceGenericAssignability.ts, 7, 19)) +>Parent1 : Symbol(Parent1, Decl(checkOrderDependenceGenericAssignability.ts, 0, 0)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 7, 17)) + + readonly a: A; +>a : Symbol(Child1.a, Decl(checkOrderDependenceGenericAssignability.ts, 7, 53)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 7, 17)) + + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +>b : Symbol(Child1.b, Decl(checkOrderDependenceGenericAssignability.ts, 8, 18)) +>B : Symbol(B, Decl(checkOrderDependenceGenericAssignability.ts, 7, 19)) +} + +function fn1(inp: Child1) { +>fn1 : Symbol(fn1, Decl(checkOrderDependenceGenericAssignability.ts, 12, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 14, 13)) +>inp : Symbol(inp, Decl(checkOrderDependenceGenericAssignability.ts, 14, 16)) +>Child1 : Symbol(Child1, Decl(checkOrderDependenceGenericAssignability.ts, 5, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 14, 13)) + + // This assignability check defeats the later one + const a: Child1 = inp; +>a : Symbol(a, Decl(checkOrderDependenceGenericAssignability.ts, 16, 9)) +>Child1 : Symbol(Child1, Decl(checkOrderDependenceGenericAssignability.ts, 5, 1)) +>inp : Symbol(inp, Decl(checkOrderDependenceGenericAssignability.ts, 14, 16)) +} + +declare let pu1: Parent1; +>pu1 : Symbol(pu1, Decl(checkOrderDependenceGenericAssignability.ts, 19, 11)) +>Parent1 : Symbol(Parent1, Decl(checkOrderDependenceGenericAssignability.ts, 0, 0)) + +declare let ps1: Parent1; +>ps1 : Symbol(ps1, Decl(checkOrderDependenceGenericAssignability.ts, 20, 11)) +>Parent1 : Symbol(Parent1, Decl(checkOrderDependenceGenericAssignability.ts, 0, 0)) + +pu1 = ps1; // Ok +>pu1 : Symbol(pu1, Decl(checkOrderDependenceGenericAssignability.ts, 19, 11)) +>ps1 : Symbol(ps1, Decl(checkOrderDependenceGenericAssignability.ts, 20, 11)) + +ps1 = pu1; // Error expected +>ps1 : Symbol(ps1, Decl(checkOrderDependenceGenericAssignability.ts, 20, 11)) +>pu1 : Symbol(pu1, Decl(checkOrderDependenceGenericAssignability.ts, 19, 11)) + +// Repro from #44572 with aliased object types + +type Parent2 = { +>Parent2 : Symbol(Parent2, Decl(checkOrderDependenceGenericAssignability.ts, 23, 10)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 27, 13)) + + child: Child2; +>child : Symbol(child, Decl(checkOrderDependenceGenericAssignability.ts, 27, 19)) +>Child2 : Symbol(Child2, Decl(checkOrderDependenceGenericAssignability.ts, 30, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 27, 13)) + + parent: Parent2; +>parent : Symbol(parent, Decl(checkOrderDependenceGenericAssignability.ts, 28, 21)) +>Parent2 : Symbol(Parent2, Decl(checkOrderDependenceGenericAssignability.ts, 23, 10)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 27, 13)) +} + +type Child2 = { +>Child2 : Symbol(Child2, Decl(checkOrderDependenceGenericAssignability.ts, 30, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 32, 12)) +>B : Symbol(B, Decl(checkOrderDependenceGenericAssignability.ts, 32, 14)) + + child: Child2; +>child : Symbol(child, Decl(checkOrderDependenceGenericAssignability.ts, 32, 31)) +>Child2 : Symbol(Child2, Decl(checkOrderDependenceGenericAssignability.ts, 30, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 32, 12)) + + parent: Parent2; +>parent : Symbol(parent, Decl(checkOrderDependenceGenericAssignability.ts, 33, 21)) +>Parent2 : Symbol(Parent2, Decl(checkOrderDependenceGenericAssignability.ts, 23, 10)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 32, 12)) + + readonly a: A; +>a : Symbol(a, Decl(checkOrderDependenceGenericAssignability.ts, 34, 23)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 32, 12)) + + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +>b : Symbol(b, Decl(checkOrderDependenceGenericAssignability.ts, 35, 18)) +>B : Symbol(B, Decl(checkOrderDependenceGenericAssignability.ts, 32, 14)) +} + +function fn2(inp: Child2) { +>fn2 : Symbol(fn2, Decl(checkOrderDependenceGenericAssignability.ts, 39, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 41, 13)) +>inp : Symbol(inp, Decl(checkOrderDependenceGenericAssignability.ts, 41, 16)) +>Child2 : Symbol(Child2, Decl(checkOrderDependenceGenericAssignability.ts, 30, 1)) +>A : Symbol(A, Decl(checkOrderDependenceGenericAssignability.ts, 41, 13)) + + // This assignability check defeats the later one + const a: Child2 = inp; +>a : Symbol(a, Decl(checkOrderDependenceGenericAssignability.ts, 43, 9)) +>Child2 : Symbol(Child2, Decl(checkOrderDependenceGenericAssignability.ts, 30, 1)) +>inp : Symbol(inp, Decl(checkOrderDependenceGenericAssignability.ts, 41, 16)) +} + +declare let pu2: Parent2; +>pu2 : Symbol(pu2, Decl(checkOrderDependenceGenericAssignability.ts, 46, 11)) +>Parent2 : Symbol(Parent2, Decl(checkOrderDependenceGenericAssignability.ts, 23, 10)) + +declare let ps2: Parent2; +>ps2 : Symbol(ps2, Decl(checkOrderDependenceGenericAssignability.ts, 47, 11)) +>Parent2 : Symbol(Parent2, Decl(checkOrderDependenceGenericAssignability.ts, 23, 10)) + +pu2 = ps2; // Ok +>pu2 : Symbol(pu2, Decl(checkOrderDependenceGenericAssignability.ts, 46, 11)) +>ps2 : Symbol(ps2, Decl(checkOrderDependenceGenericAssignability.ts, 47, 11)) + +ps2 = pu2; // Error expected +>ps2 : Symbol(ps2, Decl(checkOrderDependenceGenericAssignability.ts, 47, 11)) +>pu2 : Symbol(pu2, Decl(checkOrderDependenceGenericAssignability.ts, 46, 11)) + diff --git a/tests/baselines/reference/checkOrderDependenceGenericAssignability.types b/tests/baselines/reference/checkOrderDependenceGenericAssignability.types new file mode 100644 index 0000000000000..29bd7a004ae0c --- /dev/null +++ b/tests/baselines/reference/checkOrderDependenceGenericAssignability.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/checkOrderDependenceGenericAssignability.ts === +// Repro from #44572 with interface types + +interface Parent1 { + child: Child1; +>child : Child1 + + parent: Parent1; +>parent : Parent1 +} + +interface Child1 extends Parent1 { + readonly a: A; +>a : A + + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +>b : B +} + +function fn1(inp: Child1) { +>fn1 : (inp: Child1) => void +>inp : Child1 + + // This assignability check defeats the later one + const a: Child1 = inp; +>a : Child1 +>inp : Child1 +} + +declare let pu1: Parent1; +>pu1 : Parent1 + +declare let ps1: Parent1; +>ps1 : Parent1 + +pu1 = ps1; // Ok +>pu1 = ps1 : Parent1 +>pu1 : Parent1 +>ps1 : Parent1 + +ps1 = pu1; // Error expected +>ps1 = pu1 : Parent1 +>ps1 : Parent1 +>pu1 : Parent1 + +// Repro from #44572 with aliased object types + +type Parent2 = { +>Parent2 : Parent2 + + child: Child2; +>child : Child2 + + parent: Parent2; +>parent : Parent2 +} + +type Child2 = { +>Child2 : Child2 + + child: Child2; +>child : Child2 + + parent: Parent2; +>parent : Parent2 + + readonly a: A; +>a : A + + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +>b : B +} + +function fn2(inp: Child2) { +>fn2 : (inp: Child2) => void +>inp : Child2 + + // This assignability check defeats the later one + const a: Child2 = inp; +>a : Child2 +>inp : Child2 +} + +declare let pu2: Parent2; +>pu2 : Parent2 + +declare let ps2: Parent2; +>ps2 : Parent2 + +pu2 = ps2; // Ok +>pu2 = ps2 : Parent2 +>pu2 : Parent2 +>ps2 : Parent2 + +ps2 = pu2; // Error expected +>ps2 = pu2 : Parent2 +>ps2 : Parent2 +>pu2 : Parent2 + diff --git a/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt b/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt index 8933563702677..97aaa56294068 100644 --- a/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt +++ b/tests/baselines/reference/flatArrayNoExcessiveStackDepth.errors.txt @@ -5,7 +5,7 @@ tests/cases/compiler/flatArrayNoExcessiveStackDepth.ts(20,5): error TS2322: Type Type 'unknown' is not assignable to type 'Arr extends readonly (infer InnerArr)[] ? FlatArray : Arr'. Type 'FlatArray' is not assignable to type 'FlatArray'. Type 'InnerArr' is not assignable to type 'FlatArray'. - Type 'InnerArr' is not assignable to type '(InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr) & InnerArr'. + Type 'InnerArr' is not assignable to type 'InnerArr & (InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr)'. Type 'InnerArr' is not assignable to type 'InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr'. @@ -38,7 +38,7 @@ tests/cases/compiler/flatArrayNoExcessiveStackDepth.ts(20,5): error TS2322: Type !!! error TS2322: Type 'unknown' is not assignable to type 'Arr extends readonly (infer InnerArr)[] ? FlatArray : Arr'. !!! error TS2322: Type 'FlatArray' is not assignable to type 'FlatArray'. !!! error TS2322: Type 'InnerArr' is not assignable to type 'FlatArray'. -!!! error TS2322: Type 'InnerArr' is not assignable to type '(InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr) & InnerArr'. +!!! error TS2322: Type 'InnerArr' is not assignable to type 'InnerArr & (InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr)'. !!! error TS2322: Type 'InnerArr' is not assignable to type 'InnerArr extends readonly (infer InnerArr)[] ? FlatArray : InnerArr'. } \ No newline at end of file diff --git a/tests/cases/compiler/checkOrderDependenceGenericAssignability.ts b/tests/cases/compiler/checkOrderDependenceGenericAssignability.ts new file mode 100644 index 0000000000000..4445165a79d73 --- /dev/null +++ b/tests/cases/compiler/checkOrderDependenceGenericAssignability.ts @@ -0,0 +1,53 @@ +// @strict: true + +// Repro from #44572 with interface types + +interface Parent1 { + child: Child1; + parent: Parent1; +} + +interface Child1 extends Parent1 { + readonly a: A; + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +} + +function fn1(inp: Child1) { + // This assignability check defeats the later one + const a: Child1 = inp; +} + +declare let pu1: Parent1; +declare let ps1: Parent1; + +pu1 = ps1; // Ok +ps1 = pu1; // Error expected + +// Repro from #44572 with aliased object types + +type Parent2 = { + child: Child2; + parent: Parent2; +} + +type Child2 = { + child: Child2; + parent: Parent2; + readonly a: A; + // This field isn't necessary to the repro, but the + // type parameter is, so including it + readonly b: B; +} + +function fn2(inp: Child2) { + // This assignability check defeats the later one + const a: Child2 = inp; +} + +declare let pu2: Parent2; +declare let ps2: Parent2; + +pu2 = ps2; // Ok +ps2 = pu2; // Error expected