Skip to content

Commit 6cb58d3

Browse files
authored
Optional variance annotations (microsoft#48240)
* Simplify getVariancesWorker and associated logic * Accept new API baselines * Add 'in' and 'out' modififers / add modifiers to type parameters * Check variance annotations * Update test runner * Accept new API baselines * Allow variance annotations only on certain type parameters * Add deprecated implementation of createTypeParameterDeclaration * Accept new API baselines * Report variance markers as 'sub-XXX' and 'super-XXX' * Add tests * Accept new baselines
1 parent fdb1c2f commit 6cb58d3

25 files changed

+2296
-578
lines changed

src/compiler/checker.ts

+113-62
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

+12
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,14 @@
883883
"category": "Error",
884884
"code": 1272
885885
},
886+
"'{0}' modifier cannot appear on a type parameter": {
887+
"category": "Error",
888+
"code": 1273
889+
},
890+
"'{0}' modifier can only appear on a type parameter of a class, interface or type alias": {
891+
"category": "Error",
892+
"code": 1274
893+
},
886894

887895
"'with' statements are not allowed in an async function block.": {
888896
"category": "Error",
@@ -2727,6 +2735,10 @@
27272735
"category": "Error",
27282736
"code": 2635
27292737
},
2738+
"Type '{0}' is not assignable to type '{1}' as implied by variance annotation.": {
2739+
"category": "Error",
2740+
"code": 2636
2741+
},
27302742

27312743
"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
27322744
"category": "Error",

