Skip to content

Abstract Classes and methods #3579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Jul 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
dd1f982
Parse abstract keyword
DickvdBrink Apr 30, 2015
0e72677
Accept baseline changes
DickvdBrink Apr 30, 2015
b42e447
Error on creating a new instance of an abstract class
DickvdBrink Apr 30, 2015
3aeae55
Output abstract keyword in declaration files (for classes)
DickvdBrink Apr 30, 2015
9436934
Added test for abstract-classes
DickvdBrink Apr 30, 2015
0ed7898
Accepted baselines
DickvdBrink Apr 30, 2015
3bc2aa9
fix merge conflicts with master
Jun 9, 2015
cd06627
Fixed Some indentation
Jun 10, 2015
5316d0d
Abstract keyword: Added parsing and some checks
Jun 15, 2015
506349f
Fix merge conflicts with master
Jun 15, 2015
1954322
Fixed some indentation issues
Jun 16, 2015
864a28a
forbid abstract methods from having an implementation
Jun 16, 2015
388e2fd
merge with extendsExpressions
Jun 16, 2015
a07f862
forbid calling abstract member foo() via super.foo()
Jun 17, 2015
5ca3955
check for inheriting abstract member functions
Jun 18, 2015
6dc430d
constructor cannot have modifier 'abstract'
Jun 18, 2015
4c1002e
removed premature parser check
Jun 18, 2015
10c8b6a
removed comment
Jun 18, 2015
326036d
write to declaration file
Jun 18, 2015
d596bb7
declarations of abstract methods must be consecutive
Jun 18, 2015
8681388
added tests
Jun 18, 2015
8f1790d
Simplified checkClassPropertyAccess -- fixed bug in super access
Jun 19, 2015
df3560f
moved tests, added a test
Jun 19, 2015
b448310
accepted baselines
Jun 19, 2015
b7f4ee5
Merge branch 'master' into abstract-classes2
Jun 19, 2015
933a2fa
updated baseline for new __extends impl
Jun 19, 2015
24da34c
fixed some indentation quirks, comments
Jun 19, 2015
d0924f4
moved abstract-method-inheritance test to checkKindsOfPropertyMemberO…
Jun 22, 2015
31b627a
moved comment
Jun 22, 2015
92ef6f5
responded to some of Daniel's comments
Jun 22, 2015
5c0b913
changed error messages and fixed comments
Jun 22, 2015
0daa9eb
updated baselines for new error messages
Jun 22, 2015
a8d205a
new tests
Jun 22, 2015
676f4a1
added baselines for new tests
Jun 22, 2015
9451aa6
Fixed order of arguments in error message
Jun 23, 2015
1068890
Moved tests to classAbstractKeyword folder
Jun 23, 2015
74d248e
Changed error message
Jun 23, 2015
3eea717
Fixed some error messages.
Jun 23, 2015
1f6637b
Added check to test
Jun 23, 2015
771e487
Re-fixed error message.
Jun 23, 2015
36b1dba
accepted baselines
Jun 23, 2015
d34b23a
Merge branch 'master' into abstract-classes2
Jun 23, 2015
b332727
updated comment in test and baseline
Jun 23, 2015
15c6842
consolidated looping through class members into one loop
Jun 24, 2015
5930052
cleaner loop
Jun 24, 2015
f8b95a5
Drafting constructor assignability restrictions
Jun 25, 2015
4640148
added context flag
Jun 25, 2015
a7ec1c4
merged master
Jun 25, 2015
31b8ff6
Merge branch 'contextSensitiveIsRelatedTo' into abstract-classes2
Jun 25, 2015
a183ba9
added flag as argument to checkTypeRelatedTo
Jun 29, 2015
2a9ea48
Merge branch 'master' into contextSensitiveIsRelatedTo
Jun 29, 2015
d8fe237
merged in master
Jun 29, 2015
ded2441
fixed a conflict
Jun 29, 2015
d932618
merged with contextSensitiveRelatedTo
Jun 29, 2015
e47e5bc
fixed a comment
Jun 29, 2015
b445f90
Merge branch 'contextSensitiveIsRelatedTo' into abstract-classes2
Jun 29, 2015
12383af
Responding to Jason
Jun 30, 2015
18d6e73
Revert isRelatedFlags changes
Jun 30, 2015
5864a66
updated baselines on classAbstract tests
Jun 30, 2015
994b73f
fixed an erroneous assertion
Jun 30, 2015
feb7e1d
Fixed generic abstract class inheritance and some comments
Jun 30, 2015
a1877ef
fexed comment and initialization
Jul 1, 2015
4dd369f
moved initialization and changed a comment
Jul 1, 2015
1608845
merged with master
Jul 1, 2015
1efff28
fixed union-type determination, moved abstract implementation test, a…
Jul 1, 2015
c93bde6
added tests
Jul 1, 2015
139d0f4
updated baselines
Jul 1, 2015
27ebd5c
removed a prototype
Jul 1, 2015
a0bd465
Appeasing Jason
Jul 1, 2015
07142a4
Revert "Appeasing Jason"
Jul 1, 2015
f3b1321
Appeasing Jason lite
Jul 1, 2015
6d0c7c9
removed a comment
Jul 1, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
441 changes: 291 additions & 150 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

