Variance annotations on class expressions + deferred valiation (#48645)

* Variance annotations on class expressions + deferred validation

* Add regression tests
This commit is contained in:
Anders Hejlsberg
2022-04-12 06:34:33 -07:00
committed by GitHub
parent c9a4d017fd
commit cce61d1b69
6 changed files with 141 additions and 5 deletions

View File

@@ -34838,11 +34838,17 @@ namespace ts {
if (constraintType && defaultType) {
checkTypeAssignableTo(defaultType, getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType), node.default, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
}
if (node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.ClassDeclaration || node.parent.kind === SyntaxKind.TypeAliasDeclaration) {
checkNodeDeferred(node);
addLazyDiagnostic(() => checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0));
}
function checkTypeParameterDeferred(node: TypeParameterDeclaration) {
if (isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent)) {
const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
const modifiers = getVarianceModifiers(typeParameter);
if (modifiers) {
const symbol = getSymbolOfNode(node.parent);
if (node.parent.kind === SyntaxKind.TypeAliasDeclaration && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) {
if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) {
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) {
@@ -34855,7 +34861,6 @@ namespace ts {
}
}
}
addLazyDiagnostic(() => checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0));
}
function checkParameter(node: ParameterDeclaration) {
@@ -41354,6 +41359,9 @@ namespace ts {
case SyntaxKind.ClassExpression:
checkClassExpressionDeferred(node as ClassExpression);
break;
case SyntaxKind.TypeParameter:
checkTypeParameterDeferred(node as TypeParameterDeclaration);
break;
case SyntaxKind.JsxSelfClosingElement:
checkJsxSelfClosingElementDeferred(node as JsxSelfClosingElement);
break;
@@ -43551,8 +43559,7 @@ namespace ts {
case SyntaxKind.OutKeyword:
const inOutFlag = modifier.kind === SyntaxKind.InKeyword ? ModifierFlags.In : ModifierFlags.Out;
const inOutText = modifier.kind === SyntaxKind.InKeyword ? "in" : "out";
if (node.kind !== SyntaxKind.TypeParameter || (node.parent.kind !== SyntaxKind.InterfaceDeclaration &&
node.parent.kind !== SyntaxKind.ClassDeclaration && node.parent.kind !== SyntaxKind.TypeAliasDeclaration)) {
if (node.kind !== SyntaxKind.TypeParameter || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent))) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText);
}
if (flags & inOutFlag) {

View File

@@ -324,4 +324,18 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/varianceAnnotati
!!! error TS2345: Types of property '_storedEvent' are incompatible.
!!! error TS2345: Type '{ type: "PLAY"; value: number; } | { type: "RESET"; }' is not assignable to type '{ type: "PLAY"; value: number; }'.
!!! error TS2345: Type '{ type: "RESET"; }' is not assignable to type '{ type: "PLAY"; value: number; }'.
// Repros from #48618
let Anon = class <out T> {
foo(): InstanceType<(typeof Anon<T>)> {
return this;
}
}
let OuterC = class C<out T> {
foo(): C<T> {
return this;
}
}

View File

@@ -159,6 +159,20 @@ interpret(machine);
declare const qq: ActionObject<{ type: "PLAY"; value: number }>;
createMachine<{ type: "PLAY"; value: number } | { type: "RESET" }>(qq); // Error
// Repros from #48618
let Anon = class <out T> {
foo(): InstanceType<(typeof Anon<T>)> {
return this;
}
}
let OuterC = class C<out T> {
foo(): C<T> {
return this;
}
}
//// [varianceAnnotations.js]
@@ -186,6 +200,23 @@ var notString = pu; // Error
var machine = createMachine({});
interpret(machine);
createMachine(qq); // Error
// Repros from #48618
var Anon = /** @class */ (function () {
function class_1() {
}
class_1.prototype.foo = function () {
return this;
};
return class_1;
}());
var OuterC = /** @class */ (function () {
function C() {
}
C.prototype.foo = function () {
return this;
};
return C;
}());
//// [varianceAnnotations.d.ts]
@@ -293,3 +324,13 @@ declare const qq: ActionObject<{
type: "PLAY";
value: number;
}>;
declare let Anon: {
new <out T>(): {
foo(): any;
};
};
declare let OuterC: {
new <out T>(): {
foo(): any;
};
};

View File

@@ -448,3 +448,35 @@ createMachine<{ type: "PLAY"; value: number } | { type: "RESET" }>(qq); // Erro
>type : Symbol(type, Decl(varianceAnnotations.ts, 159, 49))
>qq : Symbol(qq, Decl(varianceAnnotations.ts, 157, 13))
// Repros from #48618
let Anon = class <out T> {
>Anon : Symbol(Anon, Decl(varianceAnnotations.ts, 163, 3))
>T : Symbol(T, Decl(varianceAnnotations.ts, 163, 18))
foo(): InstanceType<(typeof Anon<T>)> {
>foo : Symbol(Anon.foo, Decl(varianceAnnotations.ts, 163, 26))
>InstanceType : Symbol(InstanceType, Decl(lib.es5.d.ts, --, --))
>Anon : Symbol(Anon, Decl(varianceAnnotations.ts, 163, 3))
>T : Symbol(T, Decl(varianceAnnotations.ts, 163, 18))
return this;
>this : Symbol(Anon, Decl(varianceAnnotations.ts, 163, 10))
}
}
let OuterC = class C<out T> {
>OuterC : Symbol(OuterC, Decl(varianceAnnotations.ts, 169, 3))
>C : Symbol(C, Decl(varianceAnnotations.ts, 169, 12))
>T : Symbol(T, Decl(varianceAnnotations.ts, 169, 21))
foo(): C<T> {
>foo : Symbol(C.foo, Decl(varianceAnnotations.ts, 169, 29))
>C : Symbol(C, Decl(varianceAnnotations.ts, 169, 12))
>T : Symbol(T, Decl(varianceAnnotations.ts, 169, 21))
return this;
>this : Symbol(C, Decl(varianceAnnotations.ts, 169, 12))
}
}

View File

@@ -346,3 +346,31 @@ createMachine<{ type: "PLAY"; value: number } | { type: "RESET" }>(qq); // Erro
>type : "RESET"
>qq : ActionObject<{ type: "PLAY"; value: number; }>
// Repros from #48618
let Anon = class <out T> {
>Anon : typeof Anon
>class <out T> { foo(): InstanceType<(typeof Anon<T>)> { return this; }} : typeof Anon
foo(): InstanceType<(typeof Anon<T>)> {
>foo : () => InstanceType<(typeof Anon<T>)>
>Anon : typeof Anon
return this;
>this : this
}
}
let OuterC = class C<out T> {
>OuterC : typeof C
>class C<out T> { foo(): C<T> { return this; }} : typeof C
>C : typeof C
foo(): C<T> {
>foo : () => C<T>
return this;
>this : this
}
}

View File

@@ -161,3 +161,17 @@ interpret(machine);
declare const qq: ActionObject<{ type: "PLAY"; value: number }>;
createMachine<{ type: "PLAY"; value: number } | { type: "RESET" }>(qq); // Error
// Repros from #48618
let Anon = class <out T> {
foo(): InstanceType<(typeof Anon<T>)> {
return this;
}
}
let OuterC = class C<out T> {
foo(): C<T> {
return this;
}
}