src/compiler/emitter.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,7 @@ namespace ts {
20092009
//
20102010

20112011
function emitTypeParameter(node: TypeParameterDeclaration) {
2012+
emitModifiers(node, node.modifiers);
20122013
emit(node.name);
20132014
if (node.constraint) {
20142015
writeSpace();

src/compiler/factory/nodeFactory.ts

+42-5
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,8 @@ namespace ts {
998998
case SyntaxKind.BigIntKeyword:
999999
case SyntaxKind.NeverKeyword:
10001000
case SyntaxKind.ObjectKeyword:
1001+
case SyntaxKind.InKeyword:
1002+
case SyntaxKind.OutKeyword:
10011003
case SyntaxKind.OverrideKeyword:
10021004
case SyntaxKind.StringKeyword:
10031005
case SyntaxKind.BooleanKeyword:
@@ -1077,6 +1079,8 @@ namespace ts {
10771079
if (flags & ModifierFlags.Override) result.push(createModifier(SyntaxKind.OverrideKeyword));
10781080
if (flags & ModifierFlags.Readonly) result.push(createModifier(SyntaxKind.ReadonlyKeyword));
10791081
if (flags & ModifierFlags.Async) result.push(createModifier(SyntaxKind.AsyncKeyword));
1082+
if (flags & ModifierFlags.In) result.push(createModifier(SyntaxKind.InKeyword));
1083+
if (flags & ModifierFlags.Out) result.push(createModifier(SyntaxKind.OutKeyword));
10801084
return result.length ? result : undefined;
10811085
}
10821086

@@ -1126,11 +1130,27 @@ namespace ts {
11261130
//
11271131

11281132
// @api
1129-
function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
1133+
function createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration;
1134+
/** @deprecated */
1135+
function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration;
1136+
function createTypeParameterDeclaration(modifiersOrName: readonly Modifier[] | string | Identifier | undefined , nameOrConstraint?: string | Identifier | TypeNode, constraintOrDefault?: TypeNode, defaultType?: TypeNode) {
1137+
let name;
1138+
let modifiers;
1139+
let constraint;
1140+
if (modifiersOrName === undefined || isArray(modifiersOrName)) {
1141+
modifiers = modifiersOrName;
1142+
name = nameOrConstraint as string | Identifier;
1143+
constraint = constraintOrDefault;
1144+
}
1145+
else {
1146+
modifiers = undefined;
1147+
name = modifiersOrName;
1148+
constraint = nameOrConstraint as TypeNode | undefined;
1149+
}
11301150
const node = createBaseNamedDeclaration<TypeParameterDeclaration>(
11311151
SyntaxKind.TypeParameter,
11321152
/*decorators*/ undefined,
1133-
/*modifiers*/ undefined,
1153+
modifiers,
11341154
name
11351155
);
11361156
node.constraint = constraint;
@@ -1140,11 +1160,28 @@ namespace ts {
11401160
}
11411161

11421162
// @api
1143-
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
1144-
return node.name !== name
1163+
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration;
1164+
/** @deprecated */
1165+
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration;
1166+
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiersOrName: readonly Modifier[] | Identifier | undefined, nameOrConstraint: Identifier | TypeNode | undefined, constraintOrDefault: TypeNode | undefined, defaultType?: TypeNode | undefined) {
1167+
let name;
1168+
let modifiers;
1169+
let constraint;
1170+
if (modifiersOrName === undefined || isArray(modifiersOrName)) {
1171+
modifiers = modifiersOrName;
1172+
name = nameOrConstraint as Identifier;
1173+
constraint = constraintOrDefault;
1174+
}
1175+
else {
1176+
modifiers = undefined;
1177+
name = modifiersOrName;
1178+
constraint = nameOrConstraint as TypeNode | undefined;
1179+
}
1180+
return node.modifiers !== modifiers
1181+
|| node.name !== name
11451182
|| node.constraint !== constraint
11461183
|| node.default !== defaultType
1147-
? update(createTypeParameterDeclaration(name, constraint, defaultType), node)
1184+
? update(createTypeParameterDeclaration(modifiers, name, constraint, defaultType), node)
11481185
: node;
11491186
}
11501187

src/compiler/parser.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ namespace ts {
117117
return visitNode(cbNode, (node as QualifiedName).left) ||
118118
visitNode(cbNode, (node as QualifiedName).right);
119119
case SyntaxKind.TypeParameter:
120-
return visitNode(cbNode, (node as TypeParameterDeclaration).name) ||
120+
return visitNodes(cbNode, cbNodes, node.modifiers) ||
121+
visitNode(cbNode, (node as TypeParameterDeclaration).name) ||
121122
visitNode(cbNode, (node as TypeParameterDeclaration).constraint) ||
122123
visitNode(cbNode, (node as TypeParameterDeclaration).default) ||
123124
visitNode(cbNode, (node as TypeParameterDeclaration).expression);
@@ -2176,7 +2177,7 @@ namespace ts {
21762177
case ParsingContext.ArrayBindingElements:
21772178
return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();
21782179
case ParsingContext.TypeParameters:
2179-
return isIdentifier();
2180+
return token() === SyntaxKind.InKeyword || isIdentifier();
21802181
case ParsingContext.ArrayLiteralMembers:
21812182
switch (token()) {
21822183
case SyntaxKind.CommaToken:
@@ -3176,6 +3177,7 @@ namespace ts {
31763177

31773178
function parseTypeParameter(): TypeParameterDeclaration {
31783179
const pos = getNodePos();
3180+
const modifiers = parseModifiers();
31793181
const name = parseIdentifier();
31803182
let constraint: TypeNode | undefined;
31813183
let expression: Expression | undefined;
@@ -3200,7 +3202,7 @@ namespace ts {
32003202
}
32013203

32023204
const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined;
3203-
const node = factory.createTypeParameterDeclaration(name, constraint, defaultType);
3205+
const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType);
32043206
node.expression = expression;
32053207
return finishNode(node, pos);
32063208
}
@@ -3605,7 +3607,7 @@ namespace ts {
36053607
const name = parseIdentifierName();
36063608
parseExpected(SyntaxKind.InKeyword);
36073609
const type = parseType();
3608-
return finishNode(factory.createTypeParameterDeclaration(name, type, /*defaultType*/ undefined), pos);
3610+
return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos);
36093611
}
36103612

36113613
function parseMappedType() {
@@ -3961,6 +3963,7 @@ namespace ts {
39613963
const pos = getNodePos();
39623964
return finishNode(
39633965
factory.createTypeParameterDeclaration(
3966+
/*modifiers*/ undefined,
39643967
parseIdentifier(),
39653968
/*constraint*/ undefined,
39663969
/*defaultType*/ undefined
@@ -8656,7 +8659,7 @@ namespace ts {
86568659
if (nodeIsMissing(name)) {
86578660
return undefined;
86588661
}
8659-
return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, defaultType), typeParameterPos);
8662+
return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos);
86608663
}
86618664

86628665
function parseTemplateTagTypeParameters() {

src/compiler/program.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2414,6 +2414,8 @@ namespace ts {
24142414
case SyntaxKind.DeclareKeyword:
24152415
case SyntaxKind.AbstractKeyword:
24162416
case SyntaxKind.OverrideKeyword:
2417+
case SyntaxKind.InKeyword:
2418+
case SyntaxKind.OutKeyword:
24172419
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind)));
24182420
break;
24192421

src/compiler/scanner.ts

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ namespace ts {
131131
protected: SyntaxKind.ProtectedKeyword,
132132
public: SyntaxKind.PublicKeyword,
133133
override: SyntaxKind.OverrideKeyword,
134+
out: SyntaxKind.OutKeyword,
134135
readonly: SyntaxKind.ReadonlyKeyword,
135136
require: SyntaxKind.RequireKeyword,
136137
global: SyntaxKind.GlobalKeyword,

src/compiler/transformers/declarations.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ namespace ts {
10291029
}
10301030
case SyntaxKind.TypeParameter: {
10311031
if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) {
1032-
return cleanup(factory.updateTypeParameterDeclaration(input, input.name, /*constraint*/ undefined, /*defaultType*/ undefined));
1032+
return cleanup(factory.updateTypeParameterDeclaration(input, input.modifiers, input.name, /*constraint*/ undefined, /*defaultType*/ undefined));
10331033
}
10341034
return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
10351035
}

src/compiler/transformers/ts.ts

+2
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ namespace ts {
373373
case SyntaxKind.ConstKeyword:
374374
case SyntaxKind.DeclareKeyword:
375375
case SyntaxKind.ReadonlyKeyword:
376+
case SyntaxKind.InKeyword:
377+
case SyntaxKind.OutKeyword:
376378
// TypeScript accessibility and readonly modifiers are elided
377379
// falls through
378380
case SyntaxKind.ArrayType:

0 commit comments

Comments
 (0)