Skip to content

Commit b9ebb36

Browse files
committed
Merge pull request #665 from Microsoft/circularTypeInferenceErrors
Report circular type inference errors with -noImplicitAny
2 parents b61c722 + b805037 commit b9ebb36

File tree

8 files changed

+272
-6
lines changed

8 files changed

+272
-6
lines changed

src/compiler/checker.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ module ts {
413413
}
414414
}
415415

416-
function getFullyQualifiedName(symbol: Symbol) {
416+
function getFullyQualifiedName(symbol: Symbol): string {
417417
return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol);
418418
}
419419

@@ -1420,6 +1420,12 @@ module ts {
14201420
}
14211421
else if (links.type === resolvingType) {
14221422
links.type = anyType;
1423+
if (compilerOptions.noImplicitAny) {
1424+
var diagnostic = (<VariableDeclaration>symbol.valueDeclaration).type ?
1425+
Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation :
1426+
Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer;
1427+
error(symbol.valueDeclaration, diagnostic, symbolToString(symbol));
1428+
}
14231429
}
14241430
return links.type;
14251431
}
@@ -1475,7 +1481,7 @@ module ts {
14751481
// Otherwise, fall back to 'any'.
14761482
else {
14771483
if (compilerOptions.noImplicitAny) {
1478-
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbol.name);
1484+
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
14791485
}
14801486

14811487
type = anyType;
@@ -1489,6 +1495,10 @@ module ts {
14891495
}
14901496
else if (links.type === resolvingType) {
14911497
links.type = anyType;
1498+
if (compilerOptions.noImplicitAny) {
1499+
var getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
1500+
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
1501+
}
14921502
}
14931503
}
14941504

