From fda479e1df5d1508c56e34b17c7f39c39eb4eda9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 29 Apr 2021 13:03:31 -0700 Subject: [PATCH] Mark conditional extends as Unmeasurable and use a conditional-opaque wildcard for type erasure --- src/compiler/checker.ts | 41 ++++--- src/compiler/types.ts | 2 + .../complexRecursiveCollections.types | 2 +- ...sSomehowNeverChecksConditionals.errors.txt | 78 +++++++++++++ ...mptyClassSomehowNeverChecksConditionals.js | 30 +++++ ...lassSomehowNeverChecksConditionals.symbols | 89 +++++++++++++++ ...yClassSomehowNeverChecksConditionals.types | 63 +++++++++++ ...signabilityChecksAllowGenericAssignment.js | 9 ++ ...bilityChecksAllowGenericAssignment.symbols | 28 +++++ ...nabilityChecksAllowGenericAssignment.types | 22 ++++ .../subtypingWithCallSignatures2.types | 8 +- .../subtypingWithCallSignatures3.types | 4 +- .../subtypingWithConstructSignatures2.types | 8 +- .../subtypingWithConstructSignatures3.types | 4 +- tests/baselines/reference/variance.js | 53 ++++++++- tests/baselines/reference/variance.symbols | 104 ++++++++++++++++++ tests/baselines/reference/variance.types | 93 ++++++++++++++++ ...mptyClassSomehowNeverChecksConditionals.ts | 23 ++++ ...signabilityChecksAllowGenericAssignment.ts | 5 + .../conformance/types/conditional/variance.ts | 35 ++++++ 20 files changed, 674 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.errors.txt create mode 100644 tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.js create mode 100644 tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.symbols create mode 100644 tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.types create mode 100644 tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.js create mode 100644 tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.symbols create mode 100644 tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.types create mode 100644 tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts create mode 100644 tests/cases/compiler/overloadAssignabilityChecksAllowGenericAssignment.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 47cc9c27b886b..2c7d8963a6a3d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -735,9 +735,12 @@ namespace ts { const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String); const resolvingSymbol = createSymbol(0, InternalSymbolName.Resolving); + // note: wildcards must be first types constructed due to an assumption made during union construction + // if you reorder these, you must adjust that, too! + const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); + const opaqueWildcardType = createIntrinsicType(TypeFlags.Any, "any"); const anyType = createIntrinsicType(TypeFlags.Any, "any"); const autoType = createIntrinsicType(TypeFlags.Any, "any"); - const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); const errorType = createIntrinsicType(TypeFlags.Any, "error"); const nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType); const intrinsicMarkerType = createIntrinsicType(TypeFlags.Any, "intrinsic"); @@ -13629,7 +13632,7 @@ namespace ts { if (!(flags & TypeFlags.Never)) { includes |= flags & TypeFlags.IncludesMask; if (flags & TypeFlags.StructuredOrInstantiable) includes |= TypeFlags.IncludesStructuredOrInstantiable; - if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; + if (type === wildcardType || type === opaqueWildcardType) includes |= TypeFlags.IncludesWildcard; if (!strictNullChecks && flags & TypeFlags.Nullable) { if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType; } @@ -13788,7 +13791,10 @@ namespace ts { const includes = addTypesToUnion(typeSet, 0, types); if (unionReduction !== UnionReduction.None) { if (includes & TypeFlags.AnyOrUnknown) { - return includes & TypeFlags.Any ? includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : unknownType; + // A wildcard has the _lowest_ type id, as it's first types created, and it's made in priority order + // - a normal `wildcardType` should take priority over an `opaqueWildcardType` if both somehoe end up + // in the same construct. (And, likewise, both should have priority over a normal `any`) + return includes & TypeFlags.Any ? includes & TypeFlags.IncludesWildcard ? typeSet[0] : anyType : unknownType; } if (includes & (TypeFlags.Literal | TypeFlags.UniqueESSymbol) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) { removeRedundantLiteralTypes(typeSet, includes, !!(unionReduction & UnionReduction.Subtype)); @@ -13927,7 +13933,8 @@ namespace ts { } else { if (flags & TypeFlags.AnyOrUnknown) { - if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; + if (type === wildcardType || type === opaqueWildcardType) includes |= TypeFlags.IncludesWildcard; + if (type === opaqueWildcardType) includes |= TypeFlags.IncludesOpaqueWildcard; } else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !typeSet.has(type.id.toString())) { if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) { @@ -14111,7 +14118,7 @@ namespace ts { return neverType; } if (includes & TypeFlags.Any) { - return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType; + return includes & TypeFlags.IncludesWildcard ? includes & TypeFlags.IncludesOpaqueWildcard ? opaqueWildcardType : wildcardType : anyType; } if (!strictNullChecks && includes & TypeFlags.Nullable) { return includes & TypeFlags.Undefined ? undefinedType : nullType; @@ -14313,6 +14320,7 @@ namespace ts { type.flags & TypeFlags.InstantiableNonPrimitive || isGenericTupleType(type) || isGenericMappedType(type) && maybeNonDistributiveNameType(getNameTypeFromMappedType(type)) ? getIndexTypeForGenericType(type, stringsOnly) : getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type, noIndexSignatures) : type === wildcardType ? wildcardType : + type === opaqueWildcardType ? opaqueWildcardType : type.flags & TypeFlags.Unknown ? neverType : type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType : stringsOnly ? !noIndexSignatures && getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromProperties(type, TypeFlags.StringLiteral, includeOrigin) : @@ -14373,6 +14381,9 @@ namespace ts { mapType(types[unionIndex], t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t))) : errorType; } + if (contains(types, opaqueWildcardType)) { + return opaqueWildcardType; + } if (contains(types, wildcardType)) { return wildcardType; } @@ -14890,6 +14901,9 @@ namespace ts { } function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, noUncheckedIndexedAccessCandidate?: boolean, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, accessFlags = AccessFlags.None, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined { + if (objectType === opaqueWildcardType || indexType === opaqueWildcardType) { + return wildcardType; + } if (objectType === wildcardType || indexType === wildcardType) { return wildcardType; } @@ -15023,7 +15037,7 @@ namespace ts { while (true) { const isUnwrapped = isTypicalNondistributiveConditional(root); const checkType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.checkType), mapper); - const checkTypeInstantiable = isGenericObjectType(checkType) || isGenericIndexType(checkType); + const checkTypeInstantiable = isGenericObjectType(checkType) || isGenericIndexType(checkType) || checkType === opaqueWildcardType; const extendsType = instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), mapper); if (checkType === wildcardType || extendsType === wildcardType) { return wildcardType; @@ -15045,7 +15059,7 @@ namespace ts { // Instantiate the extends type including inferences for 'infer T' type parameters const inferredExtendsType = combinedMapper ? instantiateType(unwrapNondistributiveConditionalTuple(root, root.extendsType), combinedMapper) : extendsType; // We attempt to resolve the conditional type only when the check and extends types are non-generic - if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType)) { + if (!checkTypeInstantiable && !isGenericObjectType(inferredExtendsType) && !isGenericIndexType(inferredExtendsType) && inferredExtendsType !== opaqueWildcardType) { // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, @@ -15782,7 +15796,7 @@ namespace ts { } function createTypeEraser(sources: readonly TypeParameter[]): TypeMapper { - return createTypeMapper(sources, /*targets*/ undefined); + return createTypeMapper(sources, map(sources, () => opaqueWildcardType)); } /** @@ -15997,7 +16011,7 @@ namespace ts { const mappedTypeVariable = instantiateType(typeVariable, mapper); if (typeVariable !== mappedTypeVariable) { return mapTypeWithAlias(getReducedType(mappedTypeVariable), t => { - if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && t !== errorType) { + if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && t !== opaqueWildcardType && t !== errorType) { if (!type.declaration.nameType) { if (isArrayType(t)) { return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper)); @@ -16016,7 +16030,8 @@ namespace ts { } } // If the constraint type of the instantiation is the wildcard type, return the wildcard type. - return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); + const instantiatedConstraint = instantiateType(getConstraintTypeFromMappedType(type), mapper); + return instantiatedConstraint === opaqueWildcardType ? opaqueWildcardType : instantiatedConstraint === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); } function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) { @@ -17161,7 +17176,7 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: ESMap, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true; + if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType || source === opaqueWildcardType) return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && @@ -18546,7 +18561,7 @@ namespace ts { // one of T1 and T2 is related to the other, U1 and U2 are identical types, X1 is related to X2, // and Y1 is related to Y2. const sourceParams = (source as ConditionalType).root.inferTypeParameters; - let sourceExtends = (source).extendsType; + let sourceExtends = instantiateType((source).extendsType, makeFunctionTypeMapper(reportUnmeasurableMarkers)); let mapper: TypeMapper | undefined; if (sourceParams) { // If the source has infer type parameters, we instantiate them in the context of the target @@ -21035,7 +21050,7 @@ namespace ts { if (!couldContainTypeVariables(target)) { return; } - if (source === wildcardType) { + if (source === wildcardType || source === opaqueWildcardType) { // We are inferring from an 'any' type. We want to infer this type for every type parameter // referenced in the target type, so we record it as the propagation type and infer from the // target to itself. Then, as we find candidates we substitute the propagation type. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f7183d7dd6c27..521520b92f34b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5074,6 +5074,8 @@ namespace ts { IncludesWildcard = IndexedAccess, /* @internal */ IncludesEmptyObject = Conditional, + /* @internal */ + IncludesOpaqueWildcard = StringMapping, } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; diff --git a/tests/baselines/reference/complexRecursiveCollections.types b/tests/baselines/reference/complexRecursiveCollections.types index d6bf7cf931a27..5fb970f18d971 100644 --- a/tests/baselines/reference/complexRecursiveCollections.types +++ b/tests/baselines/reference/complexRecursiveCollections.types @@ -1137,7 +1137,7 @@ declare module Immutable { >Seq : typeof Seq function isSeq(maybeSeq: any): maybeSeq is Seq.Indexed | Seq.Keyed; ->isSeq : (maybeSeq: any) => maybeSeq is Indexed | Keyed +>isSeq : (maybeSeq: any) => maybeSeq is Keyed | Indexed >maybeSeq : any >Seq : any >Seq : any diff --git a/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.errors.txt b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.errors.txt new file mode 100644 index 0000000000000..c04ff1e9e3558 --- /dev/null +++ b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.errors.txt @@ -0,0 +1,78 @@ +tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts(5,7): error TS2322: Type 'EqualsTest' is not assignable to type 'EqualsTest'. + Type 'any extends string ? 1 : 0' is not assignable to type 'any extends number ? 1 : 0'. + Type '0 | 1' is not assignable to type 'any extends number ? 1 : 0'. + Type '0' is not assignable to type 'any extends number ? 1 : 0'. +tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts(6,7): error TS2322: Type 'EqualsTest1' is not assignable to type 'EqualsTest'. + Type 'A extends string ? 1 : 0' is not assignable to type 'A extends number ? 1 : 0'. + Type '0 | 1' is not assignable to type 'A extends number ? 1 : 0'. + Type '0' is not assignable to type 'A extends number ? 1 : 0'. +tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts(12,27): error TS2344: Type 'this' does not satisfy the constraint 'Model'. + Type 'Model' is not assignable to type 'Model'. + Types of property 'set' are incompatible. + Type '(value: K extends MClass ? number : string) => void' is not assignable to type '(value: K extends typeof Model ? number : string) => void'. + Types of parameters 'value' and 'value' are incompatible. + Type 'K extends typeof Model ? number : string' is not assignable to type 'K extends MClass ? number : string'. + Type 'string | number' is not assignable to type 'K extends MClass ? number : string'. + Type 'string' is not assignable to type 'K extends MClass ? number : string'. +tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts(20,28): error TS2344: Type 'this' does not satisfy the constraint 'ModelSub'. + Type 'Model2' is not assignable to type 'Model2'. + Types of property 'set' are incompatible. + Type '(value: K extends MClass ? number : string) => void' is not assignable to type '(value: K extends typeof ModelSub ? number : string) => void'. + Types of parameters 'value' and 'value' are incompatible. + Type 'K extends typeof ModelSub ? number : string' is not assignable to type 'K extends MClass ? number : string'. + Type 'string | number' is not assignable to type 'K extends MClass ? number : string'. + Type 'string' is not assignable to type 'K extends MClass ? number : string'. + + +==== tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts (4 errors) ==== + // quick distillation of conditionals which were previously erased by signature relating + type EqualsTest = () => A extends T ? 1 : 0; + type EqualsTest1 = () => A extends T ? 1 : 0; + + const x: EqualsTest = undefined as any as EqualsTest; // should error, obviously wrong + ~ +!!! error TS2322: Type 'EqualsTest' is not assignable to type 'EqualsTest'. +!!! error TS2322: Type 'any extends string ? 1 : 0' is not assignable to type 'any extends number ? 1 : 0'. +!!! error TS2322: Type '0 | 1' is not assignable to type 'any extends number ? 1 : 0'. +!!! error TS2322: Type '0' is not assignable to type 'any extends number ? 1 : 0'. + const y: EqualsTest = undefined as any as EqualsTest1; // same as the above, but seperate type aliases + ~ +!!! error TS2322: Type 'EqualsTest1' is not assignable to type 'EqualsTest'. +!!! error TS2322: Type 'A extends string ? 1 : 0' is not assignable to type 'A extends number ? 1 : 0'. +!!! error TS2322: Type '0 | 1' is not assignable to type 'A extends number ? 1 : 0'. +!!! error TS2322: Type '0' is not assignable to type 'A extends number ? 1 : 0'. + + // Slightly extended example using class inheritance + type ModelId = M; // just validates the input matches the `Model` type to issue an error + export declare class Model { + class: MClass; + readonly ref: ModelId; + ~~~~ +!!! error TS2344: Type 'this' does not satisfy the constraint 'Model'. +!!! error TS2344: Type 'Model' is not assignable to type 'Model'. +!!! error TS2344: Types of property 'set' are incompatible. +!!! error TS2344: Type '(value: K extends MClass ? number : string) => void' is not assignable to type '(value: K extends typeof Model ? number : string) => void'. +!!! error TS2344: Types of parameters 'value' and 'value' are incompatible. +!!! error TS2344: Type 'K extends typeof Model ? number : string' is not assignable to type 'K extends MClass ? number : string'. +!!! error TS2344: Type 'string | number' is not assignable to type 'K extends MClass ? number : string'. +!!! error TS2344: Type 'string' is not assignable to type 'K extends MClass ? number : string'. + set(value: K extends MClass ? number : string): void; + } + + // identical to the above, but with a no-op subclass + type ModelId2 = M; + export declare class Model2 { + class: MClass; + readonly ref: ModelId2; + ~~~~ +!!! error TS2344: Type 'this' does not satisfy the constraint 'ModelSub'. +!!! error TS2344: Type 'Model2' is not assignable to type 'Model2'. +!!! error TS2344: Types of property 'set' are incompatible. +!!! error TS2344: Type '(value: K extends MClass ? number : string) => void' is not assignable to type '(value: K extends typeof ModelSub ? number : string) => void'. +!!! error TS2344: Types of parameters 'value' and 'value' are incompatible. +!!! error TS2344: Type 'K extends typeof ModelSub ? number : string' is not assignable to type 'K extends MClass ? number : string'. +!!! error TS2344: Type 'string | number' is not assignable to type 'K extends MClass ? number : string'. +!!! error TS2344: Type 'string' is not assignable to type 'K extends MClass ? number : string'. + set(value: K extends MClass ? number : string): void; + } + export declare class ModelSub extends Model2 {} \ No newline at end of file diff --git a/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.js b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.js new file mode 100644 index 0000000000000..0e941dffbac5e --- /dev/null +++ b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.js @@ -0,0 +1,30 @@ +//// [emptyClassSomehowNeverChecksConditionals.ts] +// quick distillation of conditionals which were previously erased by signature relating +type EqualsTest = () => A extends T ? 1 : 0; +type EqualsTest1 = () => A extends T ? 1 : 0; + +const x: EqualsTest = undefined as any as EqualsTest; // should error, obviously wrong +const y: EqualsTest = undefined as any as EqualsTest1; // same as the above, but seperate type aliases + +// Slightly extended example using class inheritance +type ModelId = M; // just validates the input matches the `Model` type to issue an error +export declare class Model { + class: MClass; + readonly ref: ModelId; + set(value: K extends MClass ? number : string): void; +} + +// identical to the above, but with a no-op subclass +type ModelId2 = M; +export declare class Model2 { + class: MClass; + readonly ref: ModelId2; + set(value: K extends MClass ? number : string): void; +} +export declare class ModelSub extends Model2 {} + +//// [emptyClassSomehowNeverChecksConditionals.js] +"use strict"; +exports.__esModule = true; +var x = undefined; // should error, obviously wrong +var y = undefined; // same as the above, but seperate type aliases diff --git a/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.symbols b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.symbols new file mode 100644 index 0000000000000..975c89d5afa30 --- /dev/null +++ b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.symbols @@ -0,0 +1,89 @@ +=== tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts === +// quick distillation of conditionals which were previously erased by signature relating +type EqualsTest = () => A extends T ? 1 : 0; +>EqualsTest : Symbol(EqualsTest, Decl(emptyClassSomehowNeverChecksConditionals.ts, 0, 0)) +>T : Symbol(T, Decl(emptyClassSomehowNeverChecksConditionals.ts, 1, 16)) +>A : Symbol(A, Decl(emptyClassSomehowNeverChecksConditionals.ts, 1, 22)) +>A : Symbol(A, Decl(emptyClassSomehowNeverChecksConditionals.ts, 1, 22)) +>T : Symbol(T, Decl(emptyClassSomehowNeverChecksConditionals.ts, 1, 16)) + +type EqualsTest1 = () => A extends T ? 1 : 0; +>EqualsTest1 : Symbol(EqualsTest1, Decl(emptyClassSomehowNeverChecksConditionals.ts, 1, 50)) +>T : Symbol(T, Decl(emptyClassSomehowNeverChecksConditionals.ts, 2, 17)) +>A : Symbol(A, Decl(emptyClassSomehowNeverChecksConditionals.ts, 2, 23)) +>A : Symbol(A, Decl(emptyClassSomehowNeverChecksConditionals.ts, 2, 23)) +>T : Symbol(T, Decl(emptyClassSomehowNeverChecksConditionals.ts, 2, 17)) + +const x: EqualsTest = undefined as any as EqualsTest; // should error, obviously wrong +>x : Symbol(x, Decl(emptyClassSomehowNeverChecksConditionals.ts, 4, 5)) +>EqualsTest : Symbol(EqualsTest, Decl(emptyClassSomehowNeverChecksConditionals.ts, 0, 0)) +>undefined : Symbol(undefined) +>EqualsTest : Symbol(EqualsTest, Decl(emptyClassSomehowNeverChecksConditionals.ts, 0, 0)) + +const y: EqualsTest = undefined as any as EqualsTest1; // same as the above, but seperate type aliases +>y : Symbol(y, Decl(emptyClassSomehowNeverChecksConditionals.ts, 5, 5)) +>EqualsTest : Symbol(EqualsTest, Decl(emptyClassSomehowNeverChecksConditionals.ts, 0, 0)) +>undefined : Symbol(undefined) +>EqualsTest1 : Symbol(EqualsTest1, Decl(emptyClassSomehowNeverChecksConditionals.ts, 1, 50)) + +// Slightly extended example using class inheritance +type ModelId = M; // just validates the input matches the `Model` type to issue an error +>ModelId : Symbol(ModelId, Decl(emptyClassSomehowNeverChecksConditionals.ts, 5, 70)) +>M : Symbol(M, Decl(emptyClassSomehowNeverChecksConditionals.ts, 8, 13)) +>Model : Symbol(Model, Decl(emptyClassSomehowNeverChecksConditionals.ts, 8, 34)) +>M : Symbol(M, Decl(emptyClassSomehowNeverChecksConditionals.ts, 8, 13)) + +export declare class Model { +>Model : Symbol(Model, Decl(emptyClassSomehowNeverChecksConditionals.ts, 8, 34)) +>MClass : Symbol(MClass, Decl(emptyClassSomehowNeverChecksConditionals.ts, 9, 27)) +>Model : Symbol(Model, Decl(emptyClassSomehowNeverChecksConditionals.ts, 8, 34)) +>Model : Symbol(Model, Decl(emptyClassSomehowNeverChecksConditionals.ts, 8, 34)) + + class: MClass; +>class : Symbol(Model.class, Decl(emptyClassSomehowNeverChecksConditionals.ts, 9, 72)) +>MClass : Symbol(MClass, Decl(emptyClassSomehowNeverChecksConditionals.ts, 9, 27)) + + readonly ref: ModelId; +>ref : Symbol(Model.ref, Decl(emptyClassSomehowNeverChecksConditionals.ts, 10, 18)) +>ModelId : Symbol(ModelId, Decl(emptyClassSomehowNeverChecksConditionals.ts, 5, 70)) + + set(value: K extends MClass ? number : string): void; +>set : Symbol(Model.set, Decl(emptyClassSomehowNeverChecksConditionals.ts, 11, 32)) +>K : Symbol(K, Decl(emptyClassSomehowNeverChecksConditionals.ts, 12, 8)) +>value : Symbol(value, Decl(emptyClassSomehowNeverChecksConditionals.ts, 12, 11)) +>K : Symbol(K, Decl(emptyClassSomehowNeverChecksConditionals.ts, 12, 8)) +>MClass : Symbol(MClass, Decl(emptyClassSomehowNeverChecksConditionals.ts, 9, 27)) +} + +// identical to the above, but with a no-op subclass +type ModelId2 = M; +>ModelId2 : Symbol(ModelId2, Decl(emptyClassSomehowNeverChecksConditionals.ts, 13, 1)) +>M : Symbol(M, Decl(emptyClassSomehowNeverChecksConditionals.ts, 16, 14)) +>ModelSub : Symbol(ModelSub, Decl(emptyClassSomehowNeverChecksConditionals.ts, 21, 1)) +>M : Symbol(M, Decl(emptyClassSomehowNeverChecksConditionals.ts, 16, 14)) + +export declare class Model2 { +>Model2 : Symbol(Model2, Decl(emptyClassSomehowNeverChecksConditionals.ts, 16, 38)) +>MClass : Symbol(MClass, Decl(emptyClassSomehowNeverChecksConditionals.ts, 17, 28)) +>ModelSub : Symbol(ModelSub, Decl(emptyClassSomehowNeverChecksConditionals.ts, 21, 1)) +>ModelSub : Symbol(ModelSub, Decl(emptyClassSomehowNeverChecksConditionals.ts, 21, 1)) + + class: MClass; +>class : Symbol(Model2.class, Decl(emptyClassSomehowNeverChecksConditionals.ts, 17, 79)) +>MClass : Symbol(MClass, Decl(emptyClassSomehowNeverChecksConditionals.ts, 17, 28)) + + readonly ref: ModelId2; +>ref : Symbol(Model2.ref, Decl(emptyClassSomehowNeverChecksConditionals.ts, 18, 18)) +>ModelId2 : Symbol(ModelId2, Decl(emptyClassSomehowNeverChecksConditionals.ts, 13, 1)) + + set(value: K extends MClass ? number : string): void; +>set : Symbol(Model2.set, Decl(emptyClassSomehowNeverChecksConditionals.ts, 19, 33)) +>K : Symbol(K, Decl(emptyClassSomehowNeverChecksConditionals.ts, 20, 8)) +>value : Symbol(value, Decl(emptyClassSomehowNeverChecksConditionals.ts, 20, 11)) +>K : Symbol(K, Decl(emptyClassSomehowNeverChecksConditionals.ts, 20, 8)) +>MClass : Symbol(MClass, Decl(emptyClassSomehowNeverChecksConditionals.ts, 17, 28)) +} +export declare class ModelSub extends Model2 {} +>ModelSub : Symbol(ModelSub, Decl(emptyClassSomehowNeverChecksConditionals.ts, 21, 1)) +>Model2 : Symbol(Model2, Decl(emptyClassSomehowNeverChecksConditionals.ts, 16, 38)) + diff --git a/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.types b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.types new file mode 100644 index 0000000000000..ee1dd3ecfc163 --- /dev/null +++ b/tests/baselines/reference/emptyClassSomehowNeverChecksConditionals.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts === +// quick distillation of conditionals which were previously erased by signature relating +type EqualsTest = () => A extends T ? 1 : 0; +>EqualsTest : EqualsTest + +type EqualsTest1 = () => A extends T ? 1 : 0; +>EqualsTest1 : EqualsTest1 + +const x: EqualsTest = undefined as any as EqualsTest; // should error, obviously wrong +>x : EqualsTest +>undefined as any as EqualsTest : EqualsTest +>undefined as any : any +>undefined : undefined + +const y: EqualsTest = undefined as any as EqualsTest1; // same as the above, but seperate type aliases +>y : EqualsTest +>undefined as any as EqualsTest1 : EqualsTest1 +>undefined as any : any +>undefined : undefined + +// Slightly extended example using class inheritance +type ModelId = M; // just validates the input matches the `Model` type to issue an error +>ModelId : M + +export declare class Model { +>Model : Model +>Model : typeof Model +>Model : typeof Model + + class: MClass; +>class : MClass + + readonly ref: ModelId; +>ref : this + + set(value: K extends MClass ? number : string): void; +>set : (value: K extends MClass ? number : string) => void +>value : K extends MClass ? number : string +} + +// identical to the above, but with a no-op subclass +type ModelId2 = M; +>ModelId2 : M + +export declare class Model2 { +>Model2 : Model2 +>ModelSub : typeof ModelSub +>ModelSub : typeof ModelSub + + class: MClass; +>class : MClass + + readonly ref: ModelId2; +>ref : this + + set(value: K extends MClass ? number : string): void; +>set : (value: K extends MClass ? number : string) => void +>value : K extends MClass ? number : string +} +export declare class ModelSub extends Model2 {} +>ModelSub : ModelSub +>Model2 : Model2 + diff --git a/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.js b/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.js new file mode 100644 index 0000000000000..18f1a0ee54454 --- /dev/null +++ b/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.js @@ -0,0 +1,9 @@ +//// [overloadAssignabilityChecksAllowGenericAssignment.ts] +declare function provide(cb: (x: T) => void): void; +declare function provide(cb: (x: T[keyof T]) => void): void; + +declare function provider(provide: (cb: (x: T) => void) => void): void; +provider(provide); + +//// [overloadAssignabilityChecksAllowGenericAssignment.js] +provider(provide); diff --git a/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.symbols b/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.symbols new file mode 100644 index 0000000000000..7b6c4bba7f095 --- /dev/null +++ b/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.symbols @@ -0,0 +1,28 @@ +=== tests/cases/compiler/overloadAssignabilityChecksAllowGenericAssignment.ts === +declare function provide(cb: (x: T) => void): void; +>provide : Symbol(provide, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 0), Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 54)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 25)) +>cb : Symbol(cb, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 28)) +>x : Symbol(x, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 33)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 25)) + +declare function provide(cb: (x: T[keyof T]) => void): void; +>provide : Symbol(provide, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 0), Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 54)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 25)) +>cb : Symbol(cb, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 28)) +>x : Symbol(x, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 33)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 25)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 25)) + +declare function provider(provide: (cb: (x: T) => void) => void): void; +>provider : Symbol(provider, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 63)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 3, 26)) +>provide : Symbol(provide, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 3, 29)) +>cb : Symbol(cb, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 3, 39)) +>x : Symbol(x, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 3, 44)) +>T : Symbol(T, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 3, 26)) + +provider(provide); +>provider : Symbol(provider, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 1, 63)) +>provide : Symbol(provide, Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 0), Decl(overloadAssignabilityChecksAllowGenericAssignment.ts, 0, 54)) + diff --git a/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.types b/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.types new file mode 100644 index 0000000000000..68685b4b8538f --- /dev/null +++ b/tests/baselines/reference/overloadAssignabilityChecksAllowGenericAssignment.types @@ -0,0 +1,22 @@ +=== tests/cases/compiler/overloadAssignabilityChecksAllowGenericAssignment.ts === +declare function provide(cb: (x: T) => void): void; +>provide : { (cb: (x: T) => void): void; (cb: (x: T[keyof T]) => void): void; } +>cb : (x: T) => void +>x : T + +declare function provide(cb: (x: T[keyof T]) => void): void; +>provide : { (cb: (x: T) => void): void; (cb: (x: T[keyof T]) => void): void; } +>cb : (x: T[keyof T]) => void +>x : T[keyof T] + +declare function provider(provide: (cb: (x: T) => void) => void): void; +>provider : (provide: (cb: (x: T) => void) => void) => void +>provide : (cb: (x: T) => void) => void +>cb : (x: T) => void +>x : T + +provider(provide); +>provider(provide) : void +>provider : (provide: (cb: (x: T) => void) => void) => void +>provide : { (cb: (x: T) => void): void; (cb: (x: T[keyof T]) => void): void; } + diff --git a/tests/baselines/reference/subtypingWithCallSignatures2.types b/tests/baselines/reference/subtypingWithCallSignatures2.types index 51bdbc5ed9834..cd880fc9c233a 100644 --- a/tests/baselines/reference/subtypingWithCallSignatures2.types +++ b/tests/baselines/reference/subtypingWithCallSignatures2.types @@ -762,8 +762,8 @@ var r15arg1 = (x: T) => null >null : null var r15 = foo15(r15arg1); // any ->r15 : any ->foo15(r15arg1) : any +>r15 : { (x: number): number[]; (x: string): string[]; } +>foo15(r15arg1) : { (x: number): number[]; (x: string): string[]; } >foo15 : { (a: { (x: number): number[]; (x: string): string[]; }): { (x: number): number[]; (x: string): string[]; }; (a: any): any; } >r15arg1 : (x: T) => T[] @@ -789,8 +789,8 @@ var r17arg1 = (x: (a: T) => T) => null; >null : null var r17 = foo17(r17arg1); // any ->r17 : any ->foo17(r17arg1) : any +>r17 : { (x: (a: number) => number): number[]; (x: (a: string) => string): string[]; } +>foo17(r17arg1) : { (x: (a: number) => number): number[]; (x: (a: string) => string): string[]; } >foo17 : { (a: { (x: (a: number) => number): number[]; (x: (a: string) => string): string[]; }): { (x: (a: number) => number): number[]; (x: (a: string) => string): string[]; }; (a: any): any; } >r17arg1 : (x: (a: T) => T) => T[] diff --git a/tests/baselines/reference/subtypingWithCallSignatures3.types b/tests/baselines/reference/subtypingWithCallSignatures3.types index 7116d132b7d2b..0e1c89303704e 100644 --- a/tests/baselines/reference/subtypingWithCallSignatures3.types +++ b/tests/baselines/reference/subtypingWithCallSignatures3.types @@ -457,8 +457,8 @@ module Errors { >null : null var r8 = foo16(r8arg); // any ->r8 : any ->foo16(r8arg) : any +>r8 : { (x: { (a: number): number; (a?: number): number; }): number[]; (x: { (a: boolean): boolean; (a?: boolean): boolean; }): boolean[]; } +>foo16(r8arg) : { (x: { (a: number): number; (a?: number): number; }): number[]; (x: { (a: boolean): boolean; (a?: boolean): boolean; }): boolean[]; } >foo16 : { (a2: { (x: { (a: number): number; (a?: number): number; }): number[]; (x: { (a: boolean): boolean; (a?: boolean): boolean; }): boolean[]; }): { (x: { (a: number): number; (a?: number): number; }): number[]; (x: { (a: boolean): boolean; (a?: boolean): boolean; }): boolean[]; }; (a2: any): any; } >r8arg : (x: (a: T) => T) => T[] diff --git a/tests/baselines/reference/subtypingWithConstructSignatures2.types b/tests/baselines/reference/subtypingWithConstructSignatures2.types index ef65ae549c7c2..d11cd4ca7be8a 100644 --- a/tests/baselines/reference/subtypingWithConstructSignatures2.types +++ b/tests/baselines/reference/subtypingWithConstructSignatures2.types @@ -675,8 +675,8 @@ var r15arg1: new (x: T) => T[]; >x : T var r15 = foo15(r15arg1); // any ->r15 : any ->foo15(r15arg1) : any +>r15 : { new (x: number): number[]; new (x: string): string[]; } +>foo15(r15arg1) : { new (x: number): number[]; new (x: string): string[]; } >foo15 : { (a: { new (x: number): number[]; new (x: string): string[]; }): { new (x: number): number[]; new (x: string): string[]; }; (a: any): any; } >r15arg1 : new (x: T) => T[] @@ -696,8 +696,8 @@ var r17arg1: new (x: (a: T) => T) => T[]; >a : T var r17 = foo17(r17arg1); // any ->r17 : any ->foo17(r17arg1) : any +>r17 : { new (x: (a: number) => number): number[]; new (x: (a: string) => string): string[]; } +>foo17(r17arg1) : { new (x: (a: number) => number): number[]; new (x: (a: string) => string): string[]; } >foo17 : { (a: { new (x: (a: number) => number): number[]; new (x: (a: string) => string): string[]; }): { new (x: (a: number) => number): number[]; new (x: (a: string) => string): string[]; }; (a: any): any; } >r17arg1 : new (x: (a: T) => T) => T[] diff --git a/tests/baselines/reference/subtypingWithConstructSignatures3.types b/tests/baselines/reference/subtypingWithConstructSignatures3.types index 5cf176caa0934..20ddd23c552ba 100644 --- a/tests/baselines/reference/subtypingWithConstructSignatures3.types +++ b/tests/baselines/reference/subtypingWithConstructSignatures3.types @@ -406,8 +406,8 @@ module Errors { >a : T var r8 = foo16(r8arg); // any ->r8 : any ->foo16(r8arg) : any +>r8 : { new (x: { new (a: number): number; new (a?: number): number; }): number[]; new (x: { new (a: boolean): boolean; new (a?: boolean): boolean; }): boolean[]; } +>foo16(r8arg) : { new (x: { new (a: number): number; new (a?: number): number; }): number[]; new (x: { new (a: boolean): boolean; new (a?: boolean): boolean; }): boolean[]; } >foo16 : { (a2: { new (x: { new (a: number): number; new (a?: number): number; }): number[]; new (x: { new (a: boolean): boolean; new (a?: boolean): boolean; }): boolean[]; }): { new (x: { new (a: number): number; new (a?: number): number; }): number[]; new (x: { new (a: boolean): boolean; new (a?: boolean): boolean; }): boolean[]; }; (a2: any): any; } >r8arg : new (x: new (a: T) => T) => T[] diff --git a/tests/baselines/reference/variance.js b/tests/baselines/reference/variance.js index df84404b31beb..f98528a140000 100644 --- a/tests/baselines/reference/variance.js +++ b/tests/baselines/reference/variance.js @@ -24,11 +24,47 @@ class Bar { Bar.instance.push(this); } } - + +// from #31277 +interface Set { + add(value: T): this; +} + +declare const Set: new () => Set; + +// Repro from #31251 (removed getter) + +export abstract class Supervisor { + private static instances_: Set>; + private static instances(): typeof Supervisor.instances_ { + return this.hasOwnProperty('instances_') + ? this.instances_ + : this.instances_ = new Set(); + } + constructor() { + void (this.constructor as typeof Supervisor).instances().add(this); + } + public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise; +} + + +// Minimal repro for catching variance probing in then extends type. + +interface A { + x: number extends T ? 1 : 1; +} + +declare let a: A; +declare let b: A<3>; + +a = b; // error +b = a; // error //// [variance.js] "use strict"; // Test cases for parameter variances affected by conditional types. +exports.__esModule = true; +exports.Supervisor = void 0; var foo = { prop: true }; var x = foo; var y = foo; @@ -43,3 +79,18 @@ var Bar = /** @class */ (function () { }; return Bar; }()); +// Repro from #31251 (removed getter) +var Supervisor = /** @class */ (function () { + function Supervisor() { + void this.constructor.instances().add(this); + } + Supervisor.instances = function () { + return this.hasOwnProperty('instances_') + ? this.instances_ + : this.instances_ = new Set(); + }; + return Supervisor; +}()); +exports.Supervisor = Supervisor; +a = b; // error +b = a; // error diff --git a/tests/baselines/reference/variance.symbols b/tests/baselines/reference/variance.symbols index 0a6ec56d725b6..3ed498f7680c8 100644 --- a/tests/baselines/reference/variance.symbols +++ b/tests/baselines/reference/variance.symbols @@ -60,3 +60,107 @@ class Bar { } } +// from #31277 +interface Set { +>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 31, 13)) +>T : Symbol(T, Decl(variance.ts, 27, 14)) + + add(value: T): this; +>add : Symbol(Set.add, Decl(variance.ts, 27, 18)) +>value : Symbol(value, Decl(variance.ts, 28, 6)) +>T : Symbol(T, Decl(variance.ts, 27, 14)) +} + +declare const Set: new () => Set; +>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 31, 13)) +>T : Symbol(T, Decl(variance.ts, 31, 24)) +>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 31, 13)) +>T : Symbol(T, Decl(variance.ts, 31, 24)) + +// Repro from #31251 (removed getter) + +export abstract class Supervisor { +>Supervisor : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>N : Symbol(N, Decl(variance.ts, 35, 33)) +>P : Symbol(P, Decl(variance.ts, 35, 50)) +>R : Symbol(R, Decl(variance.ts, 35, 63)) + + private static instances_: Set>; +>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) +>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 31, 13)) +>Supervisor : Symbol(Supervisor, Decl(variance.ts, 31, 39)) + + private static instances(): typeof Supervisor.instances_ { +>instances : Symbol(Supervisor.instances, Decl(variance.ts, 36, 71)) +>Supervisor.instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) +>Supervisor : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) + + return this.hasOwnProperty('instances_') +>this.hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --)) +>this : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --)) + + ? this.instances_ +>this.instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) +>this : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) + + : this.instances_ = new Set(); +>this.instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) +>this : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 35, 78)) +>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 31, 13)) + } + constructor() { + void (this.constructor as typeof Supervisor).instances().add(this); +>(this.constructor as typeof Supervisor).instances().add : Symbol(Set.add, Decl(variance.ts, 27, 18)) +>(this.constructor as typeof Supervisor).instances : Symbol(Supervisor.instances, Decl(variance.ts, 36, 71)) +>this.constructor : Symbol(Object.constructor, Decl(lib.es5.d.ts, --, --)) +>this : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>constructor : Symbol(Object.constructor, Decl(lib.es5.d.ts, --, --)) +>Supervisor : Symbol(Supervisor, Decl(variance.ts, 31, 39)) +>instances : Symbol(Supervisor.instances, Decl(variance.ts, 36, 71)) +>add : Symbol(Set.add, Decl(variance.ts, 27, 18)) +>this : Symbol(Supervisor, Decl(variance.ts, 31, 39)) + } + public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise; +>call : Symbol(Supervisor.call, Decl(variance.ts, 44, 3)) +>name : Symbol(name, Decl(variance.ts, 45, 23)) +>N : Symbol(N, Decl(variance.ts, 35, 33)) +>N : Symbol(N, Decl(variance.ts, 35, 33)) +>param : Symbol(param, Decl(variance.ts, 45, 68)) +>P : Symbol(P, Decl(variance.ts, 35, 50)) +>timeout : Symbol(timeout, Decl(variance.ts, 45, 78)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>R : Symbol(R, Decl(variance.ts, 35, 63)) +} + + +// Minimal repro for catching variance probing in then extends type. + +interface A { +>A : Symbol(A, Decl(variance.ts, 46, 1)) +>T : Symbol(T, Decl(variance.ts, 51, 12)) + + x: number extends T ? 1 : 1; +>x : Symbol(A.x, Decl(variance.ts, 51, 16)) +>T : Symbol(T, Decl(variance.ts, 51, 12)) +} + +declare let a: A; +>a : Symbol(a, Decl(variance.ts, 55, 11)) +>A : Symbol(A, Decl(variance.ts, 46, 1)) + +declare let b: A<3>; +>b : Symbol(b, Decl(variance.ts, 56, 11)) +>A : Symbol(A, Decl(variance.ts, 46, 1)) + +a = b; // error +>a : Symbol(a, Decl(variance.ts, 55, 11)) +>b : Symbol(b, Decl(variance.ts, 56, 11)) + +b = a; // error +>b : Symbol(b, Decl(variance.ts, 56, 11)) +>a : Symbol(a, Decl(variance.ts, 55, 11)) + diff --git a/tests/baselines/reference/variance.types b/tests/baselines/reference/variance.types index 08ee1053b3dba..60edb12be0306 100644 --- a/tests/baselines/reference/variance.types +++ b/tests/baselines/reference/variance.types @@ -56,3 +56,96 @@ class Bar { } } +// from #31277 +interface Set { + add(value: T): this; +>add : (value: T) => this +>value : T +} + +declare const Set: new () => Set; +>Set : new () => Set + +// Repro from #31251 (removed getter) + +export abstract class Supervisor { +>Supervisor : Supervisor + + private static instances_: Set>; +>instances_ : Set> + + private static instances(): typeof Supervisor.instances_ { +>instances : () => typeof Supervisor.instances_ +>Supervisor.instances_ : Set> +>Supervisor : typeof Supervisor +>instances_ : Set> + + return this.hasOwnProperty('instances_') +>this.hasOwnProperty('instances_') ? this.instances_ : this.instances_ = new Set() : Set> +>this.hasOwnProperty('instances_') : boolean +>this.hasOwnProperty : (v: PropertyKey) => boolean +>this : typeof Supervisor +>hasOwnProperty : (v: PropertyKey) => boolean +>'instances_' : "instances_" + + ? this.instances_ +>this.instances_ : Set> +>this : typeof Supervisor +>instances_ : Set> + + : this.instances_ = new Set(); +>this.instances_ = new Set() : Set> +>this.instances_ : Set> +>this : typeof Supervisor +>instances_ : Set> +>new Set() : Set> +>Set : new () => Set + } + constructor() { + void (this.constructor as typeof Supervisor).instances().add(this); +>void (this.constructor as typeof Supervisor).instances().add(this) : undefined +>(this.constructor as typeof Supervisor).instances().add(this) : Set> +>(this.constructor as typeof Supervisor).instances().add : (value: Supervisor) => Set> +>(this.constructor as typeof Supervisor).instances() : Set> +>(this.constructor as typeof Supervisor).instances : () => Set> +>(this.constructor as typeof Supervisor) : typeof Supervisor +>this.constructor as typeof Supervisor : typeof Supervisor +>this.constructor : Function +>this : this +>constructor : Function +>Supervisor : typeof Supervisor +>instances : () => Set> +>add : (value: Supervisor) => Set> +>this : this + } + public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise; +>call : (name: N | ('' extends N ? undefined : never), param: P, timeout?: number | undefined) => Promise +>name : N | ("" extends N ? undefined : never) +>param : P +>timeout : number | undefined +} + + +// Minimal repro for catching variance probing in then extends type. + +interface A { + x: number extends T ? 1 : 1; +>x : number extends T ? 1 : 1 +} + +declare let a: A; +>a : A + +declare let b: A<3>; +>b : A<3> + +a = b; // error +>a = b : A<3> +>a : A +>b : A<3> + +b = a; // error +>b = a : A +>b : A<3> +>a : A + diff --git a/tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts b/tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts new file mode 100644 index 0000000000000..7a514f9ad0982 --- /dev/null +++ b/tests/cases/compiler/emptyClassSomehowNeverChecksConditionals.ts @@ -0,0 +1,23 @@ +// quick distillation of conditionals which were previously erased by signature relating +type EqualsTest = () => A extends T ? 1 : 0; +type EqualsTest1 = () => A extends T ? 1 : 0; + +const x: EqualsTest = undefined as any as EqualsTest; // should error, obviously wrong +const y: EqualsTest = undefined as any as EqualsTest1; // same as the above, but seperate type aliases + +// Slightly extended example using class inheritance +type ModelId = M; // just validates the input matches the `Model` type to issue an error +export declare class Model { + class: MClass; + readonly ref: ModelId; + set(value: K extends MClass ? number : string): void; +} + +// identical to the above, but with a no-op subclass +type ModelId2 = M; +export declare class Model2 { + class: MClass; + readonly ref: ModelId2; + set(value: K extends MClass ? number : string): void; +} +export declare class ModelSub extends Model2 {} \ No newline at end of file diff --git a/tests/cases/compiler/overloadAssignabilityChecksAllowGenericAssignment.ts b/tests/cases/compiler/overloadAssignabilityChecksAllowGenericAssignment.ts new file mode 100644 index 0000000000000..6a26273644ef8 --- /dev/null +++ b/tests/cases/compiler/overloadAssignabilityChecksAllowGenericAssignment.ts @@ -0,0 +1,5 @@ +declare function provide(cb: (x: T) => void): void; +declare function provide(cb: (x: T[keyof T]) => void): void; + +declare function provider(provide: (cb: (x: T) => void) => void): void; +provider(provide); \ No newline at end of file diff --git a/tests/cases/conformance/types/conditional/variance.ts b/tests/cases/conformance/types/conditional/variance.ts index 1dd5db5c67e8f..b2a0ae0776504 100644 --- a/tests/cases/conformance/types/conditional/variance.ts +++ b/tests/cases/conformance/types/conditional/variance.ts @@ -25,3 +25,38 @@ class Bar { Bar.instance.push(this); } } + +// from #31277 +interface Set { + add(value: T): this; +} + +declare const Set: new () => Set; + +// Repro from #31251 (removed getter) + +export abstract class Supervisor { + private static instances_: Set>; + private static instances(): typeof Supervisor.instances_ { + return this.hasOwnProperty('instances_') + ? this.instances_ + : this.instances_ = new Set(); + } + constructor() { + void (this.constructor as typeof Supervisor).instances().add(this); + } + public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise; +} + + +// Minimal repro for catching variance probing in then extends type. + +interface A { + x: number extends T ? 1 : 1; +} + +declare let a: A; +declare let b: A<3>; + +a = b; // error +b = a; // error \ No newline at end of file