Skip to content

Commit 013744b

Browse files
author
Andy
authored
Merge pull request #9994 from Microsoft/local_abstract_class
Allow an abstract class to appear in a local scope
2 parents 0c131fa + a25b664 commit 013744b

8 files changed

+184
-44
lines changed

src/compiler/checker.ts

+58-44
Original file line numberDiff line numberDiff line change
@@ -18625,50 +18625,9 @@ namespace ts {
1862518625
}
1862618626

1862718627
function checkGrammarModifiers(node: Node): boolean {
18628-
switch (node.kind) {
18629-
case SyntaxKind.GetAccessor:
18630-
case SyntaxKind.SetAccessor:
18631-
case SyntaxKind.Constructor:
18632-
case SyntaxKind.PropertyDeclaration:
18633-
case SyntaxKind.PropertySignature:
18634-
case SyntaxKind.MethodDeclaration:
18635-
case SyntaxKind.MethodSignature:
18636-
case SyntaxKind.IndexSignature:
18637-
case SyntaxKind.ModuleDeclaration:
18638-
case SyntaxKind.ImportDeclaration:
18639-
case SyntaxKind.ImportEqualsDeclaration:
18640-
case SyntaxKind.ExportDeclaration:
18641-
case SyntaxKind.ExportAssignment:
18642-
case SyntaxKind.FunctionExpression:
18643-
case SyntaxKind.ArrowFunction:
18644-
case SyntaxKind.Parameter:
18645-
break;
18646-
case SyntaxKind.FunctionDeclaration:
18647-
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.AsyncKeyword) &&
18648-
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
18649-
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
18650-
}
18651-
break;
18652-
case SyntaxKind.ClassDeclaration:
18653-
case SyntaxKind.InterfaceDeclaration:
18654-
case SyntaxKind.VariableStatement:
18655-
case SyntaxKind.TypeAliasDeclaration:
18656-
if (node.modifiers && node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
18657-
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
18658-
}
18659-
break;
18660-
case SyntaxKind.EnumDeclaration:
18661-
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.ConstKeyword) &&
18662-
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
18663-
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
18664-
}
18665-
break;
18666-
default:
18667-
return false;
18668-
}
18669-
18670-
if (!node.modifiers) {
18671-
return;
18628+
const quickResult = reportObviousModifierErrors(node);
18629+
if (quickResult !== undefined) {
18630+
return quickResult;
1867218631
}
1867318632

1867418633
let lastStatic: Node, lastPrivate: Node, lastProtected: Node, lastDeclare: Node, lastAsync: Node, lastReadonly: Node;
@@ -18873,6 +18832,61 @@ namespace ts {
1887318832
}
1887418833
}
1887518834

