Skip to content

Commit acc2550

Browse files
author
Yui
committed
Merge pull request #1127 from Microsoft/shorthandProperty
Shorthand property
2 parents d5cfceb + 1b66ee6 commit acc2550

File tree

53 files changed

+1230
-37
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1230
-37
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ module ts {
380380
break;
381381
case SyntaxKind.Property:
382382
case SyntaxKind.PropertyAssignment:
383+
case SyntaxKind.ShorthandPropertyAssignment:
383384
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
384385
break;
385386
case SyntaxKind.EnumMember:

src/compiler/checker.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ module ts {
9393
getReturnTypeOfSignature: getReturnTypeOfSignature,
9494
getSymbolsInScope: getSymbolsInScope,
9595
getSymbolInfo: getSymbolInfo,
96+
getShorthandAssignmentValueSymbol: getShorthandAssignmentValueSymbol,
9697
getTypeOfNode: getTypeOfNode,
9798
typeToString: typeToString,
9899
getSymbolDisplayBuilder: getSymbolDisplayBuilder,
@@ -109,6 +110,7 @@ module ts {
109110
getAliasedSymbol: resolveImport,
110111
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
111112
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
113+
hasEarlyErrors: hasEarlyErrors,
112114
isEmitBlocked: isEmitBlocked
113115
};
114116

@@ -1665,6 +1667,13 @@ module ts {
16651667
}
16661668
return type;
16671669
}
1670+
1671+
// If it is a short-hand property assignment; Use the type of the identifier
1672+
if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) {
1673+
var type = checkIdentifier(<Identifier>declaration.name);
1674+
return type
1675+
}
1676+
16681677
// Rest parameters default to type any[], other parameters default to type any
16691678
var type = declaration.flags & NodeFlags.Rest ? createArrayType(anyType) : anyType;
16701679
checkImplicitAny(type);
@@ -2399,7 +2408,7 @@ module ts {
23992408
}
24002409