@@ -1552,7 +1562,7 @@ module ts {
15521562

15531563
function hasBaseType(type: InterfaceType, checkBase: InterfaceType) {
15541564
return check(type);
1555-
function check(type: InterfaceType) {
1565+
function check(type: InterfaceType): boolean {
15561566
var target = <InterfaceType>getTargetType(type);
15571567
return target === checkBase || forEach(target.baseTypes, check);
15581568
}
@@ -2036,6 +2046,15 @@ module ts {
20362046
}
20372047
else if (signature.resolvedReturnType === resolvingType) {
20382048
signature.resolvedReturnType = anyType;
2049+
if (compilerOptions.noImplicitAny) {
2050+
var declaration = <Declaration>signature.declaration;
2051+
if (declaration.name) {
2052+
error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, identifierToString(declaration.name));
2053+
}
2054+
else {
2055+
error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions);
2056+
}
2057+
}
20392058
}
20402059
return signature.resolvedReturnType;
20412060
}
@@ -6587,7 +6606,7 @@ module ts {
65876606
// Language service support
65886607

65896608
function getNodeAtPosition(sourceFile: SourceFile, position: number): Node {
6590-
function findChildAtPosition(parent: Node) {
6609+
function findChildAtPosition(parent: Node): Node {
65916610
var child = forEachChild(parent, node => {
65926611
if (position >= node.pos && position <= node.end && position >= getTokenPosOfNode(node)) {
65936612
return findChildAtPosition(node);

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ module ts {
390390
Object_literal_s_property_0_implicitly_has_an_1_type: { code: 7018, category: DiagnosticCategory.Error, key: "Object literal's property '{0}' implicitly has an '{1}' type." },
391391
Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." },
392392
Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7020, category: DiagnosticCategory.Error, key: "Call signature, which lacks return-type annotation, implicitly has an 'any' return type." },
393+
_0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation: { code: 7021, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation." },
394+
_0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer: { code: 7022, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer." },
395+
_0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7023, category: DiagnosticCategory.Error, key: "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." },
396+
Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." },
393397
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
394398
};
395399
}

src/compiler/diagnosticMessages.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,22 @@
15571557
"category": "Error",
15581558
"code": 7020
15591559
},
1560+
"'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.": {
1561+
"category": "Error",
1562+
"code": 7021
1563+
},
1564+
"'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.": {
1565+
"category": "Error",
1566+
"code": 7022
1567+
},
1568+
"'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": {
1569+
"category": "Error",
1570+
"code": 7023
1571+
},
1572+
"Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": {
1573+
"category": "Error",
1574+
"code": 7024
1575+
},
15601576
"You cannot rename this element.": {
15611577
"category": "Error",
15621578
"code": 8000

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1973,7 +1973,7 @@ module ts {
19731973
}
19741974
}
19751975

1976-
function emitNode(node: Node) {
1976+
function emitNode(node: Node): void {
19771977
if (!node) {
19781978
return;
19791979
}

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3533,7 +3533,7 @@ module ts {
35333533
return finishNode(node);
35343534
}
35353535

3536-
function isDeclaration() {
3536+
function isDeclaration(): boolean {
35373537
switch (token) {
35383538
case SyntaxKind.VarKeyword:
35393539
case SyntaxKind.FunctionKeyword:
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
==== tests/cases/compiler/implicitAnyFromCircularInference.ts (9 errors) ====
2+
3+
// Error expected
4+
var a: typeof a;
5+
~
6+
!!! 'a' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.
7+
8+
// Error expected on b or c
9+
var b: typeof c;
10+
var c: typeof b;
11+
~
12+
!!! 'c' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.
13+
14+
// Error expected
15+
var d: Array<typeof d>;
16+
~
17+
!!! 'd' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.
18+
19+
function f() { return f; }
20+
21+
// Error expected
22+
function g() { return g(); }
23+
~
24+
!!! 'g' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
25+
26+
// Error expected
27+
var f1 = function () {
28+
~~~~~~~~~~~~~
29+
return f1();
30+
~~~~~~~~~~~~~~~~
31+
};
32+
~
33+
!!! Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
34+
35+
// Error expected
36+
var f2 = () => f2();
37+
~~~~~~~~~~
38+
!!! Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
39+
40+
// Error expected
41+
function h() {
42+
~
43+
!!! 'h' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
44+
return foo();
45+
function foo() {
46+
return h() || "hello";
47+
}
48+
}
49+
50+
interface A {
51+
s: string;
52+
}
53+
54+
function foo(x: A): string { return "abc"; }
55+
56+
class C {
57+
// Error expected
58+
s = foo(this);
59+
~~~~~~~~~~~~~~
60+
!!! 's' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.
61+
}
62+
63+
class D {
64+
// Error expected
65+
get x() {
66+
~~~~~~~~~
67+
return this.x;
68+
~~~~~~~~~~~~~~~~~~~~~~
69+
}
70+
~~~~~
71+
!!! 'x' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
72+
}
73+
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//// [implicitAnyFromCircularInference.ts]
2+
3+
// Error expected
4+
var a: typeof a;
5+
6+
// Error expected on b or c
7+
var b: typeof c;
8+
var c: typeof b;
9+
10+
// Error expected
11+
var d: Array<typeof d>;
12+
13+
function f() { return f; }
14+
15+
// Error expected
16+
function g() { return g(); }
17+
18+
// Error expected
19+
var f1 = function () {
20+
return f1();
21+
};
22+
23+
// Error expected
24+
var f2 = () => f2();
25+
26+
// Error expected
27+
function h() {
28+
return foo();
29+
function foo() {
30+
return h() || "hello";
31+
}
32+
}
33+
34+
interface A {
35+
s: string;
36+
}
37+
38+
function foo(x: A): string { return "abc"; }
39+
40+
class C {
41+
// Error expected
42+
s = foo(this);
43+
}
44+
45+
class D {
46+
// Error expected
47+
get x() {
48+
return this.x;
49+
}
50+
}
51+
52+
53+
//// [implicitAnyFromCircularInference.js]
54+
// Error expected
55+
var a;
56+
// Error expected on b or c
57+
var b;
58+
var c;
59+
// Error expected
60+
var d;
61+
function f() {
62+
return f;
63+
}
64+
// Error expected
65+
function g() {
66+
return g();
67+
}
68+
// Error expected
69+
var f1 = function () {
70+
return f1();
71+
};
72+
// Error expected
73+
var f2 = function () { return f2(); };
74+
// Error expected
75+
function h() {
76+
return foo();
77+
function foo() {
78+
return h() || "hello";
79+
}
80+
}
81+
function foo(x) {
82+
return "abc";
83+
}
84+
var C = (function () {
85+
function C() {
86+
// Error expected
87+
this.s = foo(this);
88+
}
89+
return C;
90+
})();
91+
var D = (function () {
92+
function D() {
93+
}
94+
Object.defineProperty(D.prototype, "x", {
95+
// Error expected
96+
get: function () {
97+
return this.x;
98+
},
99+
enumerable: true,
100+
configurable: true
101+
});
102+
return D;
103+
})();
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// @noimplicitany: true
2+
// @target: es5
3+
4+
// Error expected
5+
var a: typeof a;
6+
7+
// Error expected on b or c
8+
var b: typeof c;
9+
var c: typeof b;
10+
11+
// Error expected
12+
var d: Array<typeof d>;
13+
14+
function f() { return f; }
15+
16+
// Error expected
17+
function g() { return g(); }
18+
19+
// Error expected
20+
var f1 = function () {
21+
return f1();
22+
};
23+
24+
// Error expected
25+
var f2 = () => f2();
26+
27+
// Error expected
28+
function h() {
29+
return foo();
30+
function foo() {
31+
return h() || "hello";
32+
}
33+
}
34+
35+
interface A {
36+
s: string;
37+
}
38+
39+
function foo(x: A): string { return "abc"; }
40+
41+
class C {
42+
// Error expected
43+
s = foo(this);
44+
}
45+
46+
class D {
47+
// Error expected
48+
get x() {
49+
return this.x;
50+
}
51+
}

0 commit comments

Comments
 (0)