Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional variance annotations #48240

Merged
merged 13 commits into from
Mar 22, 2022
Merged
175 changes: 113 additions & 62 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,14 @@
"category": "Error",
"code": 1272
},
"'{0}' modifier cannot appear on a type parameter": {
"category": "Error",
"code": 1273
},
"'{0}' modifier can only appear on a type parameter of a class, interface or type alias": {
"category": "Error",
"code": 1274
},

"'with' statements are not allowed in an async function block.": {
"category": "Error",
Expand Down Expand Up @@ -2727,6 +2735,10 @@
"category": "Error",
"code": 2635
},
"Type '{0}' is not assignable to type '{1}' as implied by variance annotation.": {
"category": "Error",
"code": 2636
},

"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
"category": "Error",
Expand Down
1 change: 1 addition & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,7 @@ namespace ts {
//

function emitTypeParameter(node: TypeParameterDeclaration) {
emitModifiers(node, node.modifiers);
emit(node.name);
if (node.constraint) {
writeSpace();
Expand Down
47 changes: 42 additions & 5 deletions src/compiler/factory/nodeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,8 @@ namespace ts {
case SyntaxKind.BigIntKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.InKeyword:
case SyntaxKind.OutKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.BooleanKeyword:
Expand Down Expand Up @@ -1077,6 +1079,8 @@ namespace ts {
if (flags & ModifierFlags.Override) result.push(createModifier(SyntaxKind.OverrideKeyword));
if (flags & ModifierFlags.Readonly) result.push(createModifier(SyntaxKind.ReadonlyKeyword));
if (flags & ModifierFlags.Async) result.push(createModifier(SyntaxKind.AsyncKeyword));
if (flags & ModifierFlags.In) result.push(createModifier(SyntaxKind.InKeyword));
if (flags & ModifierFlags.Out) result.push(createModifier(SyntaxKind.OutKeyword));
return result.length ? result : undefined;
}

Expand Down Expand Up @@ -1126,11 +1130,27 @@ namespace ts {
//

// @api
function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
function createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration;
/** @deprecated */
function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration;
function createTypeParameterDeclaration(modifiersOrName: readonly Modifier[] | string | Identifier | undefined , nameOrConstraint?: string | Identifier | TypeNode, constraintOrDefault?: TypeNode, defaultType?: TypeNode) {
let name;
let modifiers;
let constraint;
if (modifiersOrName === undefined || isArray(modifiersOrName)) {
modifiers = modifiersOrName;
name = nameOrConstraint as string | Identifier;
constraint = constraintOrDefault;
}
else {
modifiers = undefined;
name = modifiersOrName;
constraint = nameOrConstraint as TypeNode | undefined;
}
const node = createBaseNamedDeclaration<TypeParameterDeclaration>(
SyntaxKind.TypeParameter,
/*decorators*/ undefined,
/*modifiers*/ undefined,
modifiers,
name
);
node.constraint = constraint;
Expand All @@ -1140,11 +1160,28 @@ namespace ts {
}

// @api
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
return node.name !== name
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration;
/** @deprecated */
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration;
function updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiersOrName: readonly Modifier[] | Identifier | undefined, nameOrConstraint: Identifier | TypeNode | undefined, constraintOrDefault: TypeNode | undefined, defaultType?: TypeNode | undefined) {
let name;
let modifiers;
let constraint;
if (modifiersOrName === undefined || isArray(modifiersOrName)) {
modifiers = modifiersOrName;
name = nameOrConstraint as Identifier;
constraint = constraintOrDefault;
}
else {
modifiers = undefined;
name = modifiersOrName;
constraint = nameOrConstraint as TypeNode | undefined;
}
return node.modifiers !== modifiers
|| node.name !== name
|| node.constraint !== constraint
|| node.default !== defaultType
? update(createTypeParameterDeclaration(name, constraint, defaultType), node)
? update(createTypeParameterDeclaration(modifiers, name, constraint, defaultType), node)
: node;
}

Expand Down
13 changes: 8 additions & 5 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ namespace ts {
return visitNode(cbNode, (node as QualifiedName).left) ||
visitNode(cbNode, (node as QualifiedName).right);
case SyntaxKind.TypeParameter:
return visitNode(cbNode, (node as TypeParameterDeclaration).name) ||
return visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (node as TypeParameterDeclaration).name) ||
visitNode(cbNode, (node as TypeParameterDeclaration).constraint) ||
visitNode(cbNode, (node as TypeParameterDeclaration).default) ||
visitNode(cbNode, (node as TypeParameterDeclaration).expression);
Expand Down Expand Up @@ -2176,7 +2177,7 @@ namespace ts {
case ParsingContext.ArrayBindingElements:
return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();
case ParsingContext.TypeParameters:
return isIdentifier();
return token() === SyntaxKind.InKeyword || isIdentifier();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why in but not out ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... oh because in is a JS keyword but out isn't

case ParsingContext.ArrayLiteralMembers:
switch (token()) {
case SyntaxKind.CommaToken:
Expand Down Expand Up @@ -3176,6 +3177,7 @@ namespace ts {

function parseTypeParameter(): TypeParameterDeclaration {
const pos = getNodePos();
const modifiers = parseModifiers();
const name = parseIdentifier();
let constraint: TypeNode | undefined;
let expression: Expression | undefined;
Expand All @@ -3200,7 +3202,7 @@ namespace ts {
}

const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined;
const node = factory.createTypeParameterDeclaration(name, constraint, defaultType);
const node = factory.createTypeParameterDeclaration(modifiers, name, constraint, defaultType);
node.expression = expression;
return finishNode(node, pos);
}
Expand Down Expand Up @@ -3605,7 +3607,7 @@ namespace ts {
const name = parseIdentifierName();
parseExpected(SyntaxKind.InKeyword);
const type = parseType();
return finishNode(factory.createTypeParameterDeclaration(name, type, /*defaultType*/ undefined), pos);
return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos);
}

function parseMappedType() {
Expand Down Expand Up @@ -3961,6 +3963,7 @@ namespace ts {
const pos = getNodePos();
return finishNode(
factory.createTypeParameterDeclaration(
/*modifiers*/ undefined,
parseIdentifier(),
/*constraint*/ undefined,
/*defaultType*/ undefined
Expand Down Expand Up @@ -8656,7 +8659,7 @@ namespace ts {
if (nodeIsMissing(name)) {
return undefined;
}
return finishNode(factory.createTypeParameterDeclaration(name, /*constraint*/ undefined, defaultType), typeParameterPos);
return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos);
}

function parseTemplateTagTypeParameters() {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2414,6 +2414,8 @@ namespace ts {
case SyntaxKind.DeclareKeyword:
case SyntaxKind.AbstractKeyword:
case SyntaxKind.OverrideKeyword:
case SyntaxKind.InKeyword:
case SyntaxKind.OutKeyword:
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind)));
break;

Expand Down
1 change: 1 addition & 0 deletions src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ namespace ts {
protected: SyntaxKind.ProtectedKeyword,
public: SyntaxKind.PublicKeyword,
override: SyntaxKind.OverrideKeyword,
out: SyntaxKind.OutKeyword,
readonly: SyntaxKind.ReadonlyKeyword,
require: SyntaxKind.RequireKeyword,
global: SyntaxKind.GlobalKeyword,
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ namespace ts {
}
case SyntaxKind.TypeParameter: {
if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) {
return cleanup(factory.updateTypeParameterDeclaration(input, input.name, /*constraint*/ undefined, /*defaultType*/ undefined));
return cleanup(factory.updateTypeParameterDeclaration(input, input.modifiers, input.name, /*constraint*/ undefined, /*defaultType*/ undefined));
}
return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
}
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ namespace ts {
case SyntaxKind.ConstKeyword:
case SyntaxKind.DeclareKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.InKeyword:
case SyntaxKind.OutKeyword:
// TypeScript accessibility and readonly modifiers are elided
// falls through
case SyntaxKind.ArrayType:
Expand Down
Loading