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

Allow dynamic names in types #15473

Merged
merged 65 commits into from Nov 16, 2017
Commits
Jump to file or symbol
Failed to load files and symbols.
+10,267 −1,174
Diff settings

Always

Just for now

Copy path View file
@@ -1680,7 +1680,7 @@ namespace ts {
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: __String) {
const symbol = createSymbol(symbolFlags, name);
if (symbolFlags & SymbolFlags.EnumMember) {
if (symbolFlags & (SymbolFlags.EnumMember | SymbolFlags.ClassMember)) {
symbol.parent = container.symbol;
}
addDeclarationToSymbol(symbol, node, symbolFlags);
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -190,6 +190,7 @@ namespace ts {
const writer = <EmitTextWriterWithSymbolWriter>createTextWriter(newLine);
writer.trackSymbol = trackSymbol;
writer.reportInaccessibleThisError = reportInaccessibleThisError;
writer.reportInaccessibleUniqueSymbolError = reportInaccessibleUniqueSymbolError;
writer.reportPrivateInBaseOfClassExpression = reportPrivateInBaseOfClassExpression;
writer.writeKeyword = writer.write;
writer.writeOperator = writer.write;
@@ -322,11 +323,21 @@ namespace ts {
}
}
function reportInaccessibleUniqueSymbolError() {
if (errorNameNode) {
reportedDeclarationError = true;
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary,
declarationNameToString(errorNameNode),
"unique symbol"));
}
}
function reportInaccessibleThisError() {
if (errorNameNode) {
reportedDeclarationError = true;
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_this_type_A_type_annotation_is_necessary,
declarationNameToString(errorNameNode)));
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary,
declarationNameToString(errorNameNode),
"this"));
}
}
@@ -1227,7 +1238,7 @@ namespace ts {
}
function emitPropertyDeclaration(node: Declaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLateBound(node)) {
return;
}
@@ -1246,10 +1257,8 @@ namespace ts {
emitBindingPattern(<BindingPattern>node.name);
}
else {
// If this node is a computed name, it can only be a symbol, because we've already skipped
// it if it's not a well known symbol. In that case, the text of the name will be exactly
// what we want, namely the name expression enclosed in brackets.
writeTextOfNode(currentText, node.name);
writeNameOfDeclaration(node, getVariableDeclarationTypeVisibilityError);
// If optional property emit ? but in the case of parameterProperty declaration with "?" indicating optional parameter for the constructor
// we don't want to emit property declaration with "?"
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature ||
@@ -1387,7 +1396,7 @@ namespace ts {
}
function emitAccessorDeclaration(node: AccessorDeclaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLateBound(node)) {
return;
}
@@ -1398,7 +1407,7 @@ namespace ts {
emitJsDocComments(accessors.getAccessor);
emitJsDocComments(accessors.setAccessor);
emitClassMemberDeclarationFlags(getModifierFlags(node) | (accessors.setAccessor ? 0 : ModifierFlags.Readonly));
writeTextOfNode(currentText, node.name);
writeNameOfDeclaration(node, getAccessorNameVisibilityError);
if (!hasModifier(node, ModifierFlags.Private)) {
accessorWithTypeAnnotation = node;
let type = getTypeAnnotationFromAccessor(node);
@@ -1426,6 +1435,37 @@ namespace ts {
}
}
function getAccessorNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
const diagnosticMessage = getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult);
return diagnosticMessage !== undefined ? {
diagnosticMessage,
errorNode: node,
typeName: node.name
} : undefined;
}
function getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (hasModifier(node, ModifierFlags.Static)) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
}
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
}
else {
return symbolAccessibilityResult.errorModuleName ?
Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
}
}
function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
let diagnosticMessage: DiagnosticMessage;
if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) {
@@ -1467,7 +1507,7 @@ namespace ts {
}
function writeFunctionDeclaration(node: FunctionLikeDeclaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLateBound(node)) {
return;
}
@@ -1489,13 +1529,69 @@ namespace ts {
write("constructor");
}
else {
writeTextOfNode(currentText, node.name);
writeNameOfDeclaration(node, getMethodNameVisibilityError);
if (hasQuestionToken(node)) {
write("?");
}
}
emitSignatureDeclaration(node);
}
function getMethodNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
const diagnosticMessage = getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult);
return diagnosticMessage !== undefined ? {
diagnosticMessage,
errorNode: node,
typeName: node.name
} : undefined;
}
function getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
if (hasModifier(node, ModifierFlags.Static)) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1;
}
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
return symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1;
}
else {
return symbolAccessibilityResult.errorModuleName ?
Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1;
}
}
}
function writeNameOfDeclaration(node: NamedDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
if (hasDynamicName(node)) {
// If this node has a dynamic name, it can only be an identifier or property access because
// we've already skipped it otherwise.
Debug.assert(resolver.isLateBound(node));
writeLateBoundNameOfDeclaration(node as LateBoundDeclaration, getSymbolAccessibilityDiagnostic);
}
else {
// If this node is a computed name, it can only be a symbol, because we've already skipped
// it if it's not a well known symbol. In that case, the text of the name will be exactly
// what we want, namely the name expression enclosed in brackets.
writeTextOfNode(currentText, node.name);
}
}
function writeLateBoundNameOfDeclaration(node: LateBoundDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
const entityName = node.name.expression;
const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration);
handleSymbolAccessibilityError(visibilityResult);
recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName));
writeTextOfNode(currentText, node.name);
}
function emitSignatureDeclarationWithJsDocComments(node: SignatureDeclaration) {
@@ -491,23 +491,23 @@
"category": "Error",
"code": 1164
},
"A computed property name in an ambient context must directly refer to a built-in symbol.": {
"A computed property name in an ambient context must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1165
},
"A computed property name in a class property declaration must directly refer to a built-in symbol.": {
"A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1166
},
"A computed property name in a method overload must directly refer to a built-in symbol.": {
"A computed property name in a method overload must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1168
},
"A computed property name in an interface must directly refer to a built-in symbol.": {
"A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1169
},
"A computed property name in a type literal must directly refer to a built-in symbol.": {
"A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1170
},
@@ -911,6 +911,30 @@
"category": "Error",
"code": 1329
},
"A property of an interface or type literal whose type is a 'unique symbol' type must be 'readonly'.": {
"category": "Error",
"code": 1330
},
"A property of a class whose type is a 'unique symbol' type must be both 'static' and 'readonly'.": {
"category": "Error",
"code": 1331
},
"A variable whose type is a 'unique symbol' type must be 'const'.": {
"category": "Error",
"code": 1332
},
"'unique symbol' types may not be used on a variable declaration with a binding name.": {
"category": "Error",
"code": 1333
},
"'unique symbol' types are only allowed on variables in a variable statement.": {
"category": "Error",
"code": 1334
},
"'unique symbol' types are not allowed here.": {
"category": "Error",
"code": 1335
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -1780,7 +1804,7 @@
"category": "Error",
"code": 2526
},
"The inferred type of '{0}' references an inaccessible 'this' type. A type annotation is necessary.": {
"The inferred type of '{0}' references an inaccessible '{1}' type. A type annotation is necessary.": {
"category": "Error",
"code": 2527
},
@@ -2228,6 +2252,14 @@
"category": "Error",
"code": 2716
},
"Subsequent property declarations must have the same type. Property '{0}' has type '{1}' at {2}, but here has type '{3}'.": {
"category": "Error",
"code": 2717
},
"Duplicate declaration '{0}'.": {
"category": "Error",
"code": 2718
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -2530,6 +2562,39 @@
"code": 4094
},
"Public static method '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named.": {
"category": "Error",
"code": 4095
},
"Public static method '{0}' of exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4096
},
"Public static method '{0}' of exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4097
},
"Public method '{0}' of exported class has or is using name '{1}' from external module {2} but cannot be named.": {
"category": "Error",
"code": 4098
},
"Public method '{0}' of exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4099
},
"Public method '{0}' of exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4100
},
"Method '{0}' of exported interface has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4101
},
"Method '{0}' of exported interface has or is using private name '{1}'.": {
"category": "Error",
"code": 4102
},
"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
Copy path View file
@@ -736,15 +736,17 @@ namespace ts {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
export function createTypeOperatorNode(type: TypeNode) {
export function createTypeOperatorNode(type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | TypeNode, type?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
node.operator = SyntaxKind.KeyOfKeyword;
node.type = parenthesizeElementTypeMember(type);
node.operator = typeof operatorOrType === "number" ? operatorOrType : SyntaxKind.KeyOfKeyword;
node.type = parenthesizeElementTypeMember(typeof operatorOrType === "number" ? type : operatorOrType);
return node;
}
export function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) {
return node.type !== type ? updateNode(createTypeOperatorNode(type), node) : node;
return node.type !== type ? updateNode(createTypeOperatorNode(node.operator, type), node) : node;

This comment has been minimized.

@weswigham

weswigham Oct 5, 2017

Member

This should check node.operator in addition to node.type, right?

This comment has been minimized.

@rbuckton

rbuckton Oct 6, 2017

Member

No. operator is not a Node and you can't change it during update. We have a very small number of cases where we allow this, but generally we shouldn't. If you want to change the operator you should call createTypeOperatorNode instead.

}
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
Copy path View file
@@ -2665,8 +2665,8 @@ namespace ts {
case SyntaxKind.AnyKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.ObjectKeyword:
@@ -2720,6 +2720,7 @@ namespace ts {
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UniqueKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
@@ -2805,7 +2806,7 @@ namespace ts {
return finishNode(postfix);
}
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) {
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword) {
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
parseExpected(operator);
node.operator = operator;
@@ -2814,9 +2815,11 @@ namespace ts {
}
function parseTypeOperatorOrHigher(): TypeNode {
switch (token()) {
const operator = token();
switch (operator) {
case SyntaxKind.KeyOfKeyword:
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
case SyntaxKind.UniqueKeyword:
return parseTypeOperator(operator);
case SyntaxKind.DotDotDotToken: {
const result = createNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType;
nextToken();
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.