Skip to content

Commit 80b7613

Browse files
author
Andy Hanson
committed
Allow an abstract class to appear in a local scope
1 parent c578367 commit 80b7613

8 files changed

+184
-44
lines changed

src/compiler/checker.ts

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18268,50 +18268,9 @@ namespace ts {
1826818268
}
1826918269

1827018270
function checkGrammarModifiers(node: Node): boolean {
18271-
switch (node.kind) {
18272-
case SyntaxKind.GetAccessor:
18273-
case SyntaxKind.SetAccessor:
18274-
case SyntaxKind.Constructor:
18275-
case SyntaxKind.PropertyDeclaration:
18276-
case SyntaxKind.PropertySignature:
18277-
case SyntaxKind.MethodDeclaration:
18278-
case SyntaxKind.MethodSignature:
18279-
case SyntaxKind.IndexSignature:
18280-
case SyntaxKind.ModuleDeclaration:
18281-
case SyntaxKind.ImportDeclaration:
18282-
case SyntaxKind.ImportEqualsDeclaration:
18283-
case SyntaxKind.ExportDeclaration:
18284-
case SyntaxKind.ExportAssignment:
18285-
case SyntaxKind.FunctionExpression:
18286-
case SyntaxKind.ArrowFunction:
18287-
case SyntaxKind.Parameter:
18288-
break;
18289-
case SyntaxKind.FunctionDeclaration:
18290-
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.AsyncKeyword) &&
18291-
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
18292-
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
18293-
}
18294-
break;
18295-
case SyntaxKind.ClassDeclaration:
18296-
case SyntaxKind.InterfaceDeclaration:
18297-
case SyntaxKind.VariableStatement:
18298-
case SyntaxKind.TypeAliasDeclaration:
18299-
if (node.modifiers && node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
18300-
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
18301-
}
18302-
break;
18303-
case SyntaxKind.EnumDeclaration:
18304-
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.ConstKeyword) &&
18305-
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
18306-
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
18307-
}
18308-
break;
18309-
default:
18310-
return false;
18311-
}
18312-
18313-
if (!node.modifiers) {
18314-
return;
18271+
const quickResult = reportObviousModifierErrors(node);
18272+
if (quickResult !== undefined) {
18273+
return quickResult;
1831518274
}
1831618275

1831718276
let lastStatic: Node, lastPrivate: Node, lastProtected: Node, lastDeclare: Node, lastAsync: Node, lastReadonly: Node;
@@ -18516,6 +18475,61 @@ namespace ts {
1851618475
}
1851718476
}
1851818477

18478+
/**
18479+
* true | false: Early return this value from checkGrammarModifiers.
18480+
* undefined: Need to do full checking on the modifiers.
18481+
*/
18482+
function reportObviousModifierErrors(node: Node): boolean | undefined {
18483+
return !node.modifiers
18484+
? false
18485+
: shouldReportBadModifier(node)
18486+
? grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here)
18487+
: undefined;
18488+
}
18489+
function shouldReportBadModifier(node: Node): boolean {
18490+
switch (node.kind) {
18491+
case SyntaxKind.GetAccessor:
18492+
case SyntaxKind.SetAccessor:
18493+
case SyntaxKind.Constructor:
18494+
case SyntaxKind.PropertyDeclaration:
18495+
case SyntaxKind.PropertySignature:
18496+
case SyntaxKind.MethodDeclaration:
18497+
case SyntaxKind.MethodSignature:
18498+
case SyntaxKind.IndexSignature:
18499+
case SyntaxKind.ModuleDeclaration:
18500+
case SyntaxKind.ImportDeclaration:
18501+
case SyntaxKind.ImportEqualsDeclaration:
18502+
case SyntaxKind.ExportDeclaration:
18503+
case SyntaxKind.ExportAssignment:
18504+
case SyntaxKind.FunctionExpression:
18505+
case SyntaxKind.ArrowFunction:
18506+
case SyntaxKind.Parameter:
18507+
return false;
18508+
default:
18509+
if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
18510+
return false;
18511+
}
18512+
switch (node.kind) {
18513+
case SyntaxKind.FunctionDeclaration:
18514+
return nodeHasAnyModifiersExcept(node, SyntaxKind.AsyncKeyword);
18515+
case SyntaxKind.ClassDeclaration:
18516+
return nodeHasAnyModifiersExcept(node, SyntaxKind.AbstractKeyword);
18517+
case SyntaxKind.InterfaceDeclaration:
18518+
case SyntaxKind.VariableStatement:
18519+
case SyntaxKind.TypeAliasDeclaration:
18520+
return true;
18521+
case SyntaxKind.EnumDeclaration:
18522+
return nodeHasAnyModifiersExcept(node, SyntaxKind.ConstKeyword)
18523+
default:
18524+
Debug.fail();
18525+
return false;
18526+
}
18527+
}
18528+
}
18529+
function nodeHasAnyModifiersExcept(node: Node, allowedModifier: SyntaxKind): boolean {
18530+
return node.modifiers.length > 1 || node.modifiers[0].kind !== allowedModifier;
18531+
}
18532+
1851918533
function checkGrammarAsyncModifier(node: Node, asyncModifier: Node): boolean {
1852018534
if (languageVersion < ScriptTarget.ES6) {
1852118535
return grammarErrorOnNode(asyncModifier, Diagnostics.Async_functions_are_only_available_when_targeting_ECMAScript_2015_or_higher);
Lines changed: 31 additions & 0 deletions
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+
})();
Lines changed: 17 additions & 0 deletions
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+
Lines changed: 22 additions & 0 deletions
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+
Lines changed: 13 additions & 0 deletions
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+
Lines changed: 31 additions & 0 deletions
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+
})();
Lines changed: 6 additions & 0 deletions
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+
})();
Lines changed: 6 additions & 0 deletions
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)