Skip to content

Commit

Permalink
Fixes microsoft#8675 by allowing duplicate identifiers across declara…
Browse files Browse the repository at this point in the history
…tions.

Duplicate identifiers *within the same block* are still disallowed.
  • Loading branch information
RyanCavanaugh committed May 19, 2016
1 parent 9ffc7a9 commit 115317e
Show file tree
Hide file tree
Showing 57 changed files with 676 additions and 622 deletions.
89 changes: 88 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12893,6 +12893,90 @@ namespace ts {
}
}

function checkClassForDuplicateDeclarations(node: ClassLikeDeclaration) {
const getter = 1, setter = 2, property = getter | setter;

const instanceNames: Map<number> = {};
const staticNames: Map<number> = {};
for (const member of node.members) {
let memberName: string;
if (member.name) {
switch (member.name.kind) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.Identifier:
memberName = (member.name as LiteralExpression|Identifier).text;
break;
default:
continue;
}
}

const static = forEach(member.modifiers, m => m.kind === SyntaxKind.StaticKeyword);
const names = static ? staticNames : instanceNames;
switch (member.kind) {
case SyntaxKind.Constructor:
for (const param of (member as ConstructorDeclaration).parameters) {
if (isParameterPropertyDeclaration(param)) {
addName(names, param, (param.name as Identifier).text, property);
}
}
break;

case SyntaxKind.GetAccessor:
addName(names, member.name, memberName, getter);
break;

case SyntaxKind.SetAccessor:
addName(names, member.name, memberName, setter);
break;

case SyntaxKind.PropertyDeclaration:
addName(names, member.name, memberName, property);
break;
}
}

function addName(names: Map<number>, location: Node, name: string, meaning: number) {
if (hasProperty(names, name)) {
const prev = names[name];
if (prev & meaning) {
error(location, Diagnostics.Duplicate_identifier_0, name);
} else {
names[name] = prev | meaning;
}
}
else {
names[name] = meaning;
}
}
}

function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) {
const names: Map<boolean> = {};
for (const member of node.members) {
if (member.kind == SyntaxKind.PropertySignature) {
let memberName: string;
switch (member.name.kind) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.Identifier:
memberName = (member.name as LiteralExpression|Identifier).text;
break;
default:
continue;
}

if (hasProperty(names, memberName)) {
error(member, Diagnostics.Duplicate_identifier_0, memberName);
}
else {
names[memberName] = true;
}
}
}
}

