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

Skip to content

Commit 6572c82

Browse files
committed
update check for object literal properties according to ECMA spec
1 parent 9112a0e commit 6572c82

9 files changed

+115
-160
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+< 8000 div class="diff-text-inner"> 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

@@ -1416,7 +1417,7 @@ module ts {
14161417

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

@@ -2134,16 +2173,18 @@ module ts {
21342173

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

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