24012410
// Return the symbol for the property with the given name in the given type. Creates synthetic union properties when
2402-
// necessary, maps primtive types and type parameters are to their apparent types, and augments with properties from
2411+
// necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
24032412
// Object and Function as appropriate.
24042413
function getPropertyOfType(type: Type, name: string): Symbol {
24052414
if (type.flags & TypeFlags.Union) {
@@ -2434,7 +2443,7 @@ module ts {
24342443
}
24352444

24362445
// Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and
2437-
// maps primtive types and type parameters are to their apparent types.
2446+
// maps primitive types and type parameters are to their apparent types.
24382447
function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
24392448
return getSignaturesOfObjectOrUnionType(getApparentType(type), kind);
24402449
}
@@ -2447,7 +2456,7 @@ module ts {
24472456
}
24482457

24492458
// Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
2450-
// maps primtive types and type parameters are to their apparent types.
2459+
// maps primitive types and type parameters are to their apparent types.
24512460
function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
24522461
return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind);
24532462
}
@@ -5000,7 +5009,15 @@ module ts {
50005009
if (hasProperty(members, id)) {
50015010
var member = members[id];
50025011
if (member.flags & SymbolFlags.Property) {
5003-
var type = checkExpression((<PropertyDeclaration>member.declarations[0]).initializer, contextualMapper);
5012+
var memberDecl = <PropertyDeclaration>member.declarations[0];
5013+
var type: Type;
5014+
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
5015+
type = checkExpression(memberDecl.initializer, contextualMapper);
5016+
}
5017+
else {
5018+
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
5019+
type = checkExpression(memberDecl.name, contextualMapper);
5020+
}
50045021
var prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
50055022
prop.declarations = member.declarations;
50065023
prop.parent = member.parent;
@@ -8816,6 +8833,16 @@ module ts {
88168833
return undefined;
88178834
}
88188835

8836+
function getShorthandAssignmentValueSymbol(location: Node): Symbol {
8837+
// The function returns a value symbol of an identifier in the short-hand property assignment.
8838+
// This is necessary as an identifier in short-hand property assignment can contains two meaning:
8839+
// property name and property value.
8840+
if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) {
8841+
return resolveEntityName(location, (<ShortHandPropertyDeclaration>location).name, SymbolFlags.Value);
8842+
}
8843+
return undefined;
8844+
}
8845+
88198846
function getTypeOfNode(node: Node): Type {
88208847
if (isInsideWithStatementBody(node)) {
88218848
// We cannot answer semantic questions within a with block, do not proceed any further

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ module ts {
122122
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
123123
Invalid_template_literal_expected: { code: 1158, category: DiagnosticCategory.Error, key: "Invalid template literal; expected '}'" },
124124
Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1159, category: DiagnosticCategory.Error, key: "Tagged templates are only available when targeting ECMAScript 6 and higher." },
125+
A_object_member_cannot_be_declared_optional: { code: 1160, category: DiagnosticCategory.Error, key: "A object member cannot be declared optional." },
125126
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
126127
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." },
127128
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,11 @@
480480
"code": 1159
481481
},
482482

483+
"A object member cannot be declared optional.": {
484+
"category": "Error",
485+
"code": 1160
486+
},
487+
483488
"Duplicate identifier '{0}'.": {
484489
"category": "Error",
485490
"code": 2300

src/compiler/emitter.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -927,13 +927,14 @@ module ts {
927927
}
928928
}
929929

930-
function isNonExpressionIdentifier(node: Identifier) {
930+
function isNotExpressionIdentifier(node: Identifier) {
931931
var parent = node.parent;
932932
switch (parent.kind) {
933933
case SyntaxKind.Parameter:
934934
case SyntaxKind.VariableDeclaration:
935935
case SyntaxKind.Property:
936936
case SyntaxKind.PropertyAssignment:
937+
case SyntaxKind.ShorthandPropertyAssignment:
937938
case SyntaxKind.EnumMember:
938939
case SyntaxKind.Method:
939940
case SyntaxKind.FunctionDeclaration:
@@ -957,17 +958,24 @@ module ts {
957958
}
958959
}
959960

960-
function emitIdentifier(node: Identifier) {
961-
if (!isNonExpressionIdentifier(node)) {
962-
var prefix = resolver.getExpressionNamePrefix(node);
963-
if (prefix) {
964-
write(prefix);
965-
write(".");
966-
}
961+
function emitExpressionIdentifier(node: Identifier) {
962+
var prefix = resolver.getExpressionNamePrefix(node);
963+
if (prefix) {
964+
write(prefix);
965+
write(".");
967966
}
968967
write(getSourceTextOfLocalNode(node));
969968
}
970969

970+
function emitIdentifier(node: Identifier) {
971+
if (!isNotExpressionIdentifier(node)) {
972+
emitExpressionIdentifier(node);
973+
}
974+
else {
975+
write(getSourceTextOfLocalNode(node));
976+
}
977+
}
978+
971979
function emitThis(node: Node) {
972980
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalThis) {
973981
write("_this");
@@ -1033,6 +1041,36 @@ module ts {
10331041
emitTrailingComments(node);
10341042
}
10351043

1044+
function emitShortHandPropertyAssignment(node: ShortHandPropertyDeclaration) {
1045+
function emitAsNormalPropertyAssignment() {
1046+
emitLeadingComments(node);
1047+
// Emit identifier as an identifier
1048+
emit(node.name);
1049+
write(": ");
1050+
// Even though this is stored as identified because it is in short-hand property assignment,
1051+
// treated it as expression
1052+
emitExpressionIdentifier(node.name);
1053+
emitTrailingComments(node);
1054+
}
1055+
1056+
if (compilerOptions.target < ScriptTarget.ES6) {
1057+
emitAsNormalPropertyAssignment();
1058+
}
1059+
else if (compilerOptions.target >= ScriptTarget.ES6) {
1060+
// If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment
1061+
var prefix = resolver.getExpressionNamePrefix(node.name);
1062+
if (prefix) {
1063+
emitAsNormalPropertyAssignment();
1064+
}
1065+
// If short-hand property has no prefix, emit it as short-hand.
1066+
else {
1067+
emitLeadingComments(node);
1068+
emit(node.name);
1069+
emitTrailingComments(node);
1070+
}
1071+
}
1072+
}
1073+
10361074
function tryEmitConstantValue(node: PropertyAccess | IndexedAccess): boolean {
10371075
var constantValue = resolver.getConstantValue(node);
10381076
if (constantValue !== undefined) {
@@ -2250,6 +2288,8 @@ module ts {
22502288
return emitObjectLiteral(<ObjectLiteral>node);
22512289
case SyntaxKind.PropertyAssignment:
22522290
return emitPropertyAssignment(<PropertyDeclaration>node);
2291+
case SyntaxKind.ShorthandPropertyAssignment:
2292+
return emitShortHandPropertyAssignment(<ShortHandPropertyDeclaration>node);
22532293
case SyntaxKind.PropertyAccess:
22542294
return emitPropertyAccess(<PropertyAccess>node);
22552295
case SyntaxKind.IndexedAccess:

src/compiler/parser.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ module ts {
202202
child((<ParameterDeclaration>node).initializer);
203203
case SyntaxKind.Property:
204204
case SyntaxKind.PropertyAssignment:
205+
case SyntaxKind.ShorthandPropertyAssignment:
205206
return child((<PropertyDeclaration>node).name) ||
206207
child((<PropertyDeclaration>node).type) ||
207208
child((<PropertyDeclaration>node).initializer);
@@ -580,6 +581,7 @@ module ts {
580581
case SyntaxKind.VariableDeclaration:
581582
case SyntaxKind.Property:
582583
case SyntaxKind.PropertyAssignment:
584+
case SyntaxKind.ShorthandPropertyAssignment:
583585
case SyntaxKind.EnumMember:
584586
case SyntaxKind.Method:
585587
case SyntaxKind.FunctionDeclaration:
@@ -2729,22 +2731,41 @@ module ts {
27292731
return finishNode(node);
27302732
}
27312733

2732-
function parsePropertyAssignment(): PropertyDeclaration {
2733-
var node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment);
2734-
node.name = parsePropertyName();
2734+
function parsePropertyAssignment(): Declaration {
2735+
var nodePos = scanner.getStartPos();
2736+
var nameToken = token;
2737+
var propertyName = parsePropertyName();
2738+
var node: Declaration;
27352739
if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
2740+
node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
2741+
node.name = propertyName;
27362742
var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false);
27372743
var body = parseBody(/* ignoreMissingOpenBrace */ false);
27382744
// do not propagate property name as name for function expression
27392745
// for scenarios like
27402746
// var x = 1;
27412747
// var y = { x() { } }
27422748
// otherwise this will bring y.x into the scope of x which is incorrect
2743-
node.initializer = makeFunctionExpression(SyntaxKind.FunctionExpression, node.pos, undefined, sig, body);
2749+
(<PropertyDeclaration>node).initializer = makeFunctionExpression(SyntaxKind.FunctionExpression, node.pos, undefined, sig, body);
2750+
return finishNode(node);
2751+
}
2752+
// Disallow optional property assignment
2753+
if (token === SyntaxKind.QuestionToken) {
2754+
var questionStart = scanner.getTokenPos();
2755+
grammarErrorAtPos(questionStart, scanner.getStartPos() - questionStart, Diagnostics.A_object_member_cannot_be_declared_optional);
2756+
nextToken();
2757+
}
2758+
2759+
// Parse to check if it is short-hand property assignment or normal property assignment
2760+
if (token !== SyntaxKind.ColonToken && nameToken === SyntaxKind.Identifier) {
2761+
node = <ShortHandPropertyDeclaration>createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos);
2762+
node.name = propertyName;
27442763
}
27452764
else {
2765+
node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
2766+
node.name = propertyName;
27462767
parseExpected(SyntaxKind.ColonToken);
2747-
node.initializer = parseAssignmentExpression(false);
2768+
(<PropertyDeclaration>node).initializer = parseAssignmentExpression(false);
27482769
}
27492770
return finishNode(node);
27502771
}
@@ -2794,6 +2815,9 @@ module ts {
27942815
if (p.kind === SyntaxKind.PropertyAssignment) {
27952816
currentKind = Property;
27962817
}
2818+
else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
2819+
currentKind = Property;
2820+
}
27972821
else if (p.kind === SyntaxKind.GetAccessor) {
27982822
currentKind = GetAccessor;
27992823
}

src/compiler/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ module ts {
167167
ArrayLiteral,
168168
ObjectLiteral,
169169
PropertyAssignment,
170+
ShorthandPropertyAssignment,
170171
PropertyAccess,
171172
IndexedAccess,
172173
CallExpression,
@@ -335,6 +336,10 @@ module ts {
335336
initializer?: Expression;
336337
}
337338

339+
export interface ShortHandPropertyDeclaration extends Declaration {
340+
name: Identifier;
341+
}
342+
338343
export interface ParameterDeclaration extends VariableDeclaration { }
339344

340345
/**
@@ -719,6 +724,7 @@ module ts {
719724
getReturnTypeOfSignature(signature: Signature): Type;
720725
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
721726
getSymbolInfo(node: Node): Symbol;
727+
getShorthandAssignmentValueSymbol(location: Node): Symbol;
722728
getTypeOfNode(node: Node): Type;
723729
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
724730
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;

0 commit comments

Comments
 (0)