mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Checker refactor for FunctionLike and VariableOrProperty
This commit is contained in:
parent
2bc1f4f4fa
commit
f6266fc99e
@ -53,6 +53,10 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function hasUnknownComputedName(declaration: Declaration): boolean {
|
||||
return declaration.name && declaration.name.kind === SyntaxKind.ComputedPropertyName;
|
||||
}
|
||||
|
||||
export function bindSourceFile(file: SourceFile) {
|
||||
|
||||
var parent: Node;
|
||||
@ -84,13 +88,14 @@ module ts {
|
||||
if (symbolKind & SymbolFlags.Value && !symbol.valueDeclaration) symbol.valueDeclaration = node;
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Implement getDeclarationName for property name
|
||||
// Should not be called on a declaration with a computed property name.
|
||||
function getDeclarationName(node: Declaration): string {
|
||||
if (node.name) {
|
||||
if (node.kind === SyntaxKind.ModuleDeclaration && node.name.kind === SyntaxKind.StringLiteral) {
|
||||
return '"' + (<LiteralExpression>node.name).text + '"';
|
||||
}
|
||||
return (<Identifier>node.name).text;
|
||||
Debug.assert(node.name.kind !== SyntaxKind.ComputedPropertyName);
|
||||
return (<Identifier | LiteralExpression>node.name).text;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ConstructorType:
|
||||
@ -111,6 +116,12 @@ module ts {
|
||||
}
|
||||
|
||||
function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
|
||||
// Nodes with computed property names will not get symbols, because the type checker
|
||||
// does not make properties for them.
|
||||
if (node.name && node.name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var name = getDeclarationName(node);
|
||||
if (name !== undefined) {
|
||||
var symbol = hasProperty(symbols, name) ? symbols[name] : (symbols[name] = createSymbol(0, name));
|
||||
|
||||
@ -1663,7 +1663,7 @@ module ts {
|
||||
if (declaration.kind === SyntaxKind.Parameter) {
|
||||
var func = <FunctionLikeDeclaration>declaration.parent;
|
||||
// For a parameter of a set accessor, use the type of the get accessor if one is present
|
||||
if (func.kind === SyntaxKind.SetAccessor) {
|
||||
if (func.kind === SyntaxKind.SetAccessor && !hasUnknownComputedName(func)) {
|
||||
var getter = <AccessorDeclaration>getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
|
||||
if (getter) {
|
||||
return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
|
||||
@ -2531,7 +2531,7 @@ module ts {
|
||||
else {
|
||||
// TypeScript 1.0 spec (April 2014):
|
||||
// If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
|
||||
if (declaration.kind === SyntaxKind.GetAccessor) {
|
||||
if (declaration.kind === SyntaxKind.GetAccessor && !hasUnknownComputedName(declaration)) {
|
||||
var setter = <AccessorDeclaration>getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
|
||||
returnType = getAnnotatedAccessorType(setter);
|
||||
}
|
||||
@ -6648,9 +6648,6 @@ module ts {
|
||||
checkSourceElement(node.type);
|
||||
}
|
||||
if (fullTypeCheck) {
|
||||
checkCollisionWithCapturedSuperVariable(node, node.name);
|
||||
checkCollisionWithCapturedThisVariable(node, node.name);
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
checkCollisionWithArgumentsInGeneratedCode(node);
|
||||
if (compilerOptions.noImplicitAny && !node.type) {
|
||||
switch (node.kind) {
|
||||
@ -6711,17 +6708,14 @@ module ts {
|
||||
}
|
||||
|
||||
function checkPropertyDeclaration(node: PropertyDeclaration) {
|
||||
// TODO
|
||||
checkVariableDeclaration(node);
|
||||
checkVariableOrPropertyCommon(node);
|
||||
}
|
||||
|
||||
function checkMethodDeclaration(node: MethodDeclaration) {
|
||||
// TODO
|
||||
checkFunctionDeclaration(node);
|
||||
checkFunctionLikeDeclaration(node);
|
||||
}
|
||||
|
||||
function checkConstructorDeclaration(node: ConstructorDeclaration) {
|
||||
// TODO
|
||||
checkSignatureDeclaration(node);
|
||||
checkSourceElement(node.body);
|
||||
|
||||
@ -6812,29 +6806,32 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
// TypeScript 1.0 spec (April 2014): 8.4.3
|
||||
// Accessors for the same member name must specify the same accessibility.
|
||||
var otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
|
||||
var otherAccessor = <AccessorDeclaration>getDeclarationOfKind(node.symbol, otherKind);
|
||||
if (otherAccessor) {
|
||||
if (((node.flags & NodeFlags.AccessibilityModifier) !== (otherAccessor.flags & NodeFlags.AccessibilityModifier))) {
|
||||
error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility);
|
||||
}
|
||||
if (!hasUnknownComputedName(node)) {
|
||||
// TypeScript 1.0 spec (April 2014): 8.4.3
|
||||
// Accessors for the same member name must specify the same accessibility.
|
||||
var otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
|
||||
var otherAccessor = <AccessorDeclaration>getDeclarationOfKind(node.symbol, otherKind);
|
||||
if (otherAccessor) {
|
||||
if (((node.flags & NodeFlags.AccessibilityModifier) !== (otherAccessor.flags & NodeFlags.AccessibilityModifier))) {
|
||||
error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility);
|
||||
}
|
||||
|
||||
var thisType = getAnnotatedAccessorType(node);
|
||||
var otherType = getAnnotatedAccessorType(otherAccessor);
|
||||
// TypeScript 1.0 spec (April 2014): 4.5
|
||||
// If both accessors include type annotations, the specified types must be identical.
|
||||
if (thisType && otherType) {
|
||||
if (!isTypeIdenticalTo(thisType, otherType)) {
|
||||
error(node, Diagnostics.get_and_set_accessor_must_have_the_same_type);
|
||||
var thisType = getAnnotatedAccessorType(node);
|
||||
var otherType = getAnnotatedAccessorType(otherAccessor);
|
||||
// TypeScript 1.0 spec (April 2014): 4.5
|
||||
// If both accessors include type annotations, the specified types must be identical.
|
||||
if (thisType && otherType) {
|
||||
if (!isTypeIdenticalTo(thisType, otherType)) {
|
||||
error(node, Diagnostics.get_and_set_accessor_must_have_the_same_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkAndStoreTypeOfAccessors(getSymbolOfNode(node));
|
||||
}
|
||||
}
|
||||
|
||||
checkFunctionDeclaration(node);
|
||||
checkAndStoreTypeOfAccessors(getSymbolOfNode(node));
|
||||
checkFunctionLikeDeclaration(node);
|
||||
}
|
||||
|
||||
function checkTypeReference(node: TypeReferenceNode) {
|
||||
@ -7088,7 +7085,7 @@ module ts {
|
||||
}
|
||||
|
||||
if (duplicateFunctionDeclaration) {
|
||||
forEach( declarations, declaration => {
|
||||
forEach(declarations, declaration => {
|
||||
error(declaration.name, Diagnostics.Duplicate_function_implementation);
|
||||
});
|
||||
}
|
||||
@ -7204,26 +7201,37 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkFunctionDeclaration(node: FunctionLikeDeclaration): void {
|
||||
function checkFunctionDeclaration(node: FunctionDeclaration): void {
|
||||
checkFunctionLikeDeclaration(node);
|
||||
if (fullTypeCheck) {
|
||||
checkCollisionWithCapturedSuperVariable(node, node.name);
|
||||
checkCollisionWithCapturedThisVariable(node, node.name);
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
}
|
||||
}
|
||||
|
||||
function checkFunctionLikeDeclaration(node: FunctionLikeDeclaration): void {
|
||||
checkSignatureDeclaration(node);
|
||||
|
||||
var symbol = getSymbolOfNode(node);
|
||||
// first we want to check the local symbol that contain this declaration
|
||||
// - if node.localSymbol !== undefined - this is current declaration is exported and localSymbol points to the local symbol
|
||||
// - if node.localSymbol === undefined - this node is non-exported so we can just pick the result of getSymbolOfNode
|
||||
var localSymbol = node.localSymbol || symbol;
|
||||
if (!hasUnknownComputedName(node)) {
|
||||
// first we want to check the local symbol that contain this declaration
|
||||
// - if node.localSymbol !== undefined - this is current declaration is exported and localSymbol points to the local symbol
|
||||
// - if node.localSymbol === undefined - this node is non-exported so we can just pick the result of getSymbolOfNode
|
||||
var symbol = getSymbolOfNode(node);
|
||||
var localSymbol = node.localSymbol || symbol;
|
||||
|
||||
var firstDeclaration = getDeclarationOfKind(localSymbol, node.kind);
|
||||
// Only type check the symbol once
|
||||
if (node === firstDeclaration) {
|
||||
checkFunctionOrConstructorSymbol(localSymbol);
|
||||
}
|
||||
var firstDeclaration = getDeclarationOfKind(localSymbol, node.kind);
|
||||
// Only type check the symbol once
|
||||
if (node === firstDeclaration) {
|
||||
checkFunctionOrConstructorSymbol(localSymbol);
|
||||
}
|
||||
|
||||
if (symbol.parent) {
|
||||
// run check once for the first declaration
|
||||
if (getDeclarationOfKind(symbol, node.kind) === node) {
|
||||
// run check on export symbol to check that modifiers agree across all exported declarations
|
||||
checkFunctionOrConstructorSymbol(symbol);
|
||||
if (symbol.parent) {
|
||||
// run check once for the first declaration
|
||||
if (getDeclarationOfKind(symbol, node.kind) === node) {
|
||||
// run check on export symbol to check that modifiers agree across all exported declarations
|
||||
checkFunctionOrConstructorSymbol(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7344,9 +7352,8 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Decide what to do for computed properties
|
||||
function needCollisionCheckForIdentifier(node: Node, identifier: DeclarationName, name: string): boolean {
|
||||
if (!(identifier && (<Identifier>identifier).text === name)) {
|
||||
function needCollisionCheckForIdentifier(node: Node, identifier: Identifier, name: string): boolean {
|
||||
if (!(identifier && identifier.text === name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7371,8 +7378,7 @@ module ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Decide what to do for computed properties
|
||||
function checkCollisionWithCapturedThisVariable(node: Node, name: DeclarationName): void {
|
||||
function checkCollisionWithCapturedThisVariable(node: Node, name: Identifier): void {
|
||||
if (!needCollisionCheckForIdentifier(node, name, "_this")) {
|
||||
return;
|
||||
}
|
||||
@ -7397,7 +7403,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkCollisionWithCapturedSuperVariable(node: Node, name: DeclarationName) {
|
||||
function checkCollisionWithCapturedSuperVariable(node: Node, name: Identifier) {
|
||||
if (!needCollisionCheckForIdentifier(node, name, "_super")) {
|
||||
return;
|
||||
}
|
||||
@ -7420,8 +7426,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Decide what to do for computed properties
|
||||
function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: DeclarationName) {
|
||||
function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) {
|
||||
if (!needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) {
|
||||
return;
|
||||
}
|
||||
@ -7472,40 +7477,49 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkVariableDeclaration(node: VariableDeclaration | PropertyDeclaration) {
|
||||
function checkVariableOrPropertyCommon(node: VariableDeclaration | PropertyDeclaration) {
|
||||
checkSourceElement(node.type);
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
|
||||
if (fullTypeCheck) {
|
||||
var symbol = getSymbolOfNode(node);
|
||||
|
||||
var typeOfValueDeclaration = getTypeOfVariableOrParameterOrProperty(symbol);
|
||||
var type: Type;
|
||||
var useTypeFromValueDeclaration = node === symbol.valueDeclaration;
|
||||
if (useTypeFromValueDeclaration) {
|
||||
type = typeOfValueDeclaration;
|
||||
}
|
||||
else {
|
||||
if (hasUnknownComputedName(node) || symbol.valueDeclaration !== node) {
|
||||
type = getTypeOfVariableOrPropertyDeclaration(node);
|
||||
}
|
||||
else {
|
||||
type = getTypeOfVariableOrParameterOrProperty(symbol);
|
||||
}
|
||||
|
||||
if (node.initializer && !(getNodeLinks(node.initializer).flags & NodeCheckFlags.TypeChecked)) {
|
||||
// Use default messages
|
||||
checkTypeAssignableTo(checkAndMarkExpression(node.initializer), type, node, /*headMessage*/ undefined);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
// All callers who expect a value to be returned are in fullTypeCheck mode.
|
||||
// If we are not in type check mode, no need to get the type.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function checkVariableDeclaration(node: VariableDeclaration) {
|
||||
var type = checkVariableOrPropertyCommon(node);
|
||||
if (fullTypeCheck) {
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
if (node.initializer) {
|
||||
if (!(getNodeLinks(node.initializer).flags & NodeCheckFlags.TypeChecked)) {
|
||||
// Use default messages
|
||||
checkTypeAssignableTo(checkAndMarkExpression(node.initializer), type, node, /*headMessage*/ undefined);
|
||||
}
|
||||
//TODO(jfreeman): Check that it is not a computed property
|
||||
checkCollisionWithConstDeclarations(<VariableDeclaration>node);
|
||||
checkCollisionWithConstDeclarations(node);
|
||||
}
|
||||
|
||||
checkCollisionWithCapturedSuperVariable(node, node.name);
|
||||
checkCollisionWithCapturedThisVariable(node, node.name);
|
||||
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
|
||||
if (!useTypeFromValueDeclaration) {
|
||||
var symbol = getSymbolOfNode(node);
|
||||
if (node !== symbol.valueDeclaration) {
|
||||
// TypeScript 1.0 spec (April 2014): 5.1
|
||||
// Multiple declarations for the same variable name in the same declaration space are permitted,
|
||||
// provided that each declaration associates the same type with the variable.
|
||||
var typeOfValueDeclaration = getTypeOfVariableOrParameterOrProperty(symbol);
|
||||
if (typeOfValueDeclaration !== unknownType && type !== unknownType && !isTypeIdenticalTo(typeOfValueDeclaration, type)) {
|
||||
error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(typeOfValueDeclaration), typeToString(type));
|
||||
}
|
||||
@ -8365,7 +8379,7 @@ module ts {
|
||||
case SyntaxKind.ParenType:
|
||||
return checkSourceElement((<ParenTypeNode>node).type);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return checkFunctionDeclaration(<FunctionLikeDeclaration>node);
|
||||
return checkFunctionDeclaration(<FunctionDeclaration>node);
|
||||
case SyntaxKind.Block:
|
||||
return checkBlock(<Block>node);
|
||||
case SyntaxKind.FunctionBlock:
|
||||
|
||||
@ -71,8 +71,9 @@ module ts {
|
||||
return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier;
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Implement declarationNameToString for computed properties
|
||||
// Return display name of an identifier
|
||||
// Computed property names will just be emitted as "[<expr>]", where <expr> is the source
|
||||
// text of the expression in the computed property.
|
||||
export function declarationNameToString(name: DeclarationName) {
|
||||
return name.kind === SyntaxKind.Missing ? "(Missing)" : getTextOfNode(name);
|
||||
}
|
||||
|
||||
@ -371,11 +371,9 @@ module ts {
|
||||
* Examples:
|
||||
* FunctionDeclaration
|
||||
* MethodDeclaration
|
||||
* ConstructorDeclaration
|
||||
* AccessorDeclaration
|
||||
* FunctionExpression
|
||||
*/
|
||||
export interface FunctionLikeDeclaration extends Declaration, ParsedSignature {
|
||||
export interface FunctionLikeDeclaration extends SignatureDeclaration {
|
||||
asteriskToken?: Node;
|
||||
body?: Block | Expression;
|
||||
}
|
||||
@ -389,7 +387,7 @@ module ts {
|
||||
body?: Block;
|
||||
}
|
||||
|
||||
export interface ConstructorDeclaration extends FunctionLikeDeclaration {
|
||||
export interface ConstructorDeclaration extends Node, ParsedSignature {
|
||||
body?: Block;
|
||||
}
|
||||
|
||||
@ -458,7 +456,7 @@ module ts {
|
||||
whenFalse: Expression;
|
||||
}
|
||||
|
||||
export interface FunctionExpression extends Expression, FunctionLikeDeclaration {
|
||||
export interface FunctionExpression extends Expression, SignatureDeclaration {
|
||||
name?: Identifier;
|
||||
body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//// [computedPropertyNames1.ts]
|
||||
var v = {
|
||||
get [0 + 1]() { return 0 },
|
||||
set [0 + 1](v) { }
|
||||
set [0 + 1](v: string) { } //No error
|
||||
}
|
||||
|
||||
//// [computedPropertyNames1.js]
|
||||
@ -10,5 +10,5 @@ var v = {
|
||||
return 0;
|
||||
},
|
||||
set [0 + 1](v) {
|
||||
}
|
||||
} //No error
|
||||
};
|
||||
|
||||
12
tests/baselines/reference/computedPropertyNames1.types
Normal file
12
tests/baselines/reference/computedPropertyNames1.types
Normal file
@ -0,0 +1,12 @@
|
||||
=== tests/cases/conformance/es6/computedProperties/computedPropertyNames1.ts ===
|
||||
var v = {
|
||||
>v : {}
|
||||
>{ get [0 + 1]() { return 0 }, set [0 + 1](v: string) { } //No error} : {}
|
||||
|
||||
get [0 + 1]() { return 0 },
|
||||
>0 + 1 : number
|
||||
|
||||
set [0 + 1](v: string) { } //No error
|
||||
>0 + 1 : number
|
||||
>v : string
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesOnOverloads.ts(4,5): error TS1168: Computed property names are not allowed in method overloads.
|
||||
tests/cases/conformance/es6/computedProperties/computedPropertyNamesOnOverloads.ts(5,5): error TS1168: Computed property names are not allowed in method overloads.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/computedProperties/computedPropertyNamesOnOverloads.ts (2 errors) ====
|
||||
var methodName = "method";
|
||||
var accessorName = "accessor";
|
||||
class C {
|
||||
[methodName](v: string);
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS1168: Computed property names are not allowed in method overloads.
|
||||
[methodName]();
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS1168: Computed property names are not allowed in method overloads.
|
||||
[methodName](v?: string) { }
|
||||
}
|
||||
@ -1,12 +1,9 @@
|
||||
tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName11.ts(2,4): error TS1168: Computed property names are not allowed in method overloads.
|
||||
tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName11.ts(2,4): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
|
||||
|
||||
==== tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName11.ts (2 errors) ====
|
||||
==== tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName11.ts (1 errors) ====
|
||||
class C {
|
||||
[e]();
|
||||
~~~
|
||||
!!! error TS1168: Computed property names are not allowed in method overloads.
|
||||
~~~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
@ -1,12 +1,9 @@
|
||||
tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName11.ts(2,4): error TS1168: Computed property names are not allowed in method overloads.
|
||||
tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName11.ts(2,4): error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
|
||||
|
||||
==== tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName11.ts (2 errors) ====
|
||||
==== tests/cases/conformance/parser/ecmascript5/ComputedPropertyNames/parserES5ComputedPropertyName11.ts (1 errors) ====
|
||||
class C {
|
||||
[e]();
|
||||
~~~
|
||||
!!! error TS1168: Computed property names are not allowed in method overloads.
|
||||
~~~
|
||||
!!! error TS2391: Function implementation is missing or not immediately following the declaration.
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
// @target: es6
|
||||
var v = {
|
||||
get [0 + 1]() { return 0 },
|
||||
set [0 + 1](v) { }
|
||||
set [0 + 1](v: string) { } //No error
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user