FIR: Fix callable references resolution with stub receivers

Use stubReceiver as a receiver for fake calls

See issues KT-43358 KT-43359 KT-43378
This commit is contained in:
Denis Zharkov
2020-11-15 13:15:15 +03:00
parent f97cc0b62d
commit d4c7d4fc7c
12 changed files with 27 additions and 29 deletions
@@ -36,12 +36,12 @@ class NoGenericTest {
fun B.extensionFun(): A = A()
fun test_1() {
val extensionValRef = <!UNRESOLVED_REFERENCE!>B::extensionVal<!>
val extensionFunRef = <!UNRESOLVED_REFERENCE!>B::extensionFun<!>
val extensionValRef = B::extensionVal
val extensionFunRef = B::extensionFun
}
fun test_2() {
val memberValRef = B::memberVal
val memberFunRef = B::memberFun
}
}
}
@@ -81,8 +81,8 @@ FILE: referenceToExtension.kt
}
public final fun test_1(): R|kotlin/Unit| {
lval extensionValRef: <ERROR TYPE REF: No result type for initializer> = Q|NoGenericTest.B|::<Unresolved name: extensionVal>#
lval extensionFunRef: <ERROR TYPE REF: No result type for initializer> = Q|NoGenericTest.B|::<Unresolved name: extensionFun>#
lval extensionValRef: R|kotlin/reflect/KProperty1<NoGenericTest.B, NoGenericTest.A>| = Q|NoGenericTest.B|::R|/NoGenericTest.extensionVal|
lval extensionFunRef: R|kotlin/reflect/KFunction1<NoGenericTest.B, NoGenericTest.A>| = Q|NoGenericTest.B|::R|/NoGenericTest.extensionFun|
}
public final fun test_2(): R|kotlin/Unit| {
@@ -34,9 +34,9 @@ fun main() {
<!AMBIGUITY!>foo3<!>(KotlinClass::baz)
// Type mismatch
<!INAPPLICABLE_CANDIDATE!>foo1<!>(<!UNRESOLVED_REFERENCE!>KotlinClass::bar<!>)
foo1(KotlinClass::bar)
foo2(KotlinClass::bar)
foo3(KotlinClass::bar)
<!AMBIGUITY!>foo3<!>(KotlinClass::bar)
foo1(KotlinClass2::bar)
// Type mismatch
@@ -50,13 +50,13 @@ FILE: main.kt
public final fun foo3(x: R|(kotlin/String) -> kotlin/Int|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
R|/foo1|(Q|KotlinClass|::R|/KotlinClass.Companion.baz|)
R|/foo1|(Q|KotlinClass|::R|/KotlinClass.baz|)
R|/foo2|(Q|KotlinClass|::R|/KotlinClass.baz|)
<Ambiguity: foo3, [/foo3, /foo3]>#(Q|KotlinClass|::R|/KotlinClass.baz|)
<Inapplicable(INAPPLICABLE): /foo1>#(Q|KotlinClass|::<Unresolved reference: bar>#)
R|/foo1|(Q|KotlinClass|::R|/JavaClass.bar|)
R|/foo2|(Q|KotlinClass|::R|/JavaClass.bar|)
R|/foo3|(Q|KotlinClass|::R|/JavaClass.bar|)
R|/foo1|(Q|KotlinClass2|::R|/KotlinClass2.Companion.bar|)
<Ambiguity: foo3, [/foo3, /foo3]>#(Q|KotlinClass|::R|/JavaClass.bar|)
R|/foo1|(Q|KotlinClass2|::R|/KotlinClass2.bar|)
<Inapplicable(INAPPLICABLE): /foo2>#(Q|KotlinClass2|::<Unresolved reference: bar>#)
R|/foo3|(Q|KotlinClass2|::R|/KotlinClass2.Companion.bar|)
R|/foo3|(Q|KotlinClass2|::R|/KotlinClass2.bar|)
}
@@ -180,16 +180,15 @@ internal open class FirTowerResolveTask(
if (resolvedQualifier.symbol != null) {
val typeRef = resolvedQualifier.typeRef
// NB: yet built-in Unit is used for "no-value" type
if (info.callKind == CallKind.CallableReference) {
if (info.stubReceiver != null || typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, parentGroup = TowerGroup.QualifierValue)
}
} else {
if (typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, parentGroup = TowerGroup.QualifierValue)
}
if (info.callKind == CallKind.CallableReference && info.stubReceiver != null ) {
runResolverForExpressionReceiver(info, info.stubReceiver, parentGroup = TowerGroup.QualifierValue)
}
// NB: yet built-in Unit is used for "no-value" type
if (typeRef !is FirImplicitBuiltinTypeRef) {
runResolverForExpressionReceiver(info, resolvedQualifier, parentGroup = TowerGroup.QualifierValue)
}
}
}
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: BINDING_RECEIVERS
// IGNORE_BACKEND_FIR: JVM_IR
fun <T> get(t: T): () -> String {
return t::toString
}
@@ -4,10 +4,10 @@ class A {
fun A.extA(x: String) = x
fun main() {
<!UNRESOLVED_REFERENCE!>Int::extInt<!>
Int::extInt
A::extA
<!INAPPLICABLE_CANDIDATE!>eat<!>(<!UNRESOLVED_REFERENCE!>Int::extInt<!>)
eat(Int::extInt)
eat(A::extA)
}
}
@@ -27,7 +27,7 @@ fun testA(a: A) {
fun testB(b: B) {
val call1 = call(B::foo)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>call1<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>call1<!>
val call2 = call(B()::foo)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>call2<!>
@@ -22,7 +22,7 @@ fun B.foo(): Double = 0.0
fun call(a: Any) {}
fun testA(a: A) {
call(A::foo)
call(<!UNRESOLVED_REFERENCE!>A::foo<!>)
call(A.Companion::foo)
}
@@ -186,7 +186,7 @@ fun main() {
// Should be error as `A3::foo1` is `KFunction2`, but the remaining arguments are `KFuncion1` or `Function1`
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function<kotlin.Any>")!>select(A3(), <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<A3, kotlin.Int, kotlin.Unit>")!>A3::foo1<!>, { a -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>a<!> }, { it -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>it<!> })<!>
// It's OK because `A3::foo2` is from companion of `A3`
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Int, kotlin.Any>")!>select(A3(), <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit>")!>A3::foo2<!>, { a -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>a<!> }, { it -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>it<!> })<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function<kotlin.Any>")!>select(A3(), <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KFunction2<A3, kotlin.Int, kotlin.Unit>")!>A3::foo2<!>, { a -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>a<!> }, { it -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>it<!> })<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function1<kotlin.Int, kotlin.Comparable<*> & java.io.Serializable>")!>select(A4(), { x: Number -> "" })<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function2<kotlin.Int, kotlin.Int, kotlin.Comparable<*> & java.io.Serializable>")!>select(A5<Int, Int>(), { x: Number, y: Int -> "" })<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Function3<kotlin.Int, kotlin.String, kotlin.Float, kotlin.Float>")!>select(A2(), id { a, b, c -> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>a<!>; <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>; <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>c<!> })<!>
@@ -11,7 +11,7 @@ interface TypeConstructor
class Refiner {
val memoizedFunctionLambda = createMemoizedFunction { it.foo() } // error type infered, no diagnostic, BAD, backend fails
val memoizedFunctionReference = <!INAPPLICABLE_CANDIDATE!>createMemoizedFunction<!>(<!UNRESOLVED_REFERENCE!>TypeConstructor::foo<!>) // EXTENSION_IN_CLASS_REFERENCE_IS_NOT_ALLOWED, fine
val memoizedFunctionReference = createMemoizedFunction(TypeConstructor::foo) // EXTENSION_IN_CLASS_REFERENCE_IS_NOT_ALLOWED, fine
val memoizedFunctionTypes = createMemoizedFunction<TypeConstructor, Boolean> { it.foo() } // works fine
private fun TypeConstructor.foo(): Boolean = true
@@ -11,7 +11,7 @@ import libCase1.*
import kotlin.text.format
fun case1() {
val y2 : () ->String =<!UNRESOLVED_REFERENCE!>(String)::format<!>
val y2 : () ->String =(String)::format
}
// FILE: LibCase1.kt