diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index db5002d0b1bd4..de78ab0a6cc8e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25771,14 +25771,21 @@ namespace ts { error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); } else { - let relatedInformation: DiagnosticRelatedInformation | undefined; - if (node.arguments.length === 1) { + const relatedInformation: DiagnosticRelatedInformation[] = []; + if (node.arguments.length === 0) { + // Diagnose get accessors incorrectly called as functions + const { resolvedSymbol } = getNodeLinks(node.expression); + if (resolvedSymbol && resolvedSymbol.flags & SymbolFlags.GetAccessor) { + relatedInformation.push(createDiagnosticForNode(node.expression, Diagnostics._0_is_a_get_accessor_did_you_mean_to_use_it_without, getTextOfNode(node.expression))); + } + } + else if (node.arguments.length === 1) { const text = getSourceFileOfNode(node).text; if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /* stopAfterLineBreak */ true) - 1))) { - relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon); + relatedInformation.push(createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon)); } } - invocationError(node.expression, apparentType, SignatureKind.Call, relatedInformation); + invocationError(node.expression, apparentType, SignatureKind.Call, ...relatedInformation); } return resolveErrorCall(node); } @@ -26046,7 +26053,7 @@ namespace ts { relatedMessage: maybeMissingAwait ? Diagnostics.Did_you_forget_to_use_await : undefined, }; } - function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { + function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, ...relatedInformation: DiagnosticRelatedInformation[]) { const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(apparentType, kind); const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, messageChain); if (relatedInfo) { @@ -26058,7 +26065,7 @@ namespace ts { diagnostic.length = length; } diagnostics.add(diagnostic); - invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic); + invocationErrorRecovery(apparentType, kind, addRelatedInfo(diagnostic, ...relatedInformation)); } function invocationErrorRecovery(apparentType: Type, kind: SignatureKind, diagnostic: Diagnostic) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 29bf61b2f752b..9046f05de636d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4384,6 +4384,10 @@ "category": "Error", "code": 6231 }, + "'{0}' is a 'get' accessor; did you mean to use it without '()'?": { + "category": "Message", + "code": 6232 + }, "Projects to reference": { "category": "Message", diff --git a/tests/baselines/reference/accessorAccidentalCallDiagnostic.errors.txt b/tests/baselines/reference/accessorAccidentalCallDiagnostic.errors.txt new file mode 100644 index 0000000000000..f2bf6b4cf1860 --- /dev/null +++ b/tests/baselines/reference/accessorAccidentalCallDiagnostic.errors.txt @@ -0,0 +1,17 @@ +tests/cases/compiler/accessorAccidentalCallDiagnostic.ts(6,14): error TS2349: This expression is not callable. + Type 'Number' has no call signatures. + + +==== tests/cases/compiler/accessorAccidentalCallDiagnostic.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/24554 + class Test24554 { + get property(): number { return 1; } + } + function test24554(x: Test24554) { + return x.property(); + ~~~~~~~~ +!!! error TS2349: This expression is not callable. +!!! error TS2349: Type 'Number' has no call signatures. +!!! related TS6232 tests/cases/compiler/accessorAccidentalCallDiagnostic.ts:6:12: 'x.property' is a 'get' accessor; did you mean to use it without '()'? + } + \ No newline at end of file diff --git a/tests/baselines/reference/accessorAccidentalCallDiagnostic.js b/tests/baselines/reference/accessorAccidentalCallDiagnostic.js new file mode 100644 index 0000000000000..6d5ae04ad5220 --- /dev/null +++ b/tests/baselines/reference/accessorAccidentalCallDiagnostic.js @@ -0,0 +1,25 @@ +//// [accessorAccidentalCallDiagnostic.ts] +// https://github.com/microsoft/TypeScript/issues/24554 +class Test24554 { + get property(): number { return 1; } +} +function test24554(x: Test24554) { + return x.property(); +} + + +//// [accessorAccidentalCallDiagnostic.js] +// https://github.com/microsoft/TypeScript/issues/24554 +var Test24554 = /** @class */ (function () { + function Test24554() { + } + Object.defineProperty(Test24554.prototype, "property", { + get: function () { return 1; }, + enumerable: false, + configurable: true + }); + return Test24554; +}()); +function test24554(x) { + return x.property(); +} diff --git a/tests/baselines/reference/accessorAccidentalCallDiagnostic.symbols b/tests/baselines/reference/accessorAccidentalCallDiagnostic.symbols new file mode 100644 index 0000000000000..d60d466e4cd69 --- /dev/null +++ b/tests/baselines/reference/accessorAccidentalCallDiagnostic.symbols @@ -0,0 +1,19 @@ +=== tests/cases/compiler/accessorAccidentalCallDiagnostic.ts === +// https://github.com/microsoft/TypeScript/issues/24554 +class Test24554 { +>Test24554 : Symbol(Test24554, Decl(accessorAccidentalCallDiagnostic.ts, 0, 0)) + + get property(): number { return 1; } +>property : Symbol(Test24554.property, Decl(accessorAccidentalCallDiagnostic.ts, 1, 17)) +} +function test24554(x: Test24554) { +>test24554 : Symbol(test24554, Decl(accessorAccidentalCallDiagnostic.ts, 3, 1)) +>x : Symbol(x, Decl(accessorAccidentalCallDiagnostic.ts, 4, 19)) +>Test24554 : Symbol(Test24554, Decl(accessorAccidentalCallDiagnostic.ts, 0, 0)) + + return x.property(); +>x.property : Symbol(Test24554.property, Decl(accessorAccidentalCallDiagnostic.ts, 1, 17)) +>x : Symbol(x, Decl(accessorAccidentalCallDiagnostic.ts, 4, 19)) +>property : Symbol(Test24554.property, Decl(accessorAccidentalCallDiagnostic.ts, 1, 17)) +} + diff --git a/tests/baselines/reference/accessorAccidentalCallDiagnostic.types b/tests/baselines/reference/accessorAccidentalCallDiagnostic.types new file mode 100644 index 0000000000000..17a59da43c8e7 --- /dev/null +++ b/tests/baselines/reference/accessorAccidentalCallDiagnostic.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/accessorAccidentalCallDiagnostic.ts === +// https://github.com/microsoft/TypeScript/issues/24554 +class Test24554 { +>Test24554 : Test24554 + + get property(): number { return 1; } +>property : number +>1 : 1 +} +function test24554(x: Test24554) { +>test24554 : (x: Test24554) => any +>x : Test24554 + + return x.property(); +>x.property() : any +>x.property : number +>x : Test24554 +>property : number +} + diff --git a/tests/baselines/reference/instancePropertiesInheritedIntoClassType.errors.txt b/tests/baselines/reference/instancePropertiesInheritedIntoClassType.errors.txt index 3b39bdc8e78ea..33d34d8db6ef9 100644 --- a/tests/baselines/reference/instancePropertiesInheritedIntoClassType.errors.txt +++ b/tests/baselines/reference/instancePropertiesInheritedIntoClassType.errors.txt @@ -35,6 +35,7 @@ tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIn ~ !!! error TS2349: This expression is not callable. !!! error TS2349: Type 'Number' has no call signatures. +!!! related TS6232 tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts:19:14: 'd.y' is a 'get' accessor; did you mean to use it without '()'? } @@ -64,4 +65,5 @@ tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIn ~ !!! error TS2349: This expression is not callable. !!! error TS2349: Type 'String' has no call signatures. +!!! related TS6232 tests/cases/conformance/classes/members/classTypes/instancePropertiesInheritedIntoClassType.ts:41:14: 'd.y' is a 'get' accessor; did you mean to use it without '()'? } \ No newline at end of file diff --git a/tests/baselines/reference/instancePropertyInClassType.errors.txt b/tests/baselines/reference/instancePropertyInClassType.errors.txt index aa5f4eaa8d6eb..c09527fd12312 100644 --- a/tests/baselines/reference/instancePropertyInClassType.errors.txt +++ b/tests/baselines/reference/instancePropertyInClassType.errors.txt @@ -33,6 +33,7 @@ tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.t ~ !!! error TS2349: This expression is not callable. !!! error TS2349: Type 'Number' has no call signatures. +!!! related TS6232 tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts:17:14: 'c.y' is a 'get' accessor; did you mean to use it without '()'? } @@ -60,4 +61,5 @@ tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.t ~ !!! error TS2349: This expression is not callable. !!! error TS2349: Type 'String' has no call signatures. +!!! related TS6232 tests/cases/conformance/classes/members/classTypes/instancePropertyInClassType.ts:37:14: 'c.y' is a 'get' accessor; did you mean to use it without '()'? } \ No newline at end of file diff --git a/tests/cases/compiler/accessorAccidentalCallDiagnostic.ts b/tests/cases/compiler/accessorAccidentalCallDiagnostic.ts new file mode 100644 index 0000000000000..a616fabe8ab6f --- /dev/null +++ b/tests/cases/compiler/accessorAccidentalCallDiagnostic.ts @@ -0,0 +1,9 @@ +// @target: es5 + +// https://github.com/microsoft/TypeScript/issues/24554 +class Test24554 { + get property(): number { return 1; } +} +function test24554(x: Test24554) { + return x.property(); +}