Skip to content

Commit 34f6c51

Browse files
committed
Clarify error message when an accessor is invoked.
1 parent b2b360a commit 34f6c51

File tree

5 files changed

+66
-15
lines changed

5 files changed

+66
-15
lines changed

src/compiler/checker.ts

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,17 @@ namespace ts {
243243
const parsed = getParseTreeNode(node, isFunctionLike);
244244
return parsed ? isImplementationOfOverload(parsed) : undefined;
245245
},
246-
getImmediateAliasedSymbol,
246+
getImmediateAliasedSymbol: symbol => {
247+
Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
248+
const links = getSymbolLinks(symbol);
249+
if (!links.immediateTarget) {
250+
const node = getDeclarationOfAliasSymbol(symbol);
251+
if (!node) return Debug.fail();
252+
links.immediateTarget = getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true);
253+
}
254+
255+
return links.immediateTarget;
256+
},
247257
getAliasedSymbol: resolveAlias,
248258
getEmitResolver,
249259
getExportsOfModule: getExportsOfModuleAsArray,
@@ -20796,13 +20806,47 @@ namespace ts {
2079620806
}
2079720807
else {
2079820808
let relatedInformation: DiagnosticRelatedInformation | undefined;
20809+
let propertyName: string | undefined;
20810+
let propertyAccessorText: string | undefined;
2079920811
if (node.arguments.length === 1) {
2080020812
const text = getSourceFileOfNode(node).text;
2080120813
if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) {
2080220814
relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.It_is_highly_likely_that_you_are_missing_a_semicolon);
2080320815
}
2080420816
}
20805-
invocationError(node, apparentType, SignatureKind.Call, relatedInformation);
20817+
else if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
20818+
const propertyAccess = node.expression as PropertyAccessExpression;
20819+
const symbol = getSymbolOfEntityNameOrPropertyAccessExpression(propertyAccess);
20820+
20821+
// Handle union types with non-function-like signatures.
20822+
if (symbol) {
20823+
const links = getSymbolLinks(symbol);
20824+
const isObjectUnionOrIntersection = links && links.type && (
20825+
(links.type.flags & (TypeFlags.Union | TypeFlags.Intersection | TypeFlags.Object)) !== 0
20826+
) || false;
20827+
20828+
let invokable = isObjectUnionOrIntersection;
20829+
if (isObjectUnionOrIntersection) {
20830+
if (links && links.type && (links.type.flags & TypeFlags.Object)) {
20831+
const resolvedType = links.type as ObjectType;
20832+
invokable = (resolvedType.callSignatures && resolvedType.callSignatures.length !== 0) || false;
20833+
}
20834+
else {
20835+
const resolvedType = links.type as UnionOrIntersectionType;
20836+
invokable = every(resolvedType.types, ty => (ty as ResolvedType).callSignatures && (ty as ResolvedType).callSignatures.length !== 0);
20837+
}
20838+
}
20839+
20840+
if (!invokable) {
20841+
const file = getSourceFileOfNode(node);
20842+
20843+
propertyName = propertyAccess.name.escapedText.toString();
20844+
propertyAccessorText = createPrinter().printNode(EmitHint.Expression, propertyAccess, file);
20845+
}
20846+
}
20847+
}
20848+
20849+
invocationError(node, apparentType, SignatureKind.Call, relatedInformation, propertyName, propertyAccessorText);
2080620850
}
2080720851
return resolveErrorCall(node);
2080820852
}
@@ -20972,11 +21016,14 @@ namespace ts {
2097221016
return true;
2097321017
}
2097421018

20975-
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) {
21019+
function invocationError(node: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation, propertyName?: string, didYouMean?: string) {
2097621020
const diagnostic = error(node, (kind === SignatureKind.Call ?
20977-
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
21021+
(propertyName === undefined ?
21022+
Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures :
21023+
Diagnostics.Cannot_invoke_expression_1_which_is_a_property_and_has_the_type_0_which_has_no_compatible_call_signature_Did_you_mean_2
21024+
) :
2097821025
Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature
20979-
), typeToString(apparentType));
21026+
), typeToString(apparentType), propertyName, didYouMean);
2098021027
invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic);
2098121028
}
2098221029

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2585,6 +2585,10 @@
25852585
"category": "Error",
25862586
"code": 2749
25872587
},
2588+
"Cannot invoke expression `{1}`, which is a property and has the type `{0}` which has no compatible call signature. Did you mean `{2}`": {
2589+
"category": "Error",
2590+
"code": 2750
2591+
},
25882592

25892593
"Import declaration '{0}' is using private name '{1}'.": {
25902594
"category": "Error",

tests/baselines/reference/instancePropertiesInheritedIntoClassType.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(4,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
22
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(7,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
3-
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(19,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
3+
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(19,14): error TS2750: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `d.y`
44
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(26,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
55
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(29,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
6-
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(41,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
6+
tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts(41,14): error TS2750: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `d.y`
77

88

99
==== tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts (6 errors) ====
@@ -31,7 +31,7 @@ tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIn
3131
r.y = 4;
3232
var r6 = d.y(); // error
3333
~~~~~
34-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
34+
!!! error TS2750: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `d.y`
3535

3636
}
3737

@@ -59,5 +59,5 @@ tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIn
5959
r.y = '';
6060
var r6 = d.y(); // error
6161
~~~~~
62-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
62+
!!! error TS2750: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `d.y`
6363
}

tests/baselines/reference/instancePropertyInClassType.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(4,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
22
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(7,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
3-
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(17,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
3+
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(17,14): error TS2750: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `c.y`
44
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(24,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
55
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(27,13): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
6-
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(37,14): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
6+
tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts(37,14): error TS2750: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `c.y`
77

88

99
==== tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts (6 errors) ====
@@ -29,7 +29,7 @@ tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.t
2929
r.y = 4;
3030
var r6 = c.y(); // error
3131
~~~~~
32-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'Number' has no compatible call signatures.
32+
!!! error TS2750: Cannot invoke expression `y`, which is a property and has the type `Number` which has no compatible call signature. Did you mean `c.y`
3333

3434
}
3535

@@ -55,5 +55,5 @@ tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.t
5555
r.y = '';
5656
var r6 = c.y(); // error
5757
~~~~~
58-
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures.
58+
!!! error TS2750: Cannot invoke expression `y`, which is a property and has the type `String` which has no compatible call signature. Did you mean `c.y`
5959
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
tests/cases/compiler/file1.ts(2,16): error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.
1+
tests/cases/compiler/file1.ts(2,16): error TS2750: Cannot access ambient const enums when the '--isolatedModules' flag is provided.
22

33

44
==== tests/cases/compiler/file1.ts (1 errors) ====
55
declare const enum E { X = 1}
66
export var y = E.X;
77
~
8-
!!! error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.
8+
!!! error TS2750: Cannot access ambient const enums when the '--isolatedModules' flag is provided.
99

0 commit comments

Comments
 (0)