Skip to content

Commit 5d65e86

Browse files
Merge pull request #23253 from Kingwl/definite-assignment-assertion-improve
improve parser and error message if definite assignment assertions in…
2 parents 4975dc8 + c531065 commit 5d65e86

10 files changed

+100
-3
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29024,10 +29024,14 @@ namespace ts {
2902429024
}
2902529025
}
2902629026

29027-
function checkGrammarForInvalidQuestionMark(questionToken: Node | undefined, message: DiagnosticMessage): boolean {
29027+
function checkGrammarForInvalidQuestionMark(questionToken: QuestionToken | undefined, message: DiagnosticMessage): boolean {
2902829028
return !!questionToken && grammarErrorOnNode(questionToken, message);
2902929029
}
2903029030

29031+
function checkGrammarForInvalidExclamationToken(exclamationToken: ExclamationToken | undefined, message: DiagnosticMessage): boolean {
29032+
return !!exclamationToken && grammarErrorOnNode(exclamationToken, message);
29033+
}
29034+
2903129035
function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) {
2903229036
const enum Flags {
2903329037
Property = 1,
@@ -29072,8 +29076,10 @@ namespace ts {
2907229076
// and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields
2907329077
let currentKind: Flags;
2907429078
switch (prop.kind) {
29075-
case SyntaxKind.PropertyAssignment:
2907629079
case SyntaxKind.ShorthandPropertyAssignment:
29080+
checkGrammarForInvalidExclamationToken(prop.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context);
29081+
/* tslint:disable:no-switch-case-fall-through */
29082+
case SyntaxKind.PropertyAssignment:
2907729083
// Grammar checking for computedPropertyName and shorthandPropertyAssignment
2907829084
checkGrammarForInvalidQuestionMark(prop.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional);
2907929085
if (name.kind === SyntaxKind.NumericLiteral) {
@@ -29314,6 +29320,9 @@ namespace ts {
2931429320
else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) {
2931529321
return true;
2931629322
}
29323+
else if (checkGrammarForInvalidExclamationToken(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context)) {
29324+
return true;
29325+
}
2931729326
else if (node.body === undefined) {
2931829327
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
2931929328
}

src/compiler/parser.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ namespace ts {
8686
visitNodes(cbNode, cbNodes, node.modifiers) ||
8787
visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) ||
8888
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
89+
visitNode(cbNode, (<ShorthandPropertyAssignment>node).exclamationToken) ||
8990
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
9091
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
9192
case SyntaxKind.SpreadAssignment:
@@ -156,6 +157,7 @@ namespace ts {
156157
visitNode(cbNode, (<FunctionLikeDeclaration>node).asteriskToken) ||
157158
visitNode(cbNode, (<FunctionLikeDeclaration>node).name) ||
158159
visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) ||
160+
visitNode(cbNode, (<FunctionLikeDeclaration>node).exclamationToken) ||
159161
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
160162
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
161163
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
@@ -4713,8 +4715,10 @@ namespace ts {
47134715
const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
47144716
const tokenIsIdentifier = isIdentifier();
47154717
node.name = parsePropertyName();
4716-
// Disallowing of optional property assignments happens in the grammar checker.
4718+
// Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
47174719
(<MethodDeclaration>node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
4720+
(<MethodDeclaration>node).exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
4721+
47184722
if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
47194723
return parseMethodDeclaration(<MethodDeclaration>node, asteriskToken);
47204724
}

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,7 @@ namespace ts {
883883
kind: SyntaxKind.ShorthandPropertyAssignment;
884884
name: Identifier;
885885
questionToken?: QuestionToken;
886+
exclamationToken?: ExclamationToken;
886887
// used when ObjectLiteralExpression is used in ObjectAssignmentPattern
887888
// it is grammar error to appear in actual object initializer
888889
equalsToken?: Token<SyntaxKind.EqualsToken>;
@@ -941,6 +942,7 @@ namespace ts {
941942

942943
asteriskToken?: AsteriskToken;
943944
questionToken?: QuestionToken;
945+
exclamationToken?: ExclamationToken;
944946
body?: Block | Expression;
945947
}
946948

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,7 @@ declare namespace ts {
632632
kind: SyntaxKind.ShorthandPropertyAssignment;
633633
name: Identifier;
634634
questionToken?: QuestionToken;
635+
exclamationToken?: ExclamationToken;
635636
equalsToken?: Token<SyntaxKind.EqualsToken>;
636637
objectAssignmentInitializer?: Expression;
637638
}
@@ -668,6 +669,7 @@ declare namespace ts {
668669
_functionLikeDeclarationBrand: any;
669670
asteriskToken?: AsteriskToken;
670671
questionToken?: QuestionToken;
672+
exclamationToken?: ExclamationToken;
671673
body?: Block | Expression;
672674
}
673675
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
@@ -632,6 +632,7 @@ declare namespace ts {
632632
kind: SyntaxKind.ShorthandPropertyAssignment;
633633
name: Identifier;
634634
questionToken?: QuestionToken;
635+
exclamationToken?: ExclamationToken;
635636
equalsToken?: Token<SyntaxKind.EqualsToken>;
636637
objectAssignmentInitializer?: Expression;
637638
}
@@ -668,6 +669,7 @@ declare namespace ts {
668669
_functionLikeDeclarationBrand: any;
669670
asteriskToken?: AsteriskToken;
670671
questionToken?: QuestionToken;
672+
exclamationToken?: ExclamationToken;
671673
body?: Block | Expression;
672674
}
673675
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)