Skip to content

Commit dc78c4f

Browse files
committed
improve parser and error message if definite assignment assertions in object short hand
1 parent 92dfde0 commit dc78c4f

10 files changed

+102
-3
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26871,12 +26871,18 @@ namespace ts {
2687126871
}
2687226872
}
2687326873

26874-
function checkGrammarForInvalidQuestionMark(questionToken: Node, message: DiagnosticMessage): boolean {
26874+
function checkGrammarForInvalidQuestionMark(questionToken: QuestionToken, message: DiagnosticMessage): boolean {
2687526875
if (questionToken) {
2687626876
return grammarErrorOnNode(questionToken, message);
2687726877
}
2687826878
}
2687926879

26880+
function checkGrammarForInvalidExclamationToken(exclamationToken: ExclamationToken, message: DiagnosticMessage): boolean {
26881+
if (exclamationToken) {
26882+
return grammarErrorOnNode(exclamationToken, message);
26883+
}
26884+
}
26885+
2688026886
function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) {
2688126887
const enum Flags {
2688226888
Property = 1,
@@ -26921,8 +26927,10 @@ namespace ts {
2692126927
// and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields
2692226928
let currentKind: Flags;
2692326929
switch (prop.kind) {
26924-
case SyntaxKind.PropertyAssignment:
2692526930
case SyntaxKind.ShorthandPropertyAssignment:
26931+
checkGrammarForInvalidExclamationToken(prop.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context);
26932+
/* tslint:disable:no-switch-case-fall-through */
26933+
case SyntaxKind.PropertyAssignment:
2692626934
// Grammar checking for computedPropertyName and shorthandPropertyAssignment
2692726935
checkGrammarForInvalidQuestionMark(prop.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional);
2692826936
if (name.kind === SyntaxKind.NumericLiteral) {
@@ -27162,6 +27170,9 @@ namespace ts {
2716227170
else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) {
2716327171
return true;
2716427172
}
27173+
else if (checkGrammarForInvalidExclamationToken(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context)) {
27174+
return true;
27175+
}
2716527176
else if (node.body === undefined) {
2716627177
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
2716727178
}

src/compiler/parser.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ namespace ts {
9090
visitNodes(cbNode, cbNodes, node.modifiers) ||
9191
visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) ||
9292
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
93+
visitNode(cbNode, (<ShorthandPropertyAssignment>node).exclamationToken) ||
9394
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
9495
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
9596
case SyntaxKind.SpreadAssignment:
@@ -160,6 +161,7 @@ namespace ts {
160161
visitNode(cbNode, (<FunctionLikeDeclaration>node).asteriskToken) ||
161162
visitNode(cbNode, (<FunctionLikeDeclaration>node).name) ||
162163
visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) ||
164+
visitNode(cbNode, (<FunctionLikeDeclaration>node).exclamationToken) ||
163165
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
164166
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
165167
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
@@ -4580,8 +4582,10 @@ namespace ts {
45804582
const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
45814583
const tokenIsIdentifier = isIdentifier();
45824584
node.name = parsePropertyName();
4583-
// Disallowing of optional property assignments happens in the grammar checker.
4585+
// Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
45844586
(<MethodDeclaration>node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
4587+
(<MethodDeclaration>node).exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
4588+
45854589
if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
45864590
return parseMethodDeclaration(<MethodDeclaration>node, asteriskToken);
45874591
}

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,7 @@ namespace ts {
912912
kind: SyntaxKind.ShorthandPropertyAssignment;
913913
name: Identifier;
914914
questionToken?: QuestionToken;
915+
exclamationToken?: ExclamationToken;
915916
// used when ObjectLiteralExpression is used in ObjectAssignmentPattern
916917
// it is grammar error to appear in actual object initializer
917918
equalsToken?: Token<SyntaxKind.EqualsToken>;
@@ -970,6 +971,7 @@ namespace ts {
970971

971972
asteriskToken?: AsteriskToken;
972973
questionToken?: QuestionToken;
974+
exclamationToken?: ExclamationToken;
973975
body?: Block | Expression;
974976
}
975977

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ declare namespace ts {
608608
kind: SyntaxKind.ShorthandPropertyAssignment;
609609
name: Identifier;
610610
questionToken?: QuestionToken;
611+
exclamationToken?: ExclamationToken;
611612
equalsToken?: Token<SyntaxKind.EqualsToken>;
612613
objectAssignmentInitializer?: Expression;
613614
}
@@ -644,6 +645,7 @@ declare namespace ts {
644645
_functionLikeDeclarationBrand: any;
645646
asteriskToken?: AsteriskToken;
646647
questionToken?: QuestionToken;
648+
exclamationToken?: ExclamationToken;
647649
body?: Block | Expression;
648650
}
649651
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ declare namespace ts {
608608
kind: SyntaxKind.ShorthandPropertyAssignment;
609609
name: Identifier;
610610
questionToken?: QuestionToken;
611+
exclamationToken?: ExclamationToken;
611612
equalsToken?: Token<SyntaxKind.EqualsToken>;
612613
objectAssignmentInitializer?: Expression;
613614
}
@@ -644,6 +645,7 @@ declare namespace ts {
644645
_functionLikeDeclarationBrand: any;
645646
asteriskToken?: AsteriskToken;
646647
questionToken?: QuestionToken;
648+
exclamationToken?: ExclamationToken;
647649
body?: Block | Expression;
648650
}
649651
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tests/cases/conformance/controlFlow/definiteAssignmentAssertionsWithObjectShortHand.ts(2,16): error TS1255: A definite assignment assertion '!' is not permitted in this context.
2+
tests/cases/conformance/controlFlow/definiteAssignmentAssertionsWithObjectShortHand.ts(5,7): error TS1162: An object member cannot be declared optional.
3+
4+
5+
==== tests/cases/conformance/controlFlow/definiteAssignmentAssertionsWithObjectShortHand.ts (2 errors) ====
6+
const a: string | undefined = 'ff';
7+
const foo = { a! }
8+
~
9+
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
10+
11+
const bar = {
12+
a ? () { }
13+
~
14+
!!! error TS1162: An object member cannot be declared optional.
15+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [definiteAssignmentAssertionsWithObjectShortHand.ts]
2+
const a: string | undefined = 'ff';
3+
const foo = { a! }
4+
5+
const bar = {
6+
a ? () { }
7+
}
8+
9+
//// [definiteAssignmentAssertionsWithObjectShortHand.js]
10+
"use strict";
11+
var a = 'ff';
12+
var foo = { a: a };
13+
var bar = {
14+
a: function () { }
15+
};
16+
17+
18+
//// [definiteAssignmentAssertionsWithObjectShortHand.d.ts]
19+
declare const a: string | undefined;
20+
declare const foo: {
21+
a: string;
22+
};
23+
declare const bar: {};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/conformance/controlFlow/definiteAssignmentAssertionsWithObjectShortHand.ts ===
2+
const a: string | undefined = 'ff';
3+
>a : Symbol(a, Decl(definiteAssignmentAssertionsWithObjectShortHand.ts, 0, 5))
4+
5+
const foo = { a! }
6+
>foo : Symbol(foo, Decl(definiteAssignmentAssertionsWithObjectShortHand.ts, 1, 5))
7+
>a : Symbol(a, Decl(definiteAssignmentAssertionsWithObjectShortHand.ts, 1, 13))
8+
9+
const bar = {
10+
>bar : Symbol(bar, Decl(definiteAssignmentAssertionsWithObjectShortHand.ts, 3, 5))
11+
12+
a ? () { }
13+
>a : Symbol(a, Decl(definiteAssignmentAssertionsWithObjectShortHand.ts, 3, 13))
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/controlFlow/definiteAssignmentAssertionsWithObjectShortHand.ts ===
2+
const a: string | undefined = 'ff';
3+
>a : string | undefined
4+
>'ff' : "ff"
5+
6+
const foo = { a! }
7+
>foo : { a: string; }
8+
>{ a! } : { a: string; }
9+
>a : string
10+
11+
const bar = {
12+
>bar : {}
13+
>{ a ? () { }} : {}
14+
15+
a ? () { }
16+
>a : (() => void) | undefined
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @strict: true
2+
// @declaration: true
3+
4+
const a: string | undefined = 'ff';
5+
const foo = { a! }
6+
7+
const bar = {
8+
a ? () { }
9+
}

0 commit comments

Comments
 (0)