Skip to content

Commit e174fe4

Browse files
Merge pull request #1575 from chrisbubernak/betterErrorsForTypesWithSameName
Better errors for types with same name
2 parents 9f49a16 + afc9f45 commit e174fe4

8 files changed

+109
-23
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ module ts {
10691069
* Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope
10701070
* Meaning needs to be specified if the enclosing declaration is given
10711071
*/
1072-
function buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void {
1072+
function buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags, typeFlags?: TypeFormatFlags): void {
10731073
var parentSymbol: Symbol;
10741074
function appendParentTypeArgumentsAndSymbolName(symbol: Symbol): void {
10751075
if (parentSymbol) {
@@ -1131,11 +1131,12 @@ module ts {
11311131
}
11321132
}
11331133

1134-
// Get qualified name
1135-
if (enclosingDeclaration &&
1136-
// TypeParameters do not need qualification
1137-
!(symbol.flags & SymbolFlags.TypeParameter)) {
1138-
1134+
// Get qualified name if the symbol is not a type parameter
1135+
// and there is an enclosing declaration or we specifically
1136+
// asked for it
1137+
var isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
1138+
var typeFormatFlag = TypeFormatFlags.UseFullyQualifiedType & typeFlags;
1139+
if (!isTypeParameter && (enclosingDeclaration || typeFormatFlag)) {
11391140
walkSymbol(symbol, meaning);
11401141
return;
11411142
}
@@ -1158,7 +1159,8 @@ module ts {
11581159
writeTypeReference(<TypeReference>type, flags);
11591160
}
11601161
else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
1161-
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type);
1162+
// The specified symbol flags need to be reinterpreted as type flags
1163+
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
11621164
}
11631165
else if (type.flags & TypeFlags.Tuple) {
11641166
writeTupleType(<TupleType>type);
@@ -1229,17 +1231,18 @@ module ts {
12291231
function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) {
12301232
// Always use 'typeof T' for type of class, enum, and module objects
12311233
if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
1232-
writeTypeofSymbol(type);
1234+
writeTypeofSymbol(type, flags);
12331235
}
12341236
// Use 'typeof T' for types of functions and methods that circularly reference themselves
12351237
else if (shouldWriteTypeOfFunctionSymbol()) {
1236-
writeTypeofSymbol(type);
1238+
writeTypeofSymbol(type, flags);
12371239
}
12381240
else if (typeStack && contains(typeStack, type)) {
12391241
// If type is an anonymous type literal in a type alias declaration, use type alias name
12401242
var typeAlias = getTypeAliasForTypeLiteral(type);
12411243
if (typeAlias) {
1242-
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type);
1244+
// The specified symbol flags need to be reinterpreted as type flags
1245+
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, flags);
12431246
}
12441247
else {
12451248
// Recursive usage, use any
@@ -1273,10 +1276,10 @@ module ts {
12731276
}
12741277
}
12751278

1276-
function writeTypeofSymbol(type: ObjectType) {
1279+
function writeTypeofSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) {
12771280
writeKeyword(writer, SyntaxKind.TypeOfKeyword);
12781281
writeSpace(writer);
1279-
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value);
1282+
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags);
12801283
}
12811284

12821285
function getIndexerParameterName(type: ObjectType, indexKind: IndexKind, fallbackName: string): string {
@@ -3562,7 +3565,13 @@ module ts {
35623565
}
35633566
if (reportErrors) {
35643567
headMessage = headMessage || Diagnostics.Type_0_is_not_assignable_to_type_1;
3565-
reportError(headMessage, typeToString(source), typeToString(target));
3568+
var sourceType = typeToString(source);
3569+
var targetType = typeToString(target);
3570+
if (sourceType === targetType) {
3571+
sourceType = typeToString(source, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
3572+
targetType = typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
3573+
}
3574+
reportError(headMessage, sourceType, targetType);
35663575
}
35673576
return Ternary.False;
35683577
}

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,7 @@ module ts {
10801080
WriteOwnNameForAnyLike = 0x00000010, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc)
10811081
WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature
10821082
InElementType = 0x00000040, // Writing an array or union element type
1083+
UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
10831084
}
10841085

