Skip to content

Commit ed8b764

Browse files
Kingwlweswigham
authored andcommitted
add grammar check for labeled declaration (microsoft#25317)
* add grammar check for labeled function declaration * fix debug failed on labeled class declaration * move labeled statement check to binder and add more pattern for check * update diagnostic message * update baseline
1 parent 2701f78 commit ed8b764

18 files changed

+608
-1
lines changed

src/compiler/binder.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,15 @@ namespace ts {
19181918
}
19191919
}
19201920

1921+
function checkStrictModeLabeledStatement(node: LabeledStatement) {
1922+
// Grammar checking for labeledStatement
1923+
if (inStrictMode && options.target! >= ScriptTarget.ES2015) {
1924+
if (isDeclarationStatement(node.statement) || isVariableStatement(node.statement)) {
1925+
errorOnFirstToken(node.label, Diagnostics.A_label_is_not_allowed_here);
1926+
}
1927+
}
1928+
}
1929+
19211930
function errorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) {
19221931
const span = getSpanOfTokenAtPosition(file, node.pos);
19231932
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
@@ -2104,6 +2113,8 @@ namespace ts {
21042113
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
21052114
case SyntaxKind.WithStatement:
21062115
return checkStrictModeWithStatement(<WithStatement>node);
2116+
case SyntaxKind.LabeledStatement:
2117+
return checkStrictModeLabeledStatement(<LabeledStatement>node);
21072118
case SyntaxKind.ThisType:
21082119
seenThisKeyword = true;
21092120
return;

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,10 @@
983983
"category": "Error",
984984
"code": 1343
985985
},
986+
"'A label is not allowed here.": {
987+
"category": "Error",
988+
"code": 1344
989+
},
986990

987991
"Duplicate identifier '{0}'.": {
988992
"category": "Error",

src/compiler/transformers/es2015.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2207,7 +2207,7 @@ namespace ts {
22072207
const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel);
22082208
return isIterationStatement(statement, /*lookInLabeledStatements*/ false)
22092209
? visitIterationStatement(statement, /*outermostLabeledStatement*/ node)
2210-
: restoreEnclosingLabel(visitNode(statement, visitor, isStatement), node, convertedLoopState && resetLabel);
2210+
: restoreEnclosingLabel(visitNode(statement, visitor, isStatement, liftToBlock), node, convertedLoopState && resetLabel);
22112211
}
22122212

22132213
function visitIterationStatement(node: IterationStatement, outermostLabeledStatement: LabeledStatement) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel.ts(11,8): error TS1235: A namespace declaration is only allowed in a namespace or module.
2+
tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel.ts(12,8): error TS1235: A namespace declaration is only allowed in a namespace or module.
3+
4+
5+
==== tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel.ts (2 errors) ====
6+
label: function fn() { }
7+
label: function* gen() { }
8+
label: async function gen1() { }
9+
label: enum E {}
10+
label: interface I {}
11+
label: class C { }
12+
label: var a = 1;
13+
label: let b = 1;
14+
label: const c = 1;
15+
16+
label: module M { }
17+
~~~~~~
18+
!!! error TS1235: A namespace declaration is only allowed in a namespace or module.
19+
label: namespace N {}
20+
~~~~~~~~~
21+
!!! error TS1235: A namespace declaration is only allowed in a namespace or module.
22+
label: type T = {}
23+
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//// [labeledStatementWithLabel.ts]
2+
label: function fn() { }
3+
label: function* gen() { }
4+
label: async function gen1() { }
5+
label: enum E {}
6+
label: interface I {}
7+
label: class C { }
8+
label: var a = 1;
9+
label: let b = 1;
10+
label: const c = 1;
11+
12+
label: module M { }
13+
label: namespace N {}
14+
label: type T = {}
15+
16+
17+
//// [labeledStatementWithLabel.js]
18+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
19+
return new (P || (P = Promise))(function (resolve, reject) {
20+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
23+
step((generator = generator.apply(thisArg, _arguments || [])).next());
24+
});
25+
};
26+
var __generator = (this && this.__generator) || function (thisArg, body) {
27+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29+
function verb(n) { return function (v) { return step([n, v]); }; }
30+
function step(op) {
31+
if (f) throw new TypeError("Generator is already executing.");
32+
while (_) try {
33+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34+
if (y = 0, t) op = [op[0] & 2, t.value];
35+
switch (op[0]) {
36+
case 0: case 1: t = op; break;
37+
case 4: _.label++; return { value: op[1], done: false };
38+
case 5: _.label++; y = op[1]; op = [0]; continue;
39+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
40+
default:
41+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45+
if (t[2]) _.ops.pop();
46+
_.trys.pop(); continue;
47+
}
48+
op = body.call(thisArg, _);
49+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51+
}
52+
};
53+
label: function fn() { }
54+
label: function gen() { return __generator(this, function (_a) {
55+
return [2 /*return*/];
56+
}); }
57+
label: function gen1() {
58+
return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
59+
return [2 /*return*/];
60+
}); });
61+
}
62+
label: {
63+
var E;
64+
(function (E) {
65+
})(E || (E = {}));
66+
}
67+
label:
68+
label: {
69+
var C = /** @class */ (function () {
70+
function C() {
71+
}
72+
return C;
73+
}());
74+
}
75+
label: var a = 1;
76+
label: var b = 1;
77+
label: var c = 1;
78+
label:
79+
label:
80+
label:
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel.ts ===
2+
label: function fn() { }
3+
>fn : Symbol(fn, Decl(labeledStatementWithLabel.ts, 0, 6))
4+
5+
label: function* gen() { }
6+
>gen : Symbol(gen, Decl(labeledStatementWithLabel.ts, 1, 6))
7+
8+
label: async function gen1() { }
9+
>gen1 : Symbol(gen1, Decl(labeledStatementWithLabel.ts, 2, 6))
10+
11+
label: enum E {}
12+
>E : Symbol(E, Decl(labeledStatementWithLabel.ts, 3, 6))
13+
14+
label: interface I {}
15+
>I : Symbol(I, Decl(labeledStatementWithLabel.ts, 4, 6))
16+
17+
label: class C { }
18+
>C : Symbol(C, Decl(labeledStatementWithLabel.ts, 5, 6))
19+
20+
label: var a = 1;
21+
>a : Symbol(a, Decl(labeledStatementWithLabel.ts, 6, 10))
22+
23+
label: let b = 1;
24+
>b : Symbol(b, Decl(labeledStatementWithLabel.ts, 7, 10))
25+
26+
label: const c = 1;
27+
>c : Symbol(c, Decl(labeledStatementWithLabel.ts, 8, 12))
28+
29+
label: module M { }
30+
>M : Symbol(M, Decl(labeledStatementWithLabel.ts, 10, 6))
31+
32+
label: namespace N {}
33+
>N : Symbol(N, Decl(labeledStatementWithLabel.ts, 11, 6))
34+
35+
label: type T = {}
36+
>T : Symbol(T, Decl(labeledStatementWithLabel.ts, 12, 6))
37+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
=== tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel.ts ===
2+
label: function fn() { }
3+
>label : any
4+
>fn : () => void
5+
6+
label: function* gen() { }
7+
>label : any
8+
>gen : () => IterableIterator<any>
9+
10+
label: async function gen1() { }
11+
>label : any
12+
>gen1 : () => Promise<void>
13+
14+
label: enum E {}
15+
>label : any
16+
>E : E
17+
18+
label: interface I {}
19+
>label : any
20+
>I : I
21+
22+
label: class C { }
23+
>label : any
24+
>C : C
25+
26+
label: var a = 1;
27+
>label : any
28+
>a : number
29+
>1 : 1
30+
31+
label: let b = 1;
32+
>label : any
33+
>b : number
34+
>1 : 1
35+
36+
label: const c = 1;
37+
>label : any
38+
>c : 1
39+
>1 : 1
40+
41+
label: module M { }
42+
>label : any
43+
>M : any
44+
45+
label: namespace N {}
46+
>label : any
47+
>N : any
48+
49+
label: type T = {}
50+
>label : any
51+
>T : {}
52+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel_es2015.ts(11,8): error TS1235: A namespace declaration is only allowed in a namespace or module.
2+
tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel_es2015.ts(12,8): error TS1235: A namespace declaration is only allowed in a namespace or module.
3+
4+
5+
==== tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel_es2015.ts (2 errors) ====
6+
label: function fn() { }
7+
label: function* gen() { }
8+
label: async function gen1() { }
9+
label: enum E {}
10+
label: interface I {}
11+
label: class C { }
12+
label: var a = 1;
13+
label: let b = 1;
14+
label: const c = 1;
15+
16+
label: module M { }
17+
~~~~~~
18+
!!! error TS1235: A namespace declaration is only allowed in a namespace or module.
19+
label: namespace N {}
20+
~~~~~~~~~
21+
!!! error TS1235: A namespace declaration is only allowed in a namespace or module.
22+
label: type T = {}
23+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [labeledStatementWithLabel_es2015.ts]
2+
label: function fn() { }
3+
label: function* gen() { }
4+
label: async function gen1() { }
5+
label: enum E {}
6+
label: interface I {}
7+
label: class C { }
8+
label: var a = 1;
9+
label: let b = 1;
10+
label: const c = 1;
11+
12+
label: module M { }
13+
label: namespace N {}
14+
label: type T = {}
15+
16+
17+
//// [labeledStatementWithLabel_es2015.js]
18+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
19+
return new (P || (P = Promise))(function (resolve, reject) {
20+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
23+
step((generator = generator.apply(thisArg, _arguments || [])).next());
24+
});
25+
};
26+
label: function fn() { }
27+
label: function* gen() { }
28+
label: function gen1() {
29+
return __awaiter(this, void 0, void 0, function* () { });
30+
}
31+
label: {
32+
var E;
33+
(function (E) {
34+
})(E || (E = {}));
35+
}
36+
label:
37+
label: class C {
38+
}
39+
label: var a = 1;
40+
label: let b = 1;
41+
label: const c = 1;
42+
label:
43+
label:
44+
label:
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
=== tests/cases/conformance/statements/labeledStatements/labeledStatementWithLabel_es2015.ts ===
2+
label: function fn() { }
3+
>fn : Symbol(fn, Decl(labeledStatementWithLabel_es2015.ts, 0, 6))
4+
5+
label: function* gen() { }
6+
>gen : Symbol(gen, Decl(labeledStatementWithLabel_es2015.ts, 1, 6))
7+
8+
label: async function gen1() { }
9+
>gen1 : Symbol(gen1, Decl(labeledStatementWithLabel_es2015.ts, 2, 6))
10+
11+
label: enum E {}
12+
>E : Symbol(E, Decl(labeledStatementWithLabel_es2015.ts, 3, 6))
13+
14+
label: interface I {}
15+
>I : Symbol(I, Decl(labeledStatementWithLabel_es2015.ts, 4, 6))
16+
17+
label: class C { }
18+
>C : Symbol(C, Decl(labeledStatementWithLabel_es2015.ts, 5, 6))
19+
20+
label: var a = 1;
21+
>a : Symbol(a, Decl(labeledStatementWithLabel_es2015.ts, 6, 10))
22+
23+
label: let b = 1;
24+
>b : Symbol(b, Decl(labeledStatementWithLabel_es2015.ts, 7, 10))
25+
26+
label: const c = 1;
27+
>c : Symbol(c, Decl(labeledStatementWithLabel_es2015.ts, 8, 12))
28+
29+
label: module M { }
30+
>M : Symbol(M, Decl(labeledStatementWithLabel_es2015.ts, 10, 6))
31+
32+
label: namespace N {}
33+
>N : Symbol(N, Decl(labeledStatementWithLabel_es2015.ts, 11, 6))
34+
35+
label: type T = {}
36+
>T : Symbol(T, Decl(labeledStatementWithLabel_es2015.ts, 12, 6))
37+

0 commit comments

Comments
 (0)