mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Use separate marker types for variance annotation validation (#49616)
* Use separate marker types for variance annotation validation * Add regression test
This commit is contained in:
parent
4c2770d769
commit
529ba99e29
@ -861,6 +861,10 @@ namespace ts {
|
||||
markerSubType.constraint = markerSuperType;
|
||||
const markerOtherType = createTypeParameter();
|
||||
|
||||
const markerSuperTypeForCheck = createTypeParameter();
|
||||
const markerSubTypeForCheck = createTypeParameter();
|
||||
markerSubTypeForCheck.constraint = markerSuperTypeForCheck;
|
||||
|
||||
const noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<<unresolved>>", 0, anyType);
|
||||
|
||||
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None);
|
||||
@ -5047,8 +5051,8 @@ namespace ts {
|
||||
if (type.symbol) {
|
||||
return symbolToTypeNode(type.symbol, context, SymbolFlags.Type);
|
||||
}
|
||||
const name = (type === markerSuperType || type === markerSubType) && varianceTypeParameter && varianceTypeParameter.symbol ?
|
||||
(type === markerSubType ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?";
|
||||
const name = (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter && varianceTypeParameter.symbol ?
|
||||
(type === markerSubTypeForCheck ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?";
|
||||
return factory.createTypeReferenceNode(factory.createIdentifier(name), /*typeArguments*/ undefined);
|
||||
}
|
||||
if (type.flags & TypeFlags.Union && (type as UnionType).origin) {
|
||||
@ -18543,7 +18547,7 @@ namespace ts {
|
||||
generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource);
|
||||
}
|
||||
|
||||
if (target.flags & TypeFlags.TypeParameter && target !== markerSuperType && target !== markerSubType) {
|
||||
if (target.flags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) {
|
||||
const constraint = getBaseConstraintOfType(target);
|
||||
let needsOriginalSource;
|
||||
if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) {
|
||||
@ -35041,8 +35045,8 @@ namespace ts {
|
||||
error(node, Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types);
|
||||
}
|
||||
else if (modifiers === ModifierFlags.In || modifiers === ModifierFlags.Out) {
|
||||
const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubType : markerSuperType);
|
||||
const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperType : markerSubType);
|
||||
const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck);
|
||||
const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck);
|
||||
const saveVarianceTypeParameter = typeParameter;
|
||||
varianceTypeParameter = typeParameter;
|
||||
checkTypeAssignableTo(source, target, node, Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation);
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
tests/cases/compiler/varianceAnnotationValidation.ts(5,22): error TS2636: Type 'Controller<sub-T>' is not assignable to type 'Controller<super-T>' as implied by variance annotation.
|
||||
Types of property 'run' are incompatible.
|
||||
Type '(animal: sub-T) => void' is not assignable to type '(animal: super-T) => void'.
|
||||
Types of parameters 'animal' and 'animal' are incompatible.
|
||||
Type 'super-T' is not assignable to type 'sub-T'.
|
||||
tests/cases/compiler/varianceAnnotationValidation.ts(27,1): error TS2322: Type 'AnimalContainer<Animal>' is not assignable to type 'AnimalContainer<Dog>'.
|
||||
Property 'bark' is missing in type 'Animal' but required in type 'Dog'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/varianceAnnotationValidation.ts (2 errors) ====
|
||||
// Repro from #49607
|
||||
|
||||
// Variance annotation error expected
|
||||
|
||||
interface Controller<out T> {
|
||||
~~~~~
|
||||
!!! error TS2636: Type 'Controller<sub-T>' is not assignable to type 'Controller<super-T>' as implied by variance annotation.
|
||||
!!! error TS2636: Types of property 'run' are incompatible.
|
||||
!!! error TS2636: Type '(animal: sub-T) => void' is not assignable to type '(animal: super-T) => void'.
|
||||
!!! error TS2636: Types of parameters 'animal' and 'animal' are incompatible.
|
||||
!!! error TS2636: Type 'super-T' is not assignable to type 'sub-T'.
|
||||
createAnimal: () => T;
|
||||
run: (animal: T) => void;
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
run(): void;
|
||||
};
|
||||
|
||||
class Dog implements Animal {
|
||||
run() {};
|
||||
bark() {};
|
||||
}
|
||||
|
||||
interface AnimalContainer<T> {
|
||||
controller: Controller<T>;
|
||||
}
|
||||
|
||||
declare let ca: AnimalContainer<Animal>;
|
||||
declare let cd: AnimalContainer<Dog>;
|
||||
|
||||
ca = cd; // Ok
|
||||
cd = ca; // Error
|
||||
~~
|
||||
!!! error TS2322: Type 'AnimalContainer<Animal>' is not assignable to type 'AnimalContainer<Dog>'.
|
||||
!!! error TS2322: Property 'bark' is missing in type 'Animal' but required in type 'Dog'.
|
||||
!!! related TS2728 tests/cases/compiler/varianceAnnotationValidation.ts:16:2: 'bark' is declared here.
|
||||
|
||||
64
tests/baselines/reference/varianceAnnotationValidation.js
Normal file
64
tests/baselines/reference/varianceAnnotationValidation.js
Normal file
@ -0,0 +1,64 @@
|
||||
//// [varianceAnnotationValidation.ts]
|
||||
// Repro from #49607
|
||||
|
||||
// Variance annotation error expected
|
||||
|
||||
interface Controller<out T> {
|
||||
createAnimal: () => T;
|
||||
run: (animal: T) => void;
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
run(): void;
|
||||
};
|
||||
|
||||
class Dog implements Animal {
|
||||
run() {};
|
||||
bark() {};
|
||||
}
|
||||
|
||||
interface AnimalContainer<T> {
|
||||
controller: Controller<T>;
|
||||
}
|
||||
|
||||
declare let ca: AnimalContainer<Animal>;
|
||||
declare let cd: AnimalContainer<Dog>;
|
||||
|
||||
ca = cd; // Ok
|
||||
cd = ca; // Error
|
||||
|
||||
|
||||
//// [varianceAnnotationValidation.js]
|
||||
"use strict";
|
||||
// Repro from #49607
|
||||
;
|
||||
var Dog = /** @class */ (function () {
|
||||
function Dog() {
|
||||
}
|
||||
Dog.prototype.run = function () { };
|
||||
;
|
||||
Dog.prototype.bark = function () { };
|
||||
;
|
||||
return Dog;
|
||||
}());
|
||||
ca = cd; // Ok
|
||||
cd = ca; // Error
|
||||
|
||||
|
||||
//// [varianceAnnotationValidation.d.ts]
|
||||
interface Controller<out T> {
|
||||
createAnimal: () => T;
|
||||
run: (animal: T) => void;
|
||||
}
|
||||
interface Animal {
|
||||
run(): void;
|
||||
}
|
||||
declare class Dog implements Animal {
|
||||
run(): void;
|
||||
bark(): void;
|
||||
}
|
||||
interface AnimalContainer<T> {
|
||||
controller: Controller<T>;
|
||||
}
|
||||
declare let ca: AnimalContainer<Animal>;
|
||||
declare let cd: AnimalContainer<Dog>;
|
||||
@ -0,0 +1,66 @@
|
||||
=== tests/cases/compiler/varianceAnnotationValidation.ts ===
|
||||
// Repro from #49607
|
||||
|
||||
// Variance annotation error expected
|
||||
|
||||
interface Controller<out T> {
|
||||
>Controller : Symbol(Controller, Decl(varianceAnnotationValidation.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(varianceAnnotationValidation.ts, 4, 21))
|
||||
|
||||
createAnimal: () => T;
|
||||
>createAnimal : Symbol(Controller.createAnimal, Decl(varianceAnnotationValidation.ts, 4, 29))
|
||||
>T : Symbol(T, Decl(varianceAnnotationValidation.ts, 4, 21))
|
||||
|
||||
run: (animal: T) => void;
|
||||
>run : Symbol(Controller.run, Decl(varianceAnnotationValidation.ts, 5, 23))
|
||||
>animal : Symbol(animal, Decl(varianceAnnotationValidation.ts, 6, 7))
|
||||
>T : Symbol(T, Decl(varianceAnnotationValidation.ts, 4, 21))
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
>Animal : Symbol(Animal, Decl(varianceAnnotationValidation.ts, 7, 1))
|
||||
|
||||
run(): void;
|
||||
>run : Symbol(Animal.run, Decl(varianceAnnotationValidation.ts, 9, 18))
|
||||
|
||||
};
|
||||
|
||||
class Dog implements Animal {
|
||||
>Dog : Symbol(Dog, Decl(varianceAnnotationValidation.ts, 11, 2))
|
||||
>Animal : Symbol(Animal, Decl(varianceAnnotationValidation.ts, 7, 1))
|
||||
|
||||
run() {};
|
||||
>run : Symbol(Dog.run, Decl(varianceAnnotationValidation.ts, 13, 29))
|
||||
|
||||
bark() {};
|
||||
>bark : Symbol(Dog.bark, Decl(varianceAnnotationValidation.ts, 14, 10))
|
||||
}
|
||||
|
||||
interface AnimalContainer<T> {
|
||||
>AnimalContainer : Symbol(AnimalContainer, Decl(varianceAnnotationValidation.ts, 16, 1))
|
||||
>T : Symbol(T, Decl(varianceAnnotationValidation.ts, 18, 26))
|
||||
|
||||
controller: Controller<T>;
|
||||
>controller : Symbol(AnimalContainer.controller, Decl(varianceAnnotationValidation.ts, 18, 30))
|
||||
>Controller : Symbol(Controller, Decl(varianceAnnotationValidation.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(varianceAnnotationValidation.ts, 18, 26))
|
||||
}
|
||||
|
||||
declare let ca: AnimalContainer<Animal>;
|
||||
>ca : Symbol(ca, Decl(varianceAnnotationValidation.ts, 22, 11))
|
||||
>AnimalContainer : Symbol(AnimalContainer, Decl(varianceAnnotationValidation.ts, 16, 1))
|
||||
>Animal : Symbol(Animal, Decl(varianceAnnotationValidation.ts, 7, 1))
|
||||
|
||||
declare let cd: AnimalContainer<Dog>;
|
||||
>cd : Symbol(cd, Decl(varianceAnnotationValidation.ts, 23, 11))
|
||||
>AnimalContainer : Symbol(AnimalContainer, Decl(varianceAnnotationValidation.ts, 16, 1))
|
||||
>Dog : Symbol(Dog, Decl(varianceAnnotationValidation.ts, 11, 2))
|
||||
|
||||
ca = cd; // Ok
|
||||
>ca : Symbol(ca, Decl(varianceAnnotationValidation.ts, 22, 11))
|
||||
>cd : Symbol(cd, Decl(varianceAnnotationValidation.ts, 23, 11))
|
||||
|
||||
cd = ca; // Error
|
||||
>cd : Symbol(cd, Decl(varianceAnnotationValidation.ts, 23, 11))
|
||||
>ca : Symbol(ca, Decl(varianceAnnotationValidation.ts, 22, 11))
|
||||
|
||||
51
tests/baselines/reference/varianceAnnotationValidation.types
Normal file
51
tests/baselines/reference/varianceAnnotationValidation.types
Normal file
@ -0,0 +1,51 @@
|
||||
=== tests/cases/compiler/varianceAnnotationValidation.ts ===
|
||||
// Repro from #49607
|
||||
|
||||
// Variance annotation error expected
|
||||
|
||||
interface Controller<out T> {
|
||||
createAnimal: () => T;
|
||||
>createAnimal : () => T
|
||||
|
||||
run: (animal: T) => void;
|
||||
>run : (animal: T) => void
|
||||
>animal : T
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
run(): void;
|
||||
>run : () => void
|
||||
|
||||
};
|
||||
|
||||
class Dog implements Animal {
|
||||
>Dog : Dog
|
||||
|
||||
run() {};
|
||||
>run : () => void
|
||||
|
||||
bark() {};
|
||||
>bark : () => void
|
||||
}
|
||||
|
||||
interface AnimalContainer<T> {
|
||||
controller: Controller<T>;
|
||||
>controller : Controller<T>
|
||||
}
|
||||
|
||||
declare let ca: AnimalContainer<Animal>;
|
||||
>ca : AnimalContainer<Animal>
|
||||
|
||||
declare let cd: AnimalContainer<Dog>;
|
||||
>cd : AnimalContainer<Dog>
|
||||
|
||||
ca = cd; // Ok
|
||||
>ca = cd : AnimalContainer<Dog>
|
||||
>ca : AnimalContainer<Animal>
|
||||
>cd : AnimalContainer<Dog>
|
||||
|
||||
cd = ca; // Error
|
||||
>cd = ca : AnimalContainer<Animal>
|
||||
>cd : AnimalContainer<Dog>
|
||||
>ca : AnimalContainer<Animal>
|
||||
|
||||
30
tests/cases/compiler/varianceAnnotationValidation.ts
Normal file
30
tests/cases/compiler/varianceAnnotationValidation.ts
Normal file
@ -0,0 +1,30 @@
|
||||
// @strict: true
|
||||
// @declaration: true
|
||||
|
||||
// Repro from #49607
|
||||
|
||||
// Variance annotation error expected
|
||||
|
||||
interface Controller<out T> {
|
||||
createAnimal: () => T;
|
||||
run: (animal: T) => void;
|
||||
}
|
||||
|
||||
interface Animal {
|
||||
run(): void;
|
||||
};
|
||||
|
||||
class Dog implements Animal {
|
||||
run() {};
|
||||
bark() {};
|
||||
}
|
||||
|
||||
interface AnimalContainer<T> {
|
||||
controller: Controller<T>;
|
||||
}
|
||||
|
||||
declare let ca: AnimalContainer<Animal>;
|
||||
declare let cd: AnimalContainer<Dog>;
|
||||
|
||||
ca = cd; // Ok
|
||||
cd = ca; // Error
|
||||
Loading…
x
Reference in New Issue
Block a user