function checkTypeForDuplicateIndexSignatures(node: Node) {
if (node.kind === SyntaxKind.InterfaceDeclaration) {
const nodeSymbol = getSymbolOfNode(node);
Expand Down Expand Up @@ -13177,6 +13261,7 @@ namespace ts {
const type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
checkIndexConstraints(type);
checkTypeForDuplicateIndexSignatures(node);
checkObjectTypeForDuplicateDeclarations(node);
}
}

Expand Down Expand Up @@ -15176,6 +15261,7 @@ namespace ts {
const typeWithThis = getTypeWithThisArgument(type);
const staticType = <ObjectType>getTypeOfSymbol(symbol);
checkTypeParameterListsIdentical(node, symbol);
checkClassForDuplicateDeclarations(node);

const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
Expand Down Expand Up @@ -15453,6 +15539,7 @@ namespace ts {
checkIndexConstraints(type);
}
}
checkObjectTypeForDuplicateDeclarations(node);
}
forEach(getInterfaceBaseTypeNodes(node), heritageElement => {
if (!isSupportedExpressionWithTypeArguments(heritageElement)) {
Expand Down Expand Up @@ -18146,7 +18233,7 @@ namespace ts {
else {
const existingKind = seen[(<Identifier>name).text];
if (currentKind === Property && existingKind === Property) {
continue;
grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, (<Identifier>name).text);
}
else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) {
if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2027,7 +2027,7 @@ namespace ts {
BlockScopedVariableExcludes = Value,

ParameterExcludes = Value,
PropertyExcludes = Value,
PropertyExcludes = None,
EnumMemberExcludes = Value,
FunctionExcludes = Value & ~(Function | ValueModule),
ClassExcludes = (Value | Type) & ~(ValueModule | Interface), // class-interface mergability done in checker.ts
Expand Down
11 changes: 1 addition & 10 deletions tests/baselines/reference/binaryIntegerLiteralError.errors.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts(2,17): error TS1005: ',' expected.
tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts(3,17): error TS1005: ',' expected.
tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts(6,5): error TS2300: Duplicate identifier '0b11010'.
tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts(7,5): error TS2300: Duplicate identifier '26'.
tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts(8,5): error TS2300: Duplicate identifier '"26"'.


==== tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts (5 errors) ====
==== tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralError.ts (2 errors) ====
// error
var bin1 = 0B1102110;
~~~~
Expand All @@ -16,13 +13,7 @@ tests/cases/conformance/es6/binaryAndOctalIntegerLiteral/binaryIntegerLiteralErr

var obj1 = {
0b11010: "hi",
~~~~~~~
!!! error TS2300: Duplicate identifier '0b11010'.
26: "Hello",
~~
!!! error TS2300: Duplicate identifier '26'.
"26": "world",
~~~~
!!! error TS2300: Duplicate identifier '"26"'.
};

Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(4,14): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(11,9): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(20,5): error TS2300: Duplicate identifier 'foo'.
tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(20,9): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(20,15): error TS1005: '{' expected.
tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(21,5): error TS2300: Duplicate identifier 'foo'.


==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts (6 errors) ====
==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts (4 errors) ====
// Optional parameters allow initializers only in implementation signatures
// All the below declarations are errors

Expand All @@ -31,15 +29,11 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWit

var b = {
foo(x = 1), // error
~~~
!!! error TS2300: Duplicate identifier 'foo'.
~~~~~
!!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
~
!!! error TS1005: '{' expected.
foo(x = 1) { }, // error
~~~
!!! error TS2300: Duplicate identifier 'foo'.
}

b.foo();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
=== tests/cases/conformance/classes/classDeclarations/classAndInterfaceMergeConflictingMembers.ts ===
declare class C1 {
>C1 : Symbol(C1, Decl(classAndInterfaceMergeConflictingMembers.ts, 0, 0), Decl(classAndInterfaceMergeConflictingMembers.ts, 2, 1))

public x : number;
>x : Symbol(C1.x, Decl(classAndInterfaceMergeConflictingMembers.ts, 0, 18), Decl(classAndInterfaceMergeConflictingMembers.ts, 4, 14))
}

interface C1 {
>C1 : Symbol(C1, Decl(classAndInterfaceMergeConflictingMembers.ts, 0, 0), Decl(classAndInterfaceMergeConflictingMembers.ts, 2, 1))

x : number;
>x : Symbol(C1.x, Decl(classAndInterfaceMergeConflictingMembers.ts, 0, 18), Decl(classAndInterfaceMergeConflictingMembers.ts, 4, 14))
}

declare class C2 {
>C2 : Symbol(C2, Decl(classAndInterfaceMergeConflictingMembers.ts, 6, 1), Decl(classAndInterfaceMergeConflictingMembers.ts, 10, 1))

protected x : number;
>x : Symbol(C2.x, Decl(classAndInterfaceMergeConflictingMembers.ts, 8, 18), Decl(classAndInterfaceMergeConflictingMembers.ts, 12, 14))
}

interface C2 {
>C2 : Symbol(C2, Decl(classAndInterfaceMergeConflictingMembers.ts, 6, 1), Decl(classAndInterfaceMergeConflictingMembers.ts, 10, 1))

x : number;
>x : Symbol(C2.x, Decl(classAndInterfaceMergeConflictingMembers.ts, 8, 18), Decl(classAndInterfaceMergeConflictingMembers.ts, 12, 14))
}

declare class C3 {
>C3 : Symbol(C3, Decl(classAndInterfaceMergeConflictingMembers.ts, 14, 1), Decl(classAndInterfaceMergeConflictingMembers.ts, 18, 1))

private x : number;
>x : Symbol(C3.x, Decl(classAndInterfaceMergeConflictingMembers.ts, 16, 18), Decl(classAndInterfaceMergeConflictingMembers.ts, 20, 14))
}

interface C3 {
>C3 : Symbol(C3, Decl(classAndInterfaceMergeConflictingMembers.ts, 14, 1), Decl(classAndInterfaceMergeConflictingMembers.ts, 18, 1))

x : number;
>x : Symbol(C3.x, Decl(classAndInterfaceMergeConflictingMembers.ts, 16, 18), Decl(classAndInterfaceMergeConflictingMembers.ts, 20, 14))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
=== tests/cases/conformance/classes/classDeclarations/classAndInterfaceMergeConflictingMembers.ts ===
declare class C1 {
>C1 : C1

public x : number;
>x : number
}

interface C1 {
>C1 : C1

x : number;
>x : number
}

declare class C2 {
>C2 : C2

protected x : number;
>x : number
}

interface C2 {
>C2 : C2

x : number;
>x : number
}

declare class C3 {
>C3 : C3

private x : number;
>x : number
}

interface C3 {
>C3 : C3

x : number;
>x : number
}
27 changes: 0 additions & 27 deletions tests/baselines/reference/classAndInterfaceWithSameName.errors.txt

This file was deleted.

26 changes: 26 additions & 0 deletions tests/baselines/reference/classAndInterfaceWithSameName.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
=== tests/cases/conformance/classes/classDeclarations/classAndInterfaceWithSameName.ts ===
class C { foo: string; }
>C : Symbol(C, Decl(classAndInterfaceWithSameName.ts, 0, 0), Decl(classAndInterfaceWithSameName.ts, 0, 24))
>foo : Symbol(C.foo, Decl(classAndInterfaceWithSameName.ts, 0, 9), Decl(classAndInterfaceWithSameName.ts, 1, 13))

interface C { foo: string; }
>C : Symbol(C, Decl(classAndInterfaceWithSameName.ts, 0, 0), Decl(classAndInterfaceWithSameName.ts, 0, 24))
>foo : Symbol(C.foo, Decl(classAndInterfaceWithSameName.ts, 0, 9), Decl(classAndInterfaceWithSameName.ts, 1, 13))

module M {
>M : Symbol(M, Decl(classAndInterfaceWithSameName.ts, 1, 28))

class D {
>D : Symbol(D, Decl(classAndInterfaceWithSameName.ts, 3, 10), Decl(classAndInterfaceWithSameName.ts, 6, 5))

bar: string;
>bar : Symbol(D.bar, Decl(classAndInterfaceWithSameName.ts, 4, 13), Decl(classAndInterfaceWithSameName.ts, 8, 17))
}

interface D {
>D : Symbol(D, Decl(classAndInterfaceWithSameName.ts, 3, 10), Decl(classAndInterfaceWithSameName.ts, 6, 5))

bar: string;
>bar : Symbol(D.bar, Decl(classAndInterfaceWithSameName.ts, 4, 13), Decl(classAndInterfaceWithSameName.ts, 8, 17))
}
}
Loading

0 comments on commit 115317e

Please sign in to comment.