8000 update check for object literal properties according to ECMA spec · robertknight/TypeScript@ddfd0fe · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit ddfd0fe

Browse files
committed
update check for object literal properties according to ECMA spec
1 parent 259f8a2 commit ddfd0fe

9 files changed

+116
-161
lines changed

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ module ts {
9999
A_constructor_implementation_cannot_be_declared_in_an_ambient_context: { code: 1111, category: DiagnosticCategory.Error, key: "A constructor implementation cannot be declared in an ambient context." },
100100
A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." },
101101
A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." },
102-
Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "Object literal cannot contain more than one property with the same name in the strict mode." },
102+
An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple properties with the same name in strict mode." },
103+
An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name: { code: 1115, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple get/set accessors with the same name." },
104+
An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1116, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." },
103105
Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
104106
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead." },
105107
Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." },

src/compiler/diagnosticMessages.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,10 +388,18 @@
388388
"category": "Error",
389389
"code": 1113
390390
},
391-
"Object literal cannot contain more than one property with the same name in the strict mode.": {
391+
"An object literal cannot have multiple properties with the same name in strict mode.": {
392392
"category": "Error",
393393
"code": 1114
394394
},
395+
"An object literal cannot have multiple get/set accessors with the same name.": {
396+
"category": "Error",
397+
"code": 1115
398+
},
399+
"An object literal cannot have property and accessor with the same name.": {
400+
"category": "Error",
401+
"code": 1116
402+
},
395403
"Duplicate identifier '{0}'.": {
396404
"category": "Error",
397405
"code": 2000

src/compiler/parser.ts

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ module ts {
131131

132132
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
133133
function isUseStrictPrologueDirective(node: Node): boolean {
134+
Debug.assert(isPrologueDirective(node));
134135
return (<Identifier>(<ExpressionStatement>node).expression).text === "use strict";
135136
}
136137

@@ -1415,7 +1416,7 @@ module ts {
14151416

14161417
// Now see if we might be in cases '2' or '3'.
14171418
// If the expression was a LHS expression, and we have an assignment operator, then
1418-
// we're in '2' or '3'. Consume the assignement and return.
1419+
// we're in '2' or '3'. Consume the assignment and return.
14191420
if (isLeftHandSideExpression(expr) && isAssignmentOperator()) {
14201421
if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) {
14211422
// ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an
@@ -1947,23 +1948,61 @@ module ts {
19471948
if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine;
19481949
node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, TrailingCommaBehavior.Preserve);
19491950
parseExpected(SyntaxKind.CloseBraceToken);
1950-
if (isInStrictMode) {
1951-
var seen: Map<boolean> = {};
1952-
forEach(node.properties, (p: Node) => {
1953-
// ECMA-262 11.1.5 Object Initialiser
1954-
// If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true
1955-
// a.This production is contained in strict code and IsDataDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true.
1956-
if (p.kind === SyntaxKind.PropertyAssignment) {
1957-
var name = (<PropertyDeclaration>p).name;
1958-
if (hasProperty(seen, name.text)) {
1959-
grammarErrorOnNode(name, Diagnostics.Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode);
1951+
1952+
var seen: Map<SymbolFlags> = {};
1953+
var Property = 1;
1954+
var GetAccessor = 2;
1955+
var SetAccesor = 4;
1956+
var GetOrSetAccessor = GetAccessor | SetAccesor;
1957+
forEach(node.properties, (p: Declaration) => {
1958+
if (p.kind === SyntaxKind.OmittedExpression) {
1959+
return;
1960+
}
1961+
// ECMA-262 11.1.5 Object Initialiser
1962+
// If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true
1963+
// a.This production is contained in strict code and IsDataDescriptor(previous) is true and
1964+
// IsDataDescriptor(propId.descriptor) is true.
1965+
// b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true.
1966+
// c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true.
1967+
// d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true
1968+
// and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields
1969+
var currentKind: number;
1970+
if (p.kind === SyntaxKind.PropertyAssignment) {
1971+
currentKind = Property;
1972+
}
1973+
else if (p.kind === SyntaxKind.GetAccessor) {
1974+
currentKind = GetAccessor;
1975+
}
1976+
else if (p.kind === SyntaxKind.SetAccessor) {
1977+
currentKind = SetAccesor;
1978+
}
1979+
else {
1980+
Debug.fail("Unexpected syntax kind:" + SyntaxKind[p.kind]);
1981+
}
1982+
1983+
if (!hasProperty(seen, p.name.text)) {
1984+
seen[p.name.text] = currentKind;
1985+
}
1986+
else {
1987+
var existingKind = seen[p.name.text];
1988+
if (currentKind === Property && existingKind === Property) {
1989+
if (isInStrictMode) {
1990+
grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode);
1991+
}
1992+
}
1993+
else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) {
1994+
if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) {
1995+
seen[p.name.text] = currentKind | existingKind;
19601996
}
19611997
else {
1962-
seen[name.text] = true;
1998+
grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name);
19631999
}
19642000
}
1965-
});
1966-
}
2001+
else {
2002+
grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name);
2003+
}
2004+
}
2005+
});
19672006
return finishNode(node);
19682007
}
19692008

@@ -2133,16 +2172,18 @@ module ts {
21332172

21342173
function parseWithStatement(): WithStatement {
21352174
var node = <WithStatement>createNode(SyntaxKind.WithStatement);
2175+
var startPos = scanner.getTokenPos();
21362176
parseExpected(SyntaxKind.WithKeyword);
2177+
var endPos = scanner.getStartPos();
21372178
parseExpected(SyntaxKind.OpenParenToken);
21382179
node.expression = parseExpression();
21392180
parseExpected(SyntaxKind.CloseParenToken);
21402181
node.statement = parseStatement();
21412182
node = finishNode(node);
21422183
if (isInStrictMode) {
21432184
// Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such
2144-
// a context is an SyntaxError(12.10)
2145-
grammarErrorOnNode(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode);
2185+
// a context is an
2186+
grammarErrorAtPos(startPos, endPos - startPos, Diagnostics.with_statements_are_not_allowed_in_strict_mode)
21462187
}
21472188
return node;
21482189
}

tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (8 errors) ====
1+
==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (9 errors) ====
22
var x = {
33
a: 1,
44
b: true, // OK
@@ -30,6 +30,8 @@
3030
~
3131
!!! Accessors are only available when targeting ECMAScript 5 and higher.
3232
~
33+
!!! An object literal cannot have multiple get/set accessors with the same name.
34+
~
3335
!!! Duplicate identifier 'a'.
3436
};
3537

tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
x: 1,
55
x: 2
66
~
7-
!!! Object literal cannot contain more than one property with the same name in the strict mode.
7+
!!! An object literal cannot have multiple properties with the same name in strict mode.
88
~
99
!!! Duplicate identifier 'x'.
1010
}

tests/baselines/reference/objectLiteralErrors.errors.txt

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (41 errors) ====
1+
==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (59 errors) ====
22

33
// Multiple properties with the same name
44
var e1 = { a: 0, a: 0 };
@@ -59,57 +59,93 @@
5959
// Accessor and property with the same name
6060
var f1 = { a: 0, get a() { return 0; } };
6161
~
62+
!!! An object literal cannot have property and accessor with the same name.
63+
~
6264
!!! Duplicate identifier 'a'.
6365
var f2 = { a: '', get a() { return ''; } };
6466
~
67+
!!! An object literal cannot have property and accessor with the same name.
68+
~
6569
!!! Duplicate identifier 'a'.
6670
var f3 = { a: 0, get a() { return ''; } };
6771
~
72+
!!! An object literal cannot have property and accessor with the same name.
73+
~
6874
!!! Duplicate identifier 'a'.
6975
var f4 = { a: true, get a() { return false; } };
7076
~
77+
!!! An object literal cannot have property and accessor with the same name.
78+
~
7179
!!! Duplicate identifier 'a'.
7280
var f5 = { a: {}, get a() { return {}; } };
7381
~
82+
!!! An object literal cannot have property and accessor with the same name.
83+
~
7484
!!! Duplicate identifier 'a'.
7585
var f6 = { a: 0, get 'a'() { return 0; } };
7686
~~~
87+
!!! An object literal cannot have property and accessor with the same name.
88+
~~~
7789
!!! Duplicate identifier ''a''.
7890
var f7 = { 'a': 0, get a() { return 0; } };
7991
~
92+
!!! An object literal cannot have property and accessor with the same name.
93+
~
8094
!!! Duplicate identifier 'a'.
8195
var f8 = { 'a': 0, get "a"() { return 0; } };
8296
~~~
97+
!!! An object literal cannot have property and accessor with the same name.
98+
~~~
8399
!!! Duplicate identifier '"a"'.
84100
var f9 = { 'a': 0, get 'a'() { return 0; } };
85101
~~~
102+
!!! An object literal cannot have property and accessor with the same name.
103+
~~~
86104
!!! Duplicate identifier ''a''.
87105
var f10 = { "a": 0, get 'a'() { return 0; } };
88106
~~~
107+
!!! An object literal cannot have property and accessor with the same name.
108+
~~~
89109
!!! Duplicate identifier ''a''.
90110
var f11 = { 1.0: 0, get '1'() { return 0; } };
91111
~~~
112+
!!! An object literal cannot have property and accessor with the same name.
113+
~~~
92114
!!! Duplicate identifier ''1''.
93115
var f12 = { 0: 0, get 0() { return 0; } };
94116
~
117+
!!! An object literal cannot have property and accessor with the same name.
118+
~
95119
!!! Duplicate identifier '0'.
96120
var f13 = { 0: 0, get 0() { return 0; } };
97121
~
122+
!!! An object literal cannot have property and accessor with the same name.
123+
~
98124
!!! Duplicate identifier '0'.
99125
var f14 = { 0: 0, get 0x0() { return 0; } };
100126
~~~
127+
!!! An object literal cannot have property and accessor with the same name.
128+
~~~
101129
!!! Duplicate identifier '0x0'.
102130
var f14 = { 0: 0, get 000() { return 0; } };
103131
~~~
132+
!!! An object literal cannot have property and accessor with the same name.
133+
~~~
104134
!!! Duplicate identifier '000'.
105135
var f15 = { "100": 0, get 1e2() { return 0; } };
106136
~~~
137+
!!! An object literal cannot have property and accessor with the same name.
138+
~~~
107139
!!! Duplicate identifier '1e2'.
108140
var f16 = { 0x20: 0, get 3.2e1() { return 0; } };
109141
~~~~~
142+
!!! An object literal cannot have property and accessor with the same name.
143+
~~~~~
110144
!!! Duplicate identifier '3.2e1'.
111145
var f17 = { a: 0, get b() { return 1; }, get a() { return 0; } };
112146
~
147+
!!! An object literal cannot have property and accessor with the same name.
148+
~
113149
!!! Duplicate identifier 'a'.
114150

115151
// Get and set accessor with mismatched type annotations

0 commit comments

Comments
 (0)
0