18835+
/**
18836+
* true | false: Early return this value from checkGrammarModifiers.
18837+
* undefined: Need to do full checking on the modifiers.
18838+
*/
18839+
function reportObviousModifierErrors(node: Node): boolean | undefined {
18840+
return !node.modifiers
18841+
? false
18842+
: shouldReportBadModifier(node)
18843+
? grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here)
18844+
: undefined;
18845+
}
18846+
function shouldReportBadModifier(node: Node): boolean {
18847+
switch (node.kind) {
18848+
case SyntaxKind.GetAccessor:
18849+
case SyntaxKind.SetAccessor:
18850+
case SyntaxKind.Constructor:
18851+
case SyntaxKind.PropertyDeclaration:
18852+
case SyntaxKind.PropertySignature:
18853+
case SyntaxKind.MethodDeclaration:
18854+
case SyntaxKind.MethodSignature:
18855+
case SyntaxKind.IndexSignature:
18856+
case SyntaxKind.ModuleDeclaration:
18857+
case SyntaxKind.ImportDeclaration:
18858+
case SyntaxKind.ImportEqualsDeclaration:
18859+
case SyntaxKind.ExportDeclaration:
18860+
case SyntaxKind.ExportAssignment:
18861+
case SyntaxKind.FunctionExpression:
18862+
case SyntaxKind.ArrowFunction:
18863+
case SyntaxKind.Parameter:
18864+
return false;
18865+
default:
18866+
if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
18867+
return false;
18868+
}
18869+
switch (node.kind) {
18870+
case SyntaxKind.FunctionDeclaration:
18871+
return nodeHasAnyModifiersExcept(node, SyntaxKind.AsyncKeyword);
18872+
case SyntaxKind.ClassDeclaration:
18873+
return nodeHasAnyModifiersExcept(node, SyntaxKind.AbstractKeyword);
18874+
case SyntaxKind.InterfaceDeclaration:
18875+
case SyntaxKind.VariableStatement:
18876+
case SyntaxKind.TypeAliasDeclaration:
18877+
return true;
18878+
case SyntaxKind.EnumDeclaration:
18879+
return nodeHasAnyModifiersExcept(node, SyntaxKind.ConstKeyword);
18880+
default:
18881+
Debug.fail();
18882+
return false;
18883+
}
18884+
}
18885+
}
18886+
function nodeHasAnyModifiersExcept(node: Node, allowedModifier: SyntaxKind): boolean {
18887+
return node.modifiers.length > 1 || node.modifiers[0].kind !== allowedModifier;
18888+
}
18889+
1887618890
function checkGrammarAsyncModifier(node: Node, asyncModifier: Node): boolean {
1887718891
if (languageVersion < ScriptTarget.ES6) {
1887818892
return grammarErrorOnNode(asyncModifier, Diagnostics.Async_functions_are_only_available_when_targeting_ECMAScript_2015_or_higher);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [abstractClassInLocalScope.ts]
2+
(() => {
3+
abstract class A {}
4+
class B extends A {}
5+
new B();
6+
return A;
7+
})();
8+
9+
10+
//// [abstractClassInLocalScope.js]
11+
var __extends = (this && this.__extends) || function (d, b) {
12+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
13+
function __() { this.constructor = d; }
14+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15+
};
16+
(function () {
17+
var A = (function () {
18+
function A() {
19+
}
20+
return A;
21+
}());
22+
var B = (function (_super) {
23+
__extends(B, _super);
24+
function B() {
25+
_super.apply(this, arguments);
26+
}
27+
return B;
28+
}(A));
29+
new B();
30+
return A;
31+
})();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/compiler/abstractClassInLocalScope.ts ===
2+
(() => {
3+
abstract class A {}
4+
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
5+
6+
class B extends A {}
7+
>B : Symbol(B, Decl(abstractClassInLocalScope.ts, 1, 23))
8+
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
9+
10+
new B();
11+
>B : Symbol(B, Decl(abstractClassInLocalScope.ts, 1, 23))
12+
13+
return A;
14+
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
15+
16+
})();
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/abstractClassInLocalScope.ts ===
2+
(() => {
3+
>(() => { abstract class A {} class B extends A {} new B(); return A;})() : typeof A
4+
>(() => { abstract class A {} class B extends A {} new B(); return A;}) : () => typeof A
5+
>() => { abstract class A {} class B extends A {} new B(); return A;} : () => typeof A
6+
7+
abstract class A {}
8+
>A : A
9+
10+
class B extends A {}
11+
>B : B
12+
>A : A
13+
14+
new B();
15+
>new B() : B
16+
>B : typeof B
17+
18+
return A;
19+
>A : typeof A
20+
21+
})();
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts(4,5): error TS2511: Cannot create an instance of the abstract class 'A'.
2+
3+
4+
==== tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts (1 errors) ====
5+
(() => {
6+
abstract class A {}
7+
class B extends A {}
8+
new A();
9+
~~~~~~~
10+
!!! error TS2511: Cannot create an instance of the abstract class 'A'.
11+
new B();
12+
})()
13+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [abstractClassInLocalScopeIsAbstract.ts]
2+
(() => {
3+
abstract class A {}
4+
class B extends A {}
5+
new A();
6+
new B();
7+
})()
8+
9+
10+
//// [abstractClassInLocalScopeIsAbstract.js]
11+
var __extends = (this && this.__extends) || function (d, b) {
12+
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
13+
function __() { this.constructor = d; }
14+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15+
};
16+
(function () {
17+
var A = (function () {
18+
function A() {
19+
}
20+
return A;
21+
}());
22+
var B = (function (_super) {
23+
__extends(B, _super);
24+
function B() {
25+
_super.apply(this, arguments);
26+
}
27+
return B;
28+
}(A));
29+
new A();
30+
new B();
31+
})();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(() => {
2+
abstract class A {}
3+
class B extends A {}
4+
new B();
5+
return A;
6+
})();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(() => {
2+
abstract class A {}
3+
class B extends A {}
4+
new A();
5+
new B();
6+
})()

0 commit comments

Comments
 (0)