Skip to content

Report circular type inference errors with -noImplicitAny #665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 12, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ module ts {
}
}

function getFullyQualifiedName(symbol: Symbol) {
function getFullyQualifiedName(symbol: Symbol): string {
return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol);
}

Expand Down Expand Up @@ -1420,6 +1420,12 @@ module ts {
}
else if (links.type === resolvingType) {
links.type = anyType;
if (compilerOptions.noImplicitAny) {
var diagnostic = (<VariableDeclaration>symbol.valueDeclaration).type ?
Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation :
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;
error(symbol.valueDeclaration, diagnostic, symbolToString(symbol));
}
}
return links.type;
}
Expand Down Expand Up @@ -1475,7 +1481,7 @@ module ts {
// Otherwise, fall back to 'any'.
else {
if (compilerOptions.noImplicitAny) {
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbol.name);
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
}

type = anyType;
Expand All @@ -1489,6 +1495,10 @@ module ts {
}
else if (links.type === resolvingType) {
links.type = anyType;
if (compilerOptions.noImplicitAny) {
var getter = <AccessorDeclaration>getDeclarationOfKind(symbol, SyntaxKind.GetAccessor);
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));
}
}
}

Expand Down Expand Up @@ -1552,7 +1562,7 @@ module ts {

function hasBaseType(type: InterfaceType, checkBase: InterfaceType) {
return check(type);
function check(type: InterfaceType) {
function check(type: InterfaceType): boolean {
var target = <InterfaceType>getTargetType(type);
return target === checkBase || forEach(target.baseTypes, check);
}
Expand Down Expand Up @@ -2036,6 +2046,15 @@ module ts {
}
else if (signature.resolvedReturnType === resolvingType) {
signature.resolvedReturnType = anyType;
if (compilerOptions.noImplicitAny) {
var declaration = <Declaration>signature.declaration;
if (declaration.name) {
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));
}
else {
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);
}
}
}
return signature.resolvedReturnType;
}
Expand Down Expand Up @@ -6587,7 +6606,7 @@ module ts {
// Language service support

function getNodeAtPosition(sourceFile: SourceFile, position: number): Node {
function findChildAtPosition(parent: Node) {
function findChildAtPosition(parent: Node): Node {
var child = forEachChild(parent, node => {
if (position >= node.pos && position <= node.end && position >= getTokenPosOfNode(node)) {
return findChildAtPosition(node);
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ module ts {
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." },
Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." },
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." },
_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." },
_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." },
_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." },
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." },
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
};
}
16 changes: 16 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,22 @@
"category": "Error",
"code": 7020
},
"'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.": {
"category": "Error",
"code": 7021
},
"'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.": {
"category": "Error",
"code": 7022
},
"'{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.": {
"category": "Error",
"code": 7023
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make the error message a bit more explicit. I do not find "circularity" particularly helpful, specially that we do not print the cycle. how about:
'{0}' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its initializer.

Function implicitly has return type 'any' because it does not have a return type annotation and it is referenced directly or indirectly in at least one if its return expressions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I will change the error messages.

"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.": {
"category": "Error",
"code": 7024
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1973,7 +1973,7 @@ module ts {
}
}

function emitNode(node: Node) {
function emitNode(node: Node): void {
if (!node) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3533,7 +3533,7 @@ module ts {
return finishNode(node);
}

function isDeclaration() {
function isDeclaration(): boolean {
switch (token) {
case SyntaxKind.VarKeyword:
case SyntaxKind.FunctionKeyword:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
==== tests/cases/compiler/implicitAnyFromCircularInference.ts (9 errors) ====

// Error expected
var a: typeof a;
~
!!! 'a' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.

// Error expected on b or c
var b: typeof c;
var c: typeof b;
~
!!! 'c' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.

// Error expected
var d: Array<typeof d>;
~
!!! 'd' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.

function f() { return f; }

// Error expected
function g() { return g(); }
~
!!! '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.

// Error expected
var f1 = function () {
~~~~~~~~~~~~~
return f1();
~~~~~~~~~~~~~~~~
};
~
!!! 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.

// Error expected
var f2 = () => f2();
~~~~~~~~~~
!!! 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.

// Error expected
function h() {
~
!!! '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.
return foo();
function foo() {
return h() || "hello";
}
}

interface A {
s: string;
}

function foo(x: A): string { return "abc"; }

class C {
// Error expected
s = foo(this);
~~~~~~~~~~~~~~
!!! 's' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.
}

class D {
// Error expected
get x() {
~~~~~~~~~
return this.x;
~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~
!!! '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.
}

103 changes: 103 additions & 0 deletions tests/baselines/reference/implicitAnyFromCircularInference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//// [implicitAnyFromCircularInference.ts]

// Error expected
var a: typeof a;

// Error expected on b or c
var b: typeof c;
var c: typeof b;

// Error expected
var d: Array<typeof d>;

function f() { return f; }

// Error expected
function g() { return g(); }

// Error expected
var f1 = function () {
return f1();
};

// Error expected
var f2 = () => f2();

// Error expected
function h() {
return foo();
function foo() {
return h() || "hello";
}
}

interface A {
s: string;
}

function foo(x: A): string { return "abc"; }

class C {
// Error expected
s = foo(this);
}

class D {
// Error expected
get x() {
return this.x;
}
}


//// [implicitAnyFromCircularInference.js]
// Error expected
var a;
// Error expected on b or c
var b;
var c;
// Error expected
var d;
function f() {
return f;
}
// Error expected
function g() {
return g();
}
// Error expected
var f1 = function () {
return f1();
};
// Error expected
var f2 = function () { return f2(); };
// Error expected
function h() {
return foo();
function foo() {
return h() || "hello";
}
}
function foo(x) {
return "abc";
}
var C = (function () {
function C() {
// Error expected
this.s = foo(this);
}
return C;
})();
var D = (function () {
function D() {
}
Object.defineProperty(D.prototype, "x", {
// Error expected
get: function () {
return this.x;
},
enumerable: true,
configurable: true
});
return D;
})();
51 changes: 51 additions & 0 deletions tests/cases/compiler/implicitAnyFromCircularInference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// @noimplicitany: true
// @target: es5

// Error expected
var a: typeof a;

// Error expected on b or c
var b: typeof c;
var c: typeof b;

// Error expected
var d: Array<typeof d>;

function f() { return f; }

// Error expected
function g() { return g(); }

// Error expected
var f1 = function () {
return f1();
};

// Error expected
var f2 = () => f2();

// Error expected
function h() {
return foo();
function foo() {
return h() || "hello";
}
}

interface A {
s: string;
}

function foo(x: A): string { return "abc"; }

class C {
// Error expected
s = foo(this);
}

class D {
// Error expected
get x() {
return this.x;
}
}