23 changes: 15 additions & 8 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

/* @internal */
namespace ts {
// Ternary values are defined such that
// x & y is False if either x or y is False.
// x & y is Maybe if either x or y is Maybe, but neither x or y is False.
// x & y is True if both x and y are True.
// x | y is False if both x and y are False.
// x | y is Maybe if either x or y is Maybe, but neither x or y is True.
// x | y is True if either x or y is True.
/**
* Ternary values are defined such that
* x & y is False if either x or y is False.
* x & y is Maybe if either x or y is Maybe, but neither x or y is False.
* x & y is True if both x and y are True.
* x | y is False if both x and y are False.
* x | y is Maybe if either x or y is Maybe, but neither x or y is True.
* x | y is True if either x or y is True.
*/
export const enum Ternary {
False = 0,
Maybe = 1,
True = -1
True = -1
}

export function createFileMap<T>(getCanonicalFileName: (fileName: string) => string): FileMap<T> {
Expand Down Expand Up @@ -59,6 +61,11 @@ namespace ts {

export interface StringSet extends Map<any> { }

/**
* Iterates through 'array' by index and performs the callback on each element of array until the callback
* returns a truthy value, then returns that value.
* If no such value is found, the callback is applied to each element of array and undefined is returned.
*/
export function forEach<T, U>(array: T[], callback: (element: T, index: number) => U): U {
if (array) {
for (let i = 0, len = array.length; i < len; i++) {
Expand Down
7 changes: 7 additions & 0 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,9 @@ namespace ts {
if (node.flags & NodeFlags.Static) {
write("static ");
}
if (node.flags & NodeFlags.Abstract) {
write("abstract ");
}
}

function writeImportEqualsDeclaration(node: ImportEqualsDeclaration) {
Expand Down Expand Up @@ -912,6 +915,10 @@ namespace ts {

emitJsDocComments(node);
emitModuleElementDeclarationFlags(node);
if (node.flags & NodeFlags.Abstract) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a test for export default abstract class foo {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't thought of this case and the more general behavior of exports? What would we like to support? Currently this is a parsing error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would wait on this. i would add a test though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle, I see no reason to disallow default abstract classes. Why are they any different from concrete classes from an export default standpoint?

write("abstract ");
}

write("class ");
writeTextOfNode(currentSourceFile, node.name);
let prevEnclosingDeclaration = enclosingDeclaration;
Expand Down
17 changes: 14 additions & 3 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ namespace ts {
Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression: { code: 1239, category: DiagnosticCategory.Error, key: "Unable to resolve signature of parameter decorator when called as an expression." },
Unable_to_resolve_signature_of_property_decorator_when_called_as_an_expression: { code: 1240, category: DiagnosticCategory.Error, key: "Unable to resolve signature of property decorator when called as an expression." },
Unable_to_resolve_signature_of_method_decorator_when_called_as_an_expression: { code: 1241, category: DiagnosticCategory.Error, key: "Unable to resolve signature of method decorator when called as an expression." },
abstract_modifier_can_only_appear_on_a_class_or_method_declaration: { code: 1242, category: DiagnosticCategory.Error, key: "'abstract' modifier can only appear on a class or method declaration." },
_0_modifier_cannot_be_used_with_1_modifier: { code: 1243, category: DiagnosticCategory.Error, key: "'{0}' modifier cannot be used with '{1}' modifier." },
Abstract_methods_can_only_appear_within_an_abstract_class: { code: 1244, category: DiagnosticCategory.Error, key: "Abstract methods can only appear within an abstract class." },
Method_0_cannot_have_an_implementation_because_it_is_marked_abstract: { code: 1245, category: DiagnosticCategory.Error, key: "Method '{0}' cannot have an implementation because it is marked abstract." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
Expand Down Expand Up @@ -235,10 +239,10 @@ namespace ts {
this_cannot_be_referenced_in_a_static_property_initializer: { code: 2334, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a static property initializer." },
super_can_only_be_referenced_in_a_derived_class: { code: 2335, category: DiagnosticCategory.Error, key: "'super' can only be referenced in a derived class." },
super_cannot_be_referenced_in_constructor_arguments: { code: 2336, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in constructor arguments." },
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors" },
super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class" },
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors." },
super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class." },
Property_0_does_not_exist_on_type_1: { code: 2339, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." },
Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" },
Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword." },
Property_0_is_private_and_only_accessible_within_class_1: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is private and only accessible within class '{1}'." },
An_index_expression_argument_must_be_of_type_string_number_symbol_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', 'symbol, or 'any'." },
Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." },
Expand Down Expand Up @@ -397,6 +401,13 @@ namespace ts {
No_base_constructor_has_the_specified_number_of_type_arguments: { code: 2508, category: DiagnosticCategory.Error, key: "No base constructor has the specified number of type arguments." },
Base_constructor_return_type_0_is_not_a_class_or_interface_type: { code: 2509, category: DiagnosticCategory.Error, key: "Base constructor return type '{0}' is not a class or interface type." },
Base_constructors_must_all_have_the_same_return_type: { code: 2510, category: DiagnosticCategory.Error, key: "Base constructors must all have the same return type." },
Cannot_create_an_instance_of_the_abstract_class_0: { code: 2511, category: DiagnosticCategory.Error, key: "Cannot create an instance of the abstract class '{0}'." },
Overload_signatures_must_all_be_abstract_or_not_abstract: { code: 2512, category: DiagnosticCategory.Error, key: "Overload signatures must all be abstract or not abstract." },
Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression: { code: 2513, category: DiagnosticCategory.Error, key: "Abstract method '{0}' in class '{1}' cannot be accessed via super expression." },
Classes_containing_abstract_methods_must_be_marked_abstract: { code: 2514, category: DiagnosticCategory.Error, key: "Classes containing abstract methods must be marked abstract." },
Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2: { code: 2515, category: DiagnosticCategory.Error, key: "Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'." },
All_declarations_of_an_abstract_method_must_be_consecutive: { code: 2516, category: DiagnosticCategory.Error, key: "All declarations of an abstract method must be consecutive." },
Constructor_objects_of_abstract_type_cannot_be_assigned_to_constructor_objects_of_non_abstract_type: { code: 2517, category: DiagnosticCategory.Error, key: "Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type" },
Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions: { code: 2520, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions." },
Expression_resolves_to_variable_declaration_0_that_compiler_uses_to_support_async_functions: { code: 2521, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '{0}' that compiler uses to support async functions." },
The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression: { code: 2522, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an async arrow function. Consider using a standard async function expression." },
Expand Down
55 changes: 47 additions & 8 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@
"category": "Error",
"code": 1311
},

"The return type of a property decorator function must be either 'void' or 'any'.": {
"category": "Error",
"code": 1236
Expand All @@ -790,7 +789,22 @@
"category": "Error",
"code": 1241
},

"'abstract' modifier can only appear on a class or method declaration.": {
"category": "Error",
"code": 1242
},
"'{0}' modifier cannot be used with '{1}' modifier.": {
"category": "Error",
"code": 1243
},
"Abstract methods can only appear within an abstract class.": {
"category": "Error",
"code": 1244
},
"Method '{0}' cannot have an implementation because it is marked abstract.": {
"category": "Error",
"code": 1245
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2300
Expand Down Expand Up @@ -931,19 +945,19 @@
"category": "Error",
"code": 2336
},
"Super calls are not permitted outside constructors or in nested functions inside constructors": {
"Super calls are not permitted outside constructors or in nested functions inside constructors.": {
"category": "Error",
"code": 2337
},
"'super' property access is permitted only in a constructor, member function, or member accessor of a derived class": {
"'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.": {
"category": "Error",
"code": 2338
},
"Property '{0}' does not exist on type '{1}'.": {
"category": "Error",
"code": 2339
},
"Only public and protected methods of the base class are accessible via the 'super' keyword": {
"Only public and protected methods of the base class are accessible via the 'super' keyword.": {
"category": "Error",
"code": 2340
},
Expand Down Expand Up @@ -1579,7 +1593,34 @@
"category": "Error",
"code": 2510
},

"Cannot create an instance of the abstract class '{0}'.": {
"category": "Error",
"code": 2511
},
"Overload signatures must all be abstract or not abstract.": {
"category": "Error",
"code": 2512
},
"Abstract method '{0}' in class '{1}' cannot be accessed via super expression.": {
"category": "Error",
"code": 2513
},
"Classes containing abstract methods must be marked abstract.": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this different from error 1238? This one is specifically for the inherited methods?

"category": "Error",
"code": 2514
},
"Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'.": {
"category": "Error",
"code": 2515
},
"All declarations of an abstract method must be consecutive.": {
"category": "Error",
"code": 2516
},
"Constructor objects of abstract type cannot be assigned to constructor objects of non-abstract type": {
"category": "Error",
"code":2517
},
"Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": {
"category": "Error",
"code": 2520
Expand All @@ -1600,7 +1641,6 @@
"category": "Error",
"code": 2524
},

"JSX element attributes type '{0}' must be an object type.": {
"category": "Error",
"code": 2600
Expand Down Expand Up @@ -1641,7 +1681,6 @@
"category": "Error",
"code": 2650
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4141,6 +4141,7 @@ namespace ts {
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.AbstractKeyword:
nextToken();
continue;
default:
Expand Down Expand Up @@ -4278,6 +4279,7 @@ namespace ts {
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.PublicKeyword:
case SyntaxKind.AbstractKeyword:
case SyntaxKind.StaticKeyword:
if (isStartOfDeclaration()) {
return parseDeclaration();
Expand Down
1 change: 1 addition & 0 deletions src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace ts {
}

let textToToken: Map<SyntaxKind> = {
"abstract": SyntaxKind.AbstractKeyword,
"any": SyntaxKind.AnyKeyword,
"as": SyntaxKind.AsKeyword,
"boolean": SyntaxKind.BooleanKeyword,
Expand Down
26 changes: 14 additions & 12 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ namespace ts {
StaticKeyword,
YieldKeyword,
// Contextual keywords
AbstractKeyword,
AsKeyword,
AnyKeyword,
AsyncKeyword,
Expand Down Expand Up @@ -359,18 +360,19 @@ namespace ts {
Private = 0x00000020, // Property/Method
Protected = 0x00000040, // Property/Method
Static = 0x00000080, // Property/Method
Default = 0x00000100, // Function/Class (export default declaration)
MultiLine = 0x00000200, // Multi-line array or object literal
Synthetic = 0x00000400, // Synthetic node (for full fidelity)
DeclarationFile = 0x00000800, // Node is a .d.ts file
Let = 0x00001000, // Variable declaration
Const = 0x00002000, // Variable declaration
OctalLiteral = 0x00004000, // Octal numeric literal
Namespace = 0x00008000, // Namespace declaration
ExportContext = 0x00010000, // Export context (initialized by binding)
Async = 0x00020000, // Property/Method/Function

Modifier = Export | Ambient | Public | Private | Protected | Static | Default | Async,
Abstract = 0x00000100, // Class/Method/ConstructSignature
Async = 0x00000200, // Property/Method/Function
Default = 0x00000400, // Function/Class (export default declaration)
MultiLine = 0x00000800, // Multi-line array or object literal
Synthetic = 0x00001000, // Synthetic node (for full fidelity)
DeclarationFile = 0x00002000, // Node is a .d.ts file
Let = 0x00004000, // Variable declaration
Const = 0x00008000, // Variable declaration
OctalLiteral = 0x00010000, // Octal numeric literal
Namespace = 0x00020000, // Namespace declaration
ExportContext = 0x00040000, // Export context (initialized by binding)

Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async,
AccessibilityModifier = Public | Private | Protected,
BlockScoped = Let | Const
}
Expand Down
12 changes: 7 additions & 5 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1391,15 +1391,16 @@ namespace ts {

export function isModifier(token: SyntaxKind): boolean {
switch (token) {
case SyntaxKind.AbstractKeyword:
case SyntaxKind.AsyncKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.DeclareKeyword:
case SyntaxKind.DefaultKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.DeclareKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.DefaultKeyword:
case SyntaxKind.AsyncKeyword:
return true;
}
return false;
Expand Down Expand Up @@ -1900,6 +1901,7 @@ namespace ts {
case SyntaxKind.PublicKeyword: return NodeFlags.Public;
case SyntaxKind.ProtectedKeyword: return NodeFlags.Protected;
case SyntaxKind.PrivateKeyword: return NodeFlags.Private;
case SyntaxKind.AbstractKeyword: return NodeFlags.Abstract;
case SyntaxKind.ExportKeyword: return NodeFlags.Export;
case SyntaxKind.DeclareKeyword: return NodeFlags.Ambient;
case SyntaxKind.ConstKeyword: return NodeFlags.Const;
Expand Down
Loading