diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.fir.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.fir.txt index 8a1be596659..521268378fe 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.fir.txt @@ -32,7 +32,7 @@ FILE: threeReceivers.kt } public final fun R|FooBar|.chk(buz: R|Buz|): R|kotlin/Unit| { - R|/buz|.#() + R|/buz|.#() } } diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.kt index d5cde4eebb1..6cddb4f1046 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceivers.kt @@ -17,6 +17,6 @@ class Foo { // this@Foo is dispatch receiver of foobar // Foo/foobar is dispatch receiver of invoke // this@chk is extension receiver of invoke - buz.foobar() + buz.foobar() } } diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.fir.txt b/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.fir.txt index 84ae06e8fd2..baa00202861 100644 --- a/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.fir.txt @@ -28,5 +28,5 @@ FILE: test.kt lval res1: R|kotlin/String| = R|/descriptor|.R|/WrappedPropertyDescriptor.setter| lval res2: = R|/descriptor|.#() lval res3: R|kotlin/Boolean| = R|/descriptor|.R|/WrappedPropertyDescriptor.isDelegated| - lval res4: = R|/descriptor|.#() + lval res4: = R|/descriptor|.#() } diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt b/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt index 44ef3776643..49043b2e45b 100644 --- a/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt +++ b/compiler/fir/analysis-tests/testData/resolve/problems/inaccessibleJavaGetter.kt @@ -22,5 +22,5 @@ fun test() { val res1 = descriptor.setter val res2 = descriptor.getSetter() // Should be error val res3 = descriptor.isDelegated - val res4 = descriptor.isDelegated() // Should be error + val res4 = descriptor.isDelegated() // Should be error } diff --git a/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.fir.txt b/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.fir.txt index 3cf3c1b2889..01a8ba8365f 100644 --- a/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.fir.txt @@ -1,5 +1,5 @@ FILE: main.kt public final fun test(ann: R|Ann|): R|kotlin/Unit| { R|/ann|.R|/Ann.value| - R|/ann|.#() + R|/ann|.#() } diff --git a/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.kt b/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.kt index 30c39006a34..351a292d2a4 100644 --- a/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.kt +++ b/compiler/fir/analysis-tests/testData/resolve/properties/syntheticPropertiesForJavaAnnotations.kt @@ -3,12 +3,12 @@ // FILE: Ann.java public @interface Ann { - String value() + String value(); } // FILE: main.kt fun test(ann: Ann) { ann.value - ann.value() // should be an error + ann.value() // should be an error } diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 2b15d06040d..d22825ebe34 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -120,6 +120,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { } val ILLEGAL_SELECTOR by error() val NO_RECEIVER_ALLOWED by error() + val FUNCTION_EXPECTED by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) { + parameter("expression") + parameter("type") + } } val SUPER by object : DiagnosticGroup("Super") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index ae2bb53afd6..8d09ca5ad78 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -133,6 +133,7 @@ object FirErrors { val FUNCTION_CALL_EXPECTED by error2(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val ILLEGAL_SELECTOR by error0() val NO_RECEIVER_ALLOWED by error0() + val FUNCTION_EXPECTED by error2(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) // Super val SUPER_IS_NOT_AN_EXPRESSION by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index acae26948c3..67e7aaf9d84 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -177,6 +177,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_UPPER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_CALL_EXPECTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_EXPECTED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES @@ -434,6 +435,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_MODIFIER_TA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_SETTER_RETURN_TYPE +import org.jetbrains.kotlin.name.StandardClassIds @Suppress("unused") class FirDefaultErrorMessages { @@ -496,6 +498,10 @@ class FirDefaultErrorMessages { ) map.put(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, "Cannot create an instance of an abstract class") map.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", TO_STRING, FUNCTION_PARAMETERS) + map.put( + FUNCTION_EXPECTED, + "Expression ''{0}'' of type {1} cannot be invoked as a function. The function 'invoke()' is not found", TO_STRING, RENDER_TYPE + ) map.put(ILLEGAL_SELECTOR, "The expression cannot be a selector (occur after a dot)") map.put(NO_RECEIVER_ALLOWED, "No receiver can be passed to this function or property") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 289e66b18d8..3cadc239e53 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -41,6 +41,7 @@ private fun ConeDiagnostic.toFirDiagnostic( is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.name.asString()) is ConeUnresolvedQualifierError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.qualifier) is ConeFunctionCallExpectedError -> FirErrors.FUNCTION_CALL_EXPECTED.createOn(source, this.name.asString(), this.hasValueParameters) + is ConeFunctionExpectedError -> FirErrors.FUNCTION_EXPECTED.createOn(source, this.expression, this.type) is ConeHiddenCandidateError -> FirErrors.INVISIBLE_REFERENCE.createOn(source, this.candidateSymbol) is ConeAmbiguityError -> when { applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol }) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 7acf8e17e53..1047ba599a5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.calls.tower.FirTowerResolver import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerResolveManager +import org.jetbrains.kotlin.fir.resolve.dfa.symbol import org.jetbrains.kotlin.fir.resolve.diagnostics.* import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents @@ -84,6 +85,14 @@ class FirCallResolver( val name = functionCall.calleeReference.name val result = collectCandidates(functionCall, name) + var forceCandidates: Collection? = null + if (result.candidates.isEmpty()) { + val newResult = collectCandidates(functionCall, name, CallKind.VariableAccess) + if (newResult.candidates.isNotEmpty()) { + forceCandidates = newResult.candidates + } + } + val nameReference = createResolvedNamedReference( functionCall.calleeReference, name, @@ -91,6 +100,8 @@ class FirCallResolver( result.candidates, result.applicability, functionCall.explicitReceiver, + expectedCallKind = if (forceCandidates != null) CallKind.VariableAccess else null, + expectedCandidates = forceCandidates ) val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) @@ -147,7 +158,7 @@ class FirCallResolver( val info = CallInfo( qualifiedAccess, - if (qualifiedAccess is FirFunctionCall || forceCallKind == CallKind.Function) CallKind.Function else CallKind.VariableAccess, + forceCallKind ?: if (qualifiedAccess is FirFunctionCall) CallKind.Function else CallKind.VariableAccess, name, explicitReceiver, argumentList, @@ -229,7 +240,7 @@ class FirCallResolver( reducedCandidates, result.applicability, qualifiedAccess.explicitReceiver, - functionCallExpected = functionCallExpected + expectedCallKind = if (functionCallExpected) CallKind.Function else null ) val referencedSymbol = when (nameReference) { @@ -576,38 +587,66 @@ class FirCallResolver( applicability: CandidateApplicability, explicitReceiver: FirExpression? = null, createResolvedReferenceWithoutCandidateForLocalVariables: Boolean = true, - functionCallExpected: Boolean = false + expectedCallKind: CallKind? = null, + expectedCandidates: Collection? = null ): FirNamedReference { val source = reference.source return when { - functionCallExpected -> { + expectedCallKind != null -> { fun isValueParametersNotEmpty(candidate: Candidate): Boolean { return (candidate.symbol.fir as? FirFunction)?.valueParameters?.size?.let { it > 0 } ?: false } val candidate = candidates.singleOrNull() + + val diagnostic = if (expectedCallKind == CallKind.Function) { + ConeFunctionCallExpectedError( + name, + candidate?.let { isValueParametersNotEmpty(it) } ?: candidates.any { isValueParametersNotEmpty(it) }) + } else { + val singleExpectedCandidate = expectedCandidates?.singleOrNull() + if (singleExpectedCandidate?.symbol?.fir is FirRegularClass) { + ConeUnresolvedNameError(name) + // TODO: ConeResolutionToClassifierError() + } else { + val coneType = explicitReceiver?.typeRef?.coneType + if (coneType != null && !coneType.isUnit) { + ConeFunctionExpectedError( + name.asString(), + (singleExpectedCandidate?.symbol?.fir as? FirTypedDeclaration)?.returnTypeRef?.coneType ?: coneType + ) + } else { + ConeUnresolvedNameError(name) + } + } + } + if (candidate != null) { createErrorReferenceWithExistingCandidate( candidate, - ConeFunctionCallExpectedError(name, isValueParametersNotEmpty(candidate)), + diagnostic, source, transformer.resolutionContext, components.resolutionStageRunner ) } else { - buildErrorReference( - callInfo, - ConeFunctionCallExpectedError(name, candidates.any { isValueParametersNotEmpty(it) }), - source - ) + buildErrorReference(callInfo, diagnostic, source) } } - candidates.isEmpty() -> buildErrorReference( - callInfo, - ConeUnresolvedNameError(name), - source - ) + candidates.isEmpty() -> { + val diagnostic = if (name.asString() == "invoke" && explicitReceiver is FirConstExpression<*>) { + ConeFunctionExpectedError(explicitReceiver.value?.toString() ?: "", explicitReceiver.typeRef.coneType) + } else { + ConeUnresolvedNameError(name) + } + + buildErrorReference( + callInfo, + diagnostic, + source + ) + } candidates.size > 1 -> buildErrorReference( callInfo, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index 1b9f5ba35bb..8c0b53e4bfc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic +import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol @@ -49,6 +50,10 @@ class ConeFunctionCallExpectedError(val name: Name, val hasValueParameters: Bool override val reason: String get() = "Function call expected: $name(${if (hasValueParameters) "..." else ""})" } +class ConeFunctionExpectedError(val expression: String, val type: ConeKotlinType) : ConeDiagnostic() { + override val reason: String get() = "Expression '$expression' of type '$type' cannot be invoked as a function" +} + class ConeHiddenCandidateError( val candidateSymbol: FirBasedSymbol<*> ) : ConeDiagnostic() { diff --git a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt index 1543a100c0f..353483534e4 100644 --- a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt +++ b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt @@ -50,25 +50,25 @@ fun main(args : Array) { checkSubtype(b) fooT2()(1) // : Any? - 1() - 1{} - 1(){} + 1() + 1{} + 1(){} } fun f() : Int.() -> Unit = {} fun main1() { - 1.(fun Int.() = 1)(); + 1.(fun Int.() = 1)(); {1}(); (fun (x : Int) = x)(1) - 1.(fun Int.(x : Int) = x)(1); + 1.(fun Int.(x : Int) = x)(1); l@{1}() - 1.((fun Int.() = 1))() - 1.(f())() - 1.if(true){f()}else{f()}() - 1.if(true)(fun Int.() {})else{f()}() + 1.((fun Int.() = 1))() + 1.(f())() + 1.if(true){f()}else{f()}() + 1.if(true)(fun Int.() {})else{f()}() - 1."sdf"() + 1."sdf"() 1."sdf" 1.{} @@ -78,7 +78,7 @@ fun main1() { fun test() { {x : Int -> 1}(); (fun Int.() = 1)() - "sd".(fun Int.() = 1)() + "sd".(fun Int.() = 1)() val i : Int? = null i.(fun Int.() = 1)(); {}() diff --git a/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt b/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt index c1b2b66183d..bd055ff7dd6 100644 --- a/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/kt1875.fir.kt @@ -14,7 +14,7 @@ fun test(t: T) { } fun test1(t: T?) { - t.f(1) // todo resolve f as value and report UNSAFE_CALL + t.f(1) // todo resolve f as value and report UNSAFE_CALL t?.f(1) t.f?.invoke(1) t?.f?.invoke(1) diff --git a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt index 472484733c8..8e4e54031fc 100644 --- a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt @@ -34,7 +34,7 @@ fun test4() { // should be an error on receiver, shouldn't be thrown away fun test5() { - 1.(fun String.()=1)() + 1.(fun String.()=1)() } fun R?.sure() : R = this!! diff --git a/compiler/testData/diagnostics/tests/incompleteCode/kt2014.fir.kt b/compiler/testData/diagnostics/tests/incompleteCode/kt2014.fir.kt index 87eeb2de8fe..85ef6c8f80b 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/kt2014.fir.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/kt2014.fir.kt @@ -12,7 +12,7 @@ fun x(f : Foo) { f.prop f.bar - f.a() + f.a() c() R() } diff --git a/compiler/testData/diagnostics/tests/inner/innerConstructorsFromQualifiers.fir.kt b/compiler/testData/diagnostics/tests/inner/innerConstructorsFromQualifiers.fir.kt index 4c3dce517eb..fad06683fbf 100644 --- a/compiler/testData/diagnostics/tests/inner/innerConstructorsFromQualifiers.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/innerConstructorsFromQualifiers.fir.kt @@ -33,4 +33,4 @@ fun bar() { Inner() Inner(1) } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/kt310.fir.kt b/compiler/testData/diagnostics/tests/kt310.fir.kt deleted file mode 100644 index 738c832ccec..00000000000 --- a/compiler/testData/diagnostics/tests/kt310.fir.kt +++ /dev/null @@ -1,4 +0,0 @@ - -fun f(c: LongRange): Int { - return c.start() -} diff --git a/compiler/testData/diagnostics/tests/kt310.kt b/compiler/testData/diagnostics/tests/kt310.kt index a392d2adeea..5ed1485cdf6 100644 --- a/compiler/testData/diagnostics/tests/kt310.kt +++ b/compiler/testData/diagnostics/tests/kt310.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun f(c: LongRange): Int { return c.start() diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/unresolvedInvoke.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/unresolvedInvoke.fir.kt index c42be06db89..076aa08354b 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/unresolvedInvoke.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/unresolvedInvoke.fir.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_EXPRESSION fun foo(i: Int) { i() - 1() -} \ No newline at end of file + 1() +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt index c443b26b513..eca0df8fc6e 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt @@ -1,7 +1,7 @@ fun test1() { - 1. (fun String.(i: Int) = i )(1) - 1.(label@ fun String.(i: Int) = i )(1) + 1. (fun String.(i: Int) = i )(1) + 1.(label@ fun String.(i: Int) = i )(1) } fun test2(f: String.(Int) -> Unit) { @@ -12,5 +12,5 @@ fun test2(f: String.(Int) -> Unit) { fun test3() { fun foo(): String.(Int) -> Unit = {} - 1.(foo())(1) + 1.(foo())(1) } diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt index 4fbeeccf8cb..9edb90f6966 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt @@ -2,11 +2,11 @@ class A(val x: (String.() -> Unit)?) fun test(a: A) { if (a.x != null) { - "".(a.x)() + "".(a.x)() a.x("") // todo (a.x)("") } - "".(a.x)() + "".(a.x)() a.x("") (a.x)("") diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt index 9e377fda6eb..9b4e568670f 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/kt30695_2.fir.kt @@ -26,7 +26,7 @@ val Cls.extensionProperty: MemberInvokeOwner fun testNullableReceiver(nullable: Cls?) { nullable?.extensionProperty() - nullable.extensionProperty() + nullable.extensionProperty() } fun testNotNullableReceiver(notNullable: Cls) { diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/operatorCall.fir.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/operatorCall.fir.kt index dd21d05a845..d708b8faa7e 100644 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/operatorCall.fir.kt +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/operatorCall.fir.kt @@ -5,7 +5,7 @@ class D : C { { val s = "" s() - ""() + ""() 42 }()) diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/ifElseBlockInsideDoWhileWithBreak.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/ifElseBlockInsideDoWhileWithBreak.fir.kt index d4b85792f05..b0481b32952 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/ifElseBlockInsideDoWhileWithBreak.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/ifElseBlockInsideDoWhileWithBreak.fir.kt @@ -12,5 +12,5 @@ public fun foo(xx: Any): Int { y.length } while (true) // We could have smart cast here but with break it's hard to detect - return x.length() -} \ No newline at end of file + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.fir.kt new file mode 100644 index 00000000000..d7618ffaa58 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.fir.kt @@ -0,0 +1,13 @@ +fun x(): Boolean { return true } + +public fun foo(pp: Any): Int { + var p = pp + while(true) { + (p as String).length + if (x()) break + p = 42 + } + // Smart cast is NOT possible here + // (we could provide it but p = 42 makes it difficult to understand) + return p.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.kt index d92f607130a..6d024268df5 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/whileTrue.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL fun x(): Boolean { return true } public fun foo(pp: Any): Int { @@ -11,4 +10,4 @@ public fun foo(pp: Any): Int { // Smart cast is NOT possible here // (we could provide it but p = 42 makes it difficult to understand) return p.length() -} \ No newline at end of file +} diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/2.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/2.fir.kt index d45f733b499..ab364f1cc06 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/2.fir.kt @@ -8,9 +8,9 @@ class C() { // TESTCASE NUMBER: 1 fun case1() { val b: B = B(C()) - b memberVal 1 //nok UNRESOLVED_REFERENCE + b memberVal 1 //nok UNRESOLVED_REFERENCE b.memberVal.invoke(2) //nok UNRESOLVED_REFERENCE - b.memberVal(1) //nok FUNCTION_EXPECTED + b.memberVal(1) //nok FUNCTION_EXPECTED if (b.memberVal is C) { diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/3.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/3.fir.kt index 769733fcaa2..90cb7dcd067 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/3.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/overload-resolution/building-the-overload-candidate-set-ocs/infix-function-call/pos/3.fir.kt @@ -9,9 +9,9 @@ class C() { // TESTCASE NUMBER: 1 fun case1() { val b: B = B(C()) - b memberVal 1 //nok UNRESOLVED_REFERENCE + b memberVal 1 //nok UNRESOLVED_REFERENCE b.memberVal.invoke(2) //nok UNRESOLVED_REFERENCE - b.memberVal(1) //nok FUNCTION_EXPECTED + b.memberVal(1) //nok FUNCTION_EXPECTED b.memberVal as C diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 20d2642e12b..c967fded9dc 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -327,6 +327,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.FUNCTION_EXPECTED) { firDiagnostic -> + FunctionExpectedImpl( + firDiagnostic.a, + firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b), + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.SUPER_IS_NOT_AN_EXPRESSION) { firDiagnostic -> SuperIsNotAnExpressionImpl( firDiagnostic as FirPsiDiagnostic, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index ca6c15e87ea..754051e4132 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -257,6 +257,12 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = NoReceiverAllowed::class } + abstract class FunctionExpected : KtFirDiagnostic() { + override val diagnosticClass get() = FunctionExpected::class + abstract val expression: String + abstract val type: KtType + } + abstract class SuperIsNotAnExpression : KtFirDiagnostic() { override val diagnosticClass get() = SuperIsNotAnExpression::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index e316a77c30b..8cb417b76d2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -381,6 +381,15 @@ internal class NoReceiverAllowedImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class FunctionExpectedImpl( + override val expression: String, + override val type: KtType, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.FunctionExpected(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class SuperIsNotAnExpressionImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,