[FIR] Properly generate implicit invoke calls for a.(b)()

^KT-64891 Fixed
This commit is contained in:
Nikolay Lunyak
2024-01-15 12:57:27 +02:00
committed by Space Team
parent 8e6e447d6d
commit 3a36a786d4
9 changed files with 44 additions and 45 deletions
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter
import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry
import org.jetbrains.kotlin.fir.lightTree.fir.addDestructuringStatements import org.jetbrains.kotlin.fir.lightTree.fir.addDestructuringStatements
import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference
import org.jetbrains.kotlin.fir.references.builder.buildExplicitThisReference import org.jetbrains.kotlin.fir.references.builder.buildExplicitThisReference
@@ -651,8 +652,8 @@ class LightTreeRawFirExpressionBuilder(
SUPER_EXPRESSION -> { SUPER_EXPRESSION -> {
superNode = node superNode = node
} }
PARENTHESIZED -> node.getExpressionInParentheses()?.let { process(it) } ?: run { PARENTHESIZED -> if (node.tokenType != TokenType.ERROR_ELEMENT) {
additionalArgument = getAsFirExpression(node, "Incorrect invoke receiver") additionalArgument = getAsFirExpression(node.getExpressionInParentheses(), "Incorrect invoke receiver")
} }
TYPE_ARGUMENT_LIST -> { TYPE_ARGUMENT_LIST -> {
firTypeArguments += declarationBuilder.convertTypeArguments(node, allowedUnderscoredTypeArgument = true) firTypeArguments += declarationBuilder.convertTypeArguments(node, allowedUnderscoredTypeArgument = true)
@@ -680,6 +681,15 @@ class LightTreeRawFirExpressionBuilder(
} }
) )
superNode != null || additionalArgument?.calleeReference is FirSuperReference -> {
CalleeAndReceiver(
buildErrorNamedReference {
this.source = superNode?.toFirSourceElement() ?: additionalArgument?.calleeReference?.source
diagnostic = ConeSimpleDiagnostic("Super cannot be a callee", DiagnosticKind.SuperNotAllowed)
}
)
}
additionalArgument != null -> { additionalArgument != null -> {
CalleeAndReceiver( CalleeAndReceiver(
buildSimpleNamedReference { buildSimpleNamedReference {
@@ -691,16 +701,6 @@ class LightTreeRawFirExpressionBuilder(
) )
} }
superNode != null -> {
CalleeAndReceiver(
buildErrorNamedReference {
val node = superNode!!
this.source = node.toFirSourceElement()
diagnostic = ConeSimpleDiagnostic("Super cannot be a callee", DiagnosticKind.SuperNotAllowed)
}
)
}
else -> CalleeAndReceiver( else -> CalleeAndReceiver(
buildErrorNamedReference { buildErrorNamedReference {
this.source = source this.source = source
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.references.builder.* import org.jetbrains.kotlin.fir.references.builder.*
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -2948,8 +2949,11 @@ open class PsiRawFirBuilder(
calleeExpression: KtExpression?, calleeExpression: KtExpression?,
defaultSource: KtPsiSourceElement, defaultSource: KtPsiSourceElement,
): CalleeAndReceiver { ): CalleeAndReceiver {
return when (calleeExpression) { val parenthesizedArgument = (calleeExpression as? KtParenthesizedExpression)?.expression
is KtSimpleNameExpression -> ?.toFirExpression("Incorrect invoke receiver")
return when {
calleeExpression is KtSimpleNameExpression ->
CalleeAndReceiver( CalleeAndReceiver(
buildSimpleNamedReference { buildSimpleNamedReference {
source = calleeExpression.toFirSourceElement() source = calleeExpression.toFirSourceElement()
@@ -2957,22 +2961,32 @@ open class PsiRawFirBuilder(
} }
) )
is KtParenthesizedExpression -> splitToCalleeAndReceiver(calleeExpression.expression, defaultSource) calleeExpression is KtSuperExpression || parenthesizedArgument?.calleeReference is FirSuperReference -> {
null -> {
CalleeAndReceiver( CalleeAndReceiver(
buildErrorNamedReference { buildErrorNamedReference {
source = defaultSource source = (calleeExpression as? KtSuperExpression)?.toFirSourceElement()
diagnostic = ConeSyntaxDiagnostic("Call has no callee") ?: parenthesizedArgument?.calleeReference?.source
diagnostic = ConeSimpleDiagnostic("Super cannot be a callee", DiagnosticKind.SuperNotAllowed)
} }
) )
} }
is KtSuperExpression -> { parenthesizedArgument != null -> {
CalleeAndReceiver(
buildSimpleNamedReference {
source = defaultSource.fakeElement(KtFakeSourceElementKind.ImplicitInvokeCall)
name = OperatorNameConventions.INVOKE
},
receiverExpression = parenthesizedArgument,
isImplicitInvoke = true
)
}
calleeExpression == null -> {
CalleeAndReceiver( CalleeAndReceiver(
buildErrorNamedReference { buildErrorNamedReference {
source = calleeExpression.toFirSourceElement() source = defaultSource
diagnostic = ConeSimpleDiagnostic("Super cannot be a callee", DiagnosticKind.SuperNotAllowed) diagnostic = ConeSyntaxDiagnostic("Call has no callee")
} }
) )
} }
@@ -1,5 +1,5 @@
FILE: inBrackets.kt FILE: inBrackets.kt
public? final? fun test(e: ( Int.() -> String )): R|kotlin/Unit| { public? final? fun test(e: ( Int.() -> String )): R|kotlin/Unit| {
lval s: <implicit> = IntegerLiteral(3).e#() lval s: <implicit> = IntegerLiteral(3).e#()
lval ss: <implicit> = IntegerLiteral(3).e#() lval ss: <implicit> = e#.invoke#(IntegerLiteral(3))
} }
@@ -1,16 +0,0 @@
// ISSUE: KT-64891
val b: Int.() -> Int = { 10 }
val Int.b: () -> String get() = { "B" }
fun main() {
5.(b)().<!UNRESOLVED_REFERENCE!>inv<!>() // should be Int
5.b().length // should be String
}
fun <T> id(it: T) = it
fun rain() {
5.(b)().<!UNRESOLVED_REFERENCE!>inv<!>()
5.(id(b))().inv() // should be consistent
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// ISSUE: KT-64891 // ISSUE: KT-64891
val b: Int.() -> Int = { 10 } val b: Int.() -> Int = { 10 }
@@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) {
fun test2(f: (Int) -> Int) { fun test2(f: (Int) -> Int) {
1.<!UNRESOLVED_REFERENCE!>f<!>(2) 1.<!UNRESOLVED_REFERENCE!>f<!>(2)
2.(<!UNRESOLVED_REFERENCE!>f<!>)(2) 2.(f)(<!TOO_MANY_ARGUMENTS!>2<!>)
} }
@@ -5,7 +5,7 @@ fun test1() {
} }
fun test2(f: String.(Int) -> Unit) { fun test2(f: String.(Int) -> Unit) {
11.(<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>f<!>)(1) 11.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>(f)<!>(1)
11.(f)<!NO_VALUE_FOR_PARAMETER!>()<!> 11.(f)<!NO_VALUE_FOR_PARAMETER!>()<!>
} }
@@ -24,7 +24,7 @@ fun test(a: A, b: B) {
with(b) { with(b) {
a.foo<!NO_VALUE_FOR_PARAMETER!>()<!> a.foo<!NO_VALUE_FOR_PARAMETER!>()<!>
a.(foo)<!NO_VALUE_FOR_PARAMETER!>()<!> <!TOO_MANY_ARGUMENTS!>a<!>.(<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>foo<!>)()
(a.foo)() (a.foo)()
@@ -66,7 +66,7 @@ fun test(a: A, b: B) {
with(b) { with(b) {
a.foo<!NO_VALUE_FOR_PARAMETER!>()<!> a.foo<!NO_VALUE_FOR_PARAMETER!>()<!>
a.(foo)<!NO_VALUE_FOR_PARAMETER!>()<!> a.(<!UNRESOLVED_REFERENCE!>foo<!>)()
(a.foo)() (a.foo)()
@@ -10,10 +10,10 @@ val B.a: () -> Int get() = { 5 }
fun test(a: A, b: B) { fun test(a: A, b: B) {
val x: Int = b.a() val x: Int = b.a()
b.(a)() b.(<!UNRESOLVED_REFERENCE!>a<!>)()
with(b) { with(b) {
val y: Int = a() val y: Int = a()
(a)() (<!UNRESOLVED_REFERENCE!>a<!>)()
} }
} }