mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Merge pull request #9994 from Microsoft/local_abstract_class
Allow an abstract class to appear in a local scope
This commit is contained in:
commit
013744bf85
@ -18625,50 +18625,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkGrammarModifiers(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Parameter:
|
||||
break;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.AsyncKeyword) &&
|
||||
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
if (node.modifiers && node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.ConstKeyword) &&
|
||||
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!node.modifiers) {
|
||||
return;
|
||||
const quickResult = reportObviousModifierErrors(node);
|
||||
if (quickResult !== undefined) {
|
||||
return quickResult;
|
||||
}
|
||||
|
||||
let lastStatic: Node, lastPrivate: Node, lastProtected: Node, lastDeclare: Node, lastAsync: Node, lastReadonly: Node;
|
||||
@ -18873,6 +18832,61 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* true | false: Early return this value from checkGrammarModifiers.
|
||||
* undefined: Need to do full checking on the modifiers.
|
||||
*/
|
||||
function reportObviousModifierErrors(node: Node): boolean | undefined {
|
||||
return !node.modifiers
|
||||
? false
|
||||
: shouldReportBadModifier(node)
|
||||
? grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here)
|
||||
: undefined;
|
||||
}
|
||||
function shouldReportBadModifier(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Parameter:
|
||||
return false;
|
||||
default:
|
||||
if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
|
||||
return false;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return nodeHasAnyModifiersExcept(node, SyntaxKind.AsyncKeyword);
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return nodeHasAnyModifiersExcept(node, SyntaxKind.AbstractKeyword);
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return nodeHasAnyModifiersExcept(node, SyntaxKind.ConstKeyword);
|
||||
default:
|
||||
Debug.fail();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
function nodeHasAnyModifiersExcept(node: Node, allowedModifier: SyntaxKind): boolean {
|
||||
return node.modifiers.length > 1 || node.modifiers[0].kind !== allowedModifier;
|
||||
}
|
||||
|
||||
function checkGrammarAsyncModifier(node: Node, asyncModifier: Node): boolean {
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
return grammarErrorOnNode(asyncModifier, Diagnostics.Async_functions_are_only_available_when_targeting_ECMAScript_2015_or_higher);
|
||||
|
||||
31
tests/baselines/reference/abstractClassInLocalScope.js
Normal file
31
tests/baselines/reference/abstractClassInLocalScope.js
Normal file
@ -0,0 +1,31 @@
|
||||
//// [abstractClassInLocalScope.ts]
|
||||
(() => {
|
||||
abstract class A {}
|
||||
class B extends A {}
|
||||
new B();
|
||||
return A;
|
||||
})();
|
||||
|
||||
|
||||
//// [abstractClassInLocalScope.js]
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
(function () {
|
||||
var A = (function () {
|
||||
function A() {
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var B = (function (_super) {
|
||||
__extends(B, _super);
|
||||
function B() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return B;
|
||||
}(A));
|
||||
new B();
|
||||
return A;
|
||||
})();
|
||||
17
tests/baselines/reference/abstractClassInLocalScope.symbols
Normal file
17
tests/baselines/reference/abstractClassInLocalScope.symbols
Normal file
@ -0,0 +1,17 @@
|
||||
=== tests/cases/compiler/abstractClassInLocalScope.ts ===
|
||||
(() => {
|
||||
abstract class A {}
|
||||
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
|
||||
|
||||
class B extends A {}
|
||||
>B : Symbol(B, Decl(abstractClassInLocalScope.ts, 1, 23))
|
||||
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
|
||||
|
||||
new B();
|
||||
>B : Symbol(B, Decl(abstractClassInLocalScope.ts, 1, 23))
|
||||
|
||||
return A;
|
||||
>A : Symbol(A, Decl(abstractClassInLocalScope.ts, 0, 8))
|
||||
|
||||
})();
|
||||
|
||||
22
tests/baselines/reference/abstractClassInLocalScope.types
Normal file
22
tests/baselines/reference/abstractClassInLocalScope.types
Normal file
@ -0,0 +1,22 @@
|
||||
=== tests/cases/compiler/abstractClassInLocalScope.ts ===
|
||||
(() => {
|
||||
>(() => { abstract class A {} class B extends A {} new B(); return A;})() : typeof A
|
||||
>(() => { abstract class A {} class B extends A {} new B(); return A;}) : () => typeof A
|
||||
>() => { abstract class A {} class B extends A {} new B(); return A;} : () => typeof A
|
||||
|
||||
abstract class A {}
|
||||
>A : A
|
||||
|
||||
class B extends A {}
|
||||
>B : B
|
||||
>A : A
|
||||
|
||||
new B();
|
||||
>new B() : B
|
||||
>B : typeof B
|
||||
|
||||
return A;
|
||||
>A : typeof A
|
||||
|
||||
})();
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts(4,5): error TS2511: Cannot create an instance of the abstract class 'A'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/abstractClassInLocalScopeIsAbstract.ts (1 errors) ====
|
||||
(() => {
|
||||
abstract class A {}
|
||||
class B extends A {}
|
||||
new A();
|
||||
~~~~~~~
|
||||
!!! error TS2511: Cannot create an instance of the abstract class 'A'.
|
||||
new B();
|
||||
})()
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
//// [abstractClassInLocalScopeIsAbstract.ts]
|
||||
(() => {
|
||||
abstract class A {}
|
||||
class B extends A {}
|
||||
new A();
|
||||
new B();
|
||||
})()
|
||||
|
||||
|
||||
//// [abstractClassInLocalScopeIsAbstract.js]
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
(function () {
|
||||
var A = (function () {
|
||||
function A() {
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var B = (function (_super) {
|
||||
__extends(B, _super);
|
||||
function B() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return B;
|
||||
}(A));
|
||||
new A();
|
||||
new B();
|
||||
})();
|
||||
6
tests/cases/compiler/abstractClassInLocalScope.ts
Normal file
6
tests/cases/compiler/abstractClassInLocalScope.ts
Normal file
@ -0,0 +1,6 @@
|
||||
(() => {
|
||||
abstract class A {}
|
||||
class B extends A {}
|
||||
new B();
|
||||
return A;
|
||||
})();
|
||||
@ -0,0 +1,6 @@
|
||||
(() => {
|
||||
abstract class A {}
|
||||
class B extends A {}
|
||||
new A();
|
||||
new B();
|
||||
})()
|
||||
Loading…
x
Reference in New Issue
Block a user