Skip to content

Commit

Permalink
Merge pull request #15473 from Microsoft/dynamicNames
Browse files Browse the repository at this point in the history
Allow dynamic names in types
  • Loading branch information
rbuckton committed Nov 16, 2017
2 parents 062e759 + ccba128 commit b4ea700
Show file tree
Hide file tree
Showing 171 changed files with 10,267 additions and 1,174 deletions.
2 changes: 1 addition & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
639 changes: 525 additions & 114 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

118 changes: 107 additions & 11 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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"));
}
}

Expand Down Expand Up @@ -1227,7 +1238,7 @@ namespace ts {
}

function emitPropertyDeclaration(node: Declaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLateBound(node)) {
return;
}

Expand All @@ -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 ||
Expand Down Expand Up @@ -1387,7 +1396,7 @@ namespace ts {
}

function emitAccessorDeclaration(node: AccessorDeclaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLateBound(node)) {
return;
}

Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1467,7 +1507,7 @@ namespace ts {
}

function writeFunctionDeclaration(node: FunctionLikeDeclaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLateBound(node)) {
return;
}

Expand All @@ -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) {
Expand Down
77 changes: 71 additions & 6 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
},
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand Down
10 changes: 6 additions & 4 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
Expand Down
11 changes: 7 additions & 4 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand Down
Loading

0 comments on commit b4ea700

Please sign in to comment.