Merge pull request #9994 from Microsoft/local_abstract_class

Allow an abstract class to appear in a local scope
This commit is contained in:
Andy 2016-07-28 13:46:50 -07:00 committed by GitHub
commit 013744bf85
8 changed files with 184 additions and 44 deletions

View File

@ -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);

View 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;
})();

View 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))
})();

View 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
})();

View File

@ -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();
})()

View File

@ -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();
})();

View File

@ -0,0 +1,6 @@
(() => {
abstract class A {}
class B extends A {}
new B();
return A;
})();

View File

@ -0,0 +1,6 @@
(() => {
abstract class A {}
class B extends A {}
new A();
new B();
})()