10851086
export const enum SymbolFormatFlags {

tests/baselines/reference/clodulesDerivedClasses.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
tests/cases/compiler/clodulesDerivedClasses.ts(9,7): error TS2417: Class static side 'typeof Path' incorrectly extends base class static side 'typeof Shape'.
22
Types of property 'Utils' are incompatible.
3-
Type 'typeof Utils' is not assignable to type 'typeof Utils'.
3+
Type 'typeof Path.Utils' is not assignable to type 'typeof Shape.Utils'.
44
Property 'convert' is missing in type 'typeof Utils'.
55

66

@@ -17,7 +17,7 @@ tests/cases/compiler/clodulesDerivedClasses.ts(9,7): error TS2417: Class static
1717
~~~~
1818
!!! error TS2417: Class static side 'typeof Path' incorrectly extends base class static side 'typeof Shape'.
1919
!!! error TS2417: Types of property 'Utils' are incompatible.
20-
!!! error TS2417: Type 'typeof Utils' is not assignable to type 'typeof Utils'.
20+
!!! error TS2417: Type 'typeof Path.Utils' is not assignable to type 'typeof Shape.Utils'.
2121
!!! error TS2417: Property 'convert' is missing in type 'typeof Utils'.
2222
name: string;
2323

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
tests/cases/compiler/differentTypesWithSameName.ts(16,15): error TS2345: Argument of type 'variable' is not assignable to parameter of type 'm.variable'.
2+
3+
4+
==== tests/cases/compiler/differentTypesWithSameName.ts (1 errors) ====
5+
module m {
6+
export class variable{
7+
s: string;
8+
}
9+
export function doSomething(v: m.variable) {
10+
11+
}
12+
}
13+
14+
class variable {
15+
t: number;
16+
}
17+
18+
19+
var v: variable = new variable();
20+
m.doSomething(v);
21+
~
22+
!!! error TS2345: Argument of type 'variable' is not assignable to parameter of type 'm.variable'.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [differentTypesWithSameName.ts]
2+
module m {
3+
export class variable{
4+
s: string;
5+
}
6+
export function doSomething(v: m.variable) {
7+
8+
}
9+
}
10+
11+
class variable {
12+
t: number;
13+
}
14+
15+
16+
var v: variable = new variable();
17+
m.doSomething(v);
18+
19+
//// [differentTypesWithSameName.js]
20+
var m;
21+
(function (m) {
22+
var variable = (function () {
23+
function variable() {
24+
}
25+
return variable;
26+
})();
27+
m.variable = variable;
28+
function doSomething(v) {
29+
}
30+
m.doSomething = doSomething;
31+
})(m || (m = {}));
32+
var variable = (function () {
33+
function variable() {
34+
}
35+
return variable;
36+
})();
37+
var v = new variable();
38+
m.doSomething(v);

tests/baselines/reference/everyTypeWithAnnotationAndInvalidInitializer.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAnd
2525
Type 'string' is not assignable to type 'number'.
2626
tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAndInvalidInitializer.ts(50,5): error TS2322: Type 'typeof N' is not assignable to type 'typeof M'.
2727
Types of property 'A' are incompatible.
28-
Type 'typeof A' is not assignable to type 'typeof A'.
29-
Type 'A' is not assignable to type 'A'.
28+
Type 'typeof N.A' is not assignable to type 'typeof M.A'.
29+
Type 'N.A' is not assignable to type 'M.A'.
3030
Property 'name' is missing in type 'A'.
31-
tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAndInvalidInitializer.ts(51,5): error TS2322: Type 'A' is not assignable to type 'A'.
31+
tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAndInvalidInitializer.ts(51,5): error TS2322: Type 'N.A' is not assignable to type 'M.A'.
3232
tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAndInvalidInitializer.ts(52,5): error TS2322: Type '(x: number) => boolean' is not assignable to type '(x: number) => string'.
3333
Type 'boolean' is not assignable to type 'string'.
3434

@@ -124,12 +124,12 @@ tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAnd
124124
~~~~~~~
125125
!!! error TS2322: Type 'typeof N' is not assignable to type 'typeof M'.
126126
!!! error TS2322: Types of property 'A' are incompatible.
127-
!!! error TS2322: Type 'typeof A' is not assignable to type 'typeof A'.
128-
!!! error TS2322: Type 'A' is not assignable to type 'A'.
127+
!!! error TS2322: Type 'typeof N.A' is not assignable to type 'typeof M.A'.
128+
!!! error TS2322: Type 'N.A' is not assignable to type 'M.A'.
129129
!!! error TS2322: Property 'name' is missing in type 'A'.
130130
var aClassInModule: M.A = new N.A();
131131
~~~~~~~~~~~~~~
132-
!!! error TS2322: Type 'A' is not assignable to type 'A'.
132+
!!! error TS2322: Type 'N.A' is not assignable to type 'M.A'.
133133
var aFunctionInModule: typeof M.F2 = F2;
134134
~~~~~~~~~~~~~~~~~
135135
!!! error TS2322: Type '(x: number) => boolean' is not assignable to type '(x: number) => string'.

tests/baselines/reference/qualify.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tests/cases/compiler/qualify.ts(47,13): error TS2322: Type 'I4' is not assignabl
1010
tests/cases/compiler/qualify.ts(48,13): error TS2322: Type 'I4' is not assignable to type '(k: I3) => void'.
1111
tests/cases/compiler/qualify.ts(49,13): error TS2322: Type 'I4' is not assignable to type '{ k: I3; }'.
1212
Property 'k' is missing in type 'I4'.
13-
tests/cases/compiler/qualify.ts(58,5): error TS2322: Type 'I' is not assignable to type 'I'.
13+
tests/cases/compiler/qualify.ts(58,5): error TS2322: Type 'I' is not assignable to type 'T.I'.
1414
Property 'p' is missing in type 'I'.
1515

1616

@@ -93,7 +93,7 @@ tests/cases/compiler/qualify.ts(58,5): error TS2322: Type 'I' is not assignable
9393
var y:I;
9494
var x:T.I=y;
9595
~
96-
!!! error TS2322: Type 'I' is not assignable to type 'I'.
96+
!!! error TS2322: Type 'I' is not assignable to type 'T.I'.
9797
!!! error TS2322: Property 'p' is missing in type 'I'.
9898

9999

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module m {
2+
export class variable{
3+
s: string;
4+
}
5+
export function doSomething(v: m.variable) {
6+
7+
}
8+
}
9+
10+
class variable {
11+
t: number;
12+
}
13+
14+
15+
var v: variable = new variable();
16+
m.doSomething(v);

0 commit comments

Comments
 (0)