FIR: Support SAM conversion

This commit is contained in:
Denis Zharkov
2019-09-11 14:04:34 +03:00
parent f501730d86
commit 5567620563
24 changed files with 688 additions and 25 deletions
@@ -0,0 +1,199 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
import org.jetbrains.kotlin.name.Name
interface FirSamResolver : FirSessionComponent {
fun getFunctionTypeForPossibleSamType(type: ConeKotlinType): ConeKotlinType?
fun shouldRunSamConversionForFunction(firNamedFunction: FirNamedFunction): Boolean
}
private val NULL_STUB = Any()
class FirSamResolverImpl(
private val firSession: FirSession,
private val scopeSession: ScopeSession
) : FirSamResolver {
private val cache: MutableMap<FirRegularClass, Any> = mutableMapOf()
override fun getFunctionTypeForPossibleSamType(type: ConeKotlinType): ConeKotlinType? {
return when (type) {
is ConeClassType -> getFunctionTypeForPossibleSamType(type)
is ConeFlexibleType -> ConeFlexibleType(
getFunctionTypeForPossibleSamType(type.lowerBound) ?: return null,
getFunctionTypeForPossibleSamType(type.upperBound) ?: return null
)
is ConeClassErrorType -> null
// TODO: support those types as well
is ConeAbbreviatedType, is ConeTypeParameterType, is ConeTypeVariableType,
is ConeCapturedType, is ConeDefinitelyNotNullType, is ConeIntersectionType -> null
// TODO: Thing of getting rid of this branch since ConeLookupTagBasedType should be a sealed class
is ConeLookupTagBasedType -> null
}
}
private fun getFunctionTypeForPossibleSamType(type: ConeClassType): ConeLookupTagBasedType? {
val firRegularClass =
firSession.firSymbolProvider
.getSymbolByLookupTag(type.lookupTag)
?.fir as? FirRegularClass
?: return null
val unsubstitutedFunctionType = resolveFunctionTypeIfSamInterface(firRegularClass) ?: return null
val substitutor =
substitutorByMap(
firRegularClass.typeParameters
.map { it.symbol }
.zip(type.typeArguments.map {
(it as? ConeTypedProjection)?.type
?: ConeClassTypeImpl(ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(), isNullable = true)
})
.toMap()
)
val result =
substitutor
.substituteOrSelf(unsubstitutedFunctionType)
.withNullability(ConeNullability.create(type.isMarkedNullable))
require(result is ConeLookupTagBasedType) {
"Function type should always be ConeLookupTagBasedType, but ${result::class} was found"
}
return result
}
private fun resolveFunctionTypeIfSamInterface(firRegularClass: FirRegularClass): ConeKotlinType? {
return cache.getOrPut(firRegularClass) {
val abstractMethod = firRegularClass.getSingleAbstractMethodOrNull(firSession, scopeSession) ?: return@getOrPut NULL_STUB
// TODO: val shouldConvertFirstParameterToDescriptor = samWithReceiverResolvers.any { it.shouldConvertFirstSamParameterToReceiver(abstractMethod) }
abstractMethod.getFunctionTypeForAbstractMethod(firSession)
} as? ConeKotlinType
}
override fun shouldRunSamConversionForFunction(firNamedFunction: FirNamedFunction): Boolean {
// TODO: properly support, see org.jetbrains.kotlin.load.java.sam.JvmSamConversionTransformer.shouldRunSamConversionForFunction
return true
}
}
private fun FirRegularClass.getSingleAbstractMethodOrNull(
session: FirSession,
scopeSession: ScopeSession
): FirNamedFunction? {
// TODO: restrict to Java interfaces
if (classKind != ClassKind.INTERFACE || hasMoreThenOneAbstractFunctionOrHasAbstractProperty()) return null
val samCandidateNames = computeSamCandidateNames(session)
return findSingleAbstractMethodByNames(session, scopeSession, samCandidateNames)
}
private fun FirRegularClass.computeSamCandidateNames(session: FirSession): Set<Name> {
val classes =
lookupSuperTypes(this, lookupInterfaces = true, deep = true, useSiteSession = session)
.mapNotNullTo(mutableListOf(this)) {
(session.firSymbolProvider.getSymbolByLookupTag(it.lookupTag) as? FirClassSymbol)?.fir
}
val samCandidateNames = mutableSetOf<Name>()
for (clazz in classes) {
for (declaration in clazz.declarations) {
if (declaration !is FirMemberDeclaration || declaration.modality != Modality.ABSTRACT) continue
samCandidateNames.add(declaration.name)
}
}
return samCandidateNames
}
private fun FirRegularClass.findSingleAbstractMethodByNames(
session: FirSession,
scopeSession: ScopeSession,
samCandidateNames: Set<Name>
): FirNamedFunction? {
var resultMethod: FirNamedFunction? = null
var metIncorrectMember = false
val classUseSiteMemberScope = session.firSymbolProvider.getClassUseSiteMemberScope(classId, session, scopeSession)
for (candidateName in samCandidateNames) {
if (classUseSiteMemberScope == null) break
if (metIncorrectMember) break
classUseSiteMemberScope.processPropertiesByName(candidateName) {
if ((it as? FirProperty)?.modality == Modality.ABSTRACT) {
metIncorrectMember = true
ProcessorAction.STOP
} else {
ProcessorAction.NEXT
}
}
if (metIncorrectMember) break
classUseSiteMemberScope.processFunctionsByName(candidateName) { functionSymbol ->
val firFunction = functionSymbol.fir
require(firFunction is FirNamedFunction) {
"${functionSymbol.callableId.callableName} is expected to be FirNamedFunction, but ${functionSymbol::class} was found"
}
if (firFunction.modality != Modality.ABSTRACT) return@processFunctionsByName ProcessorAction.NEXT
if (resultMethod != null) {
metIncorrectMember = true
ProcessorAction.STOP
} else {
resultMethod = firFunction
ProcessorAction.NEXT
}
}
}
if (metIncorrectMember || resultMethod == null || resultMethod!!.typeParameters.isNotEmpty()) return null
return resultMethod
}
private fun FirRegularClass.hasMoreThenOneAbstractFunctionOrHasAbstractProperty(): Boolean {
var wasAbstractFunction = false
for (declaration in declarations) {
if (declaration is FirProperty && declaration.modality == Modality.ABSTRACT) return true
if (declaration is FirNamedFunction && declaration.modality == Modality.ABSTRACT) {
if (wasAbstractFunction) return true
wasAbstractFunction = true
}
}
return false
}
private fun FirNamedFunction.getFunctionTypeForAbstractMethod(session: FirSession): ConeLookupTagBasedType {
val parameterTypes = valueParameters.map {
it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: ConeKotlinErrorType("No type for parameter $it")
}
return createFunctionalType(
session, parameterTypes,
receiverType = null,
rawReturnType = returnTypeRef.coneTypeSafe() ?: ConeKotlinErrorType("No type for return type of $this")
)
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
@@ -234,10 +235,32 @@ internal fun Candidate.resolveArgument(
}
private fun Candidate.prepareExpectedType(session: FirSession, argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
val expectedType = argument.getExpectedType(session, parameter/*, LanguageVersionSettings*/)
val basicExpectedType = argument.getExpectedType(session, parameter/*, LanguageVersionSettings*/)
val expectedType = getExpectedTypeWithSAMConversion(session, argument, basicExpectedType) ?: basicExpectedType
return this.substitutor.substituteOrSelf(expectedType)
}
private fun Candidate.getExpectedTypeWithSAMConversion(
session: FirSession,
argument: FirExpression,
candidateExpectedType: ConeKotlinType
): ConeKotlinType? {
if (candidateExpectedType.isBuiltinFunctionalType) return null
// TODO: if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null
val firNamedFunction = symbol.fir as? FirNamedFunction ?: return null
if (!samResolver.shouldRunSamConversionForFunction(firNamedFunction)) return null
val argumentIsFunctional = when ((argument as? FirWrappedArgumentExpression)?.expression ?: argument) {
is FirAnonymousFunction, is FirCallableReferenceAccess -> true
else -> argument.typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType == true
}
if (!argumentIsFunctional) return null
// TODO: resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
return samResolver.getFunctionTypeForPossibleSamType(candidateExpectedType) ?: return null
}
internal fun FirExpression.getExpectedType(
session: FirSession,
parameter: FirValueParameter/*, languageVersionSettings: LanguageVersionSettings*/
@@ -58,6 +58,9 @@ class Candidate(
system.addOtherSystem(baseSystem)
system
}
val samResolver get() = inferenceComponents.samResolver
lateinit var substitutor: ConeSubstitutor
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
@@ -72,4 +75,4 @@ class Candidate(
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> callInfo.explicitReceiver!!
else -> implicitExtensionReceiverValue?.receiverExpression ?: FirNoReceiverExpression
}
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.FirSamResolver
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
@@ -57,7 +58,8 @@ class InferenceComponents(
val ctx: TypeSystemInferenceExtensionContextDelegate,
val session: FirSession,
val returnTypeCalculator: ReturnTypeCalculator,
val scopeSession: ScopeSession
val scopeSession: ScopeSession,
val samResolver: FirSamResolver
) {
private val approximator = object : AbstractTypeApproximator(ctx) {
override fun createErrorType(message: String): SimpleTypeMarker {
@@ -978,7 +978,7 @@ private fun inferenceComponents(session: FirSession, returnTypeCalculator: Retur
require(this is ErrorTypeConstructor)
return ConeClassErrorType(reason)
}
}, session, returnTypeCalculator, scopeSession)
}, session, returnTypeCalculator, scopeSession, FirSamResolverImpl(session, scopeSession))
class FirDesignatedBodyResolveTransformer(
@@ -0,0 +1,41 @@
// FILE: MyFunction.java
public interface MyFunction<T, R> {
R foo(T x);
}
// FILE: JavaUsage.java
public class JavaUsage {
public static void foo1(MyFunction<Integer, String> x) {}
public static void foo2(MyFunction<? super Number, ? extends CharSequence> x) {}
public static <X, Y> Y foo3(MyFunction<X, Y> f, X x) {}
}
// FILE: main.kt
fun main() {
JavaUsage.foo1 { x ->
x.toInt().toString()
}
JavaUsage.foo2 { x ->
x.toInt().toString()
}
JavaUsage.foo2 { x: Int ->
x.toString()
}
JavaUsage.foo3(
{ x ->
(x + 1).toString()
},
1
)
JavaUsage.foo3(
{ x: Number ->
x.toInt().toString()
},
2
)
}
@@ -0,0 +1,23 @@
FILE: main.kt
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo1|(<L> = foo1@fun <anonymous>(x: R|ft<kotlin/Int, kotlin/Int?>!|): R|ft<kotlin/String, kotlin/String?>!| <kind=EXACTLY_ONCE> {
R|<local>/x|.R|kotlin/Int.toInt|().R|kotlin/Any.toString|()
}
)
Q|JavaUsage|.R|/JavaUsage.foo2|(<L> = foo2@fun <anonymous>(x: R|ft<kotlin/Number, kotlin/Number?>!|): R|ft<kotlin/CharSequence, kotlin/CharSequence?>!| <kind=EXACTLY_ONCE> {
R|<local>/x|.R|kotlin/Number.toInt|().R|kotlin/Any.toString|()
}
)
Q|JavaUsage|.R|/JavaUsage.foo2|(<L> = foo2@fun <anonymous>(x: R|kotlin/Int|): R|ft<kotlin/CharSequence, kotlin/CharSequence?>!| <kind=EXACTLY_ONCE> {
R|<local>/x|.R|kotlin/Any.toString|()
}
)
Q|JavaUsage|.R|/JavaUsage.foo3|<R|ft<kotlin/Int, kotlin/Int>|, R|ft<kotlin/String, kotlin/String>|>(foo3@fun <anonymous>(x: R|ft<kotlin/Int, kotlin/Int>|): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
R|<local>/x|.R|kotlin/Int.plus|(Int(1)).R|kotlin/Any.toString|()
}
, Int(1))
Q|JavaUsage|.R|/JavaUsage.foo3|<R|ft<kotlin/Int, kotlin/Int>|, R|ft<kotlin/String, kotlin/String>|>(foo3@fun <anonymous>(x: R|kotlin/Number|): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
R|<local>/x|.R|kotlin/Number.toInt|().R|kotlin/Any.toString|()
}
, Int(2))
}
@@ -0,0 +1,42 @@
// TODO: These interfaces must be marked as "fun" ones that modifier is supported
interface MyRunnable {
fun foo(x: Int): Boolean
}
interface WithProperty {
val x: Int
}
interface TwoAbstract : MyRunnable {
fun bar()
}
interface Super {
fun foo(x: Int): Any
}
interface Derived : Super {
override fun foo(x: Int): Boolean
}
fun foo1(m: MyRunnable) {}
fun foo2(m: WithProperty) {}
fun foo3(m: TwoAbstract) {}
fun foo3(m: Derived) {}
fun main() {
val f = { t: Int -> t > 1}
foo1 { x -> x > 1 }
foo1(f)
foo2 { x -> x > 1 }
foo2(f)
foo3 { x -> x > 1 }
foo3(f)
foo4 { x -> x > 1 }
foo4(f)
}
@@ -0,0 +1,56 @@
FILE: kotlinSam.kt
public abstract interface MyRunnable : R|kotlin/Any| {
public abstract fun foo(x: R|kotlin/Int|): R|kotlin/Boolean|
}
public abstract interface WithProperty : R|kotlin/Any| {
public abstract val x: R|kotlin/Int|
public get(): R|kotlin/Int|
}
public abstract interface TwoAbstract : R|MyRunnable| {
public abstract fun bar(): R|kotlin/Unit|
}
public abstract interface Super : R|kotlin/Any| {
public abstract fun foo(x: R|kotlin/Int|): R|kotlin/Any|
}
public abstract interface Derived : R|Super| {
public abstract override fun foo(x: R|kotlin/Int|): R|kotlin/Boolean|
}
public final fun foo1(m: R|MyRunnable|): R|kotlin/Unit| {
}
public final fun foo2(m: R|WithProperty|): R|kotlin/Unit| {
}
public final fun foo3(m: R|TwoAbstract|): R|kotlin/Unit| {
}
public final fun foo3(m: R|Derived|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
lval f: R|kotlin/Function1<kotlin/Int, kotlin/Boolean>| = fun <anonymous>(t: R|kotlin/Int|): kotlin/Boolean {
>(R|<local>/t|, Int(1))
}
R|/foo1|(<L> = foo1@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
>(R|<local>/x|, Int(1))
}
)
R|/foo1|(R|<local>/f|)
R|/foo2|(<L> = foo2@fun <anonymous>(x: R|kotlin/Nothing|): kotlin/Boolean <kind=EXACTLY_ONCE> {
>(R|<local>/x|, Int(1))
}
)
<Inapplicable(INAPPLICABLE): [/foo2]>#(R|<local>/f|)
<Ambiguity: foo3, [/foo3, /foo3]>#(<L> = foo3@fun <implicit>.<anonymous>(x: <implicit>): <implicit> <kind=EXACTLY_ONCE> {
>(x#, Int(1))
}
)
R|/foo3|(R|<local>/f|)
<Unresolved name: foo4>#(<L> = foo4@fun <implicit>.<anonymous>(x: <implicit>): <implicit> <kind=EXACTLY_ONCE> {
>(x#, Int(1))
}
)
<Unresolved name: foo4>#(R|<local>/f|)
}
@@ -0,0 +1,31 @@
// FILE: MyRunnable.java
public interface MyRunnable {
void bar();
}
// FILE: DerivedRunnable.java
public interface DerivedRunnable extends MyRunnable {
boolean foo(int x);
}
// FILE: JavaUsage.java
public class JavaUsage {
public static void foo(DerivedRunnable x) {}
}
// FILE: main.kt
fun foo(m: MyRunnable) {}
fun main() {
JavaUsage.foo {
x ->
x > 1
}
JavaUsage.foo({ it > 1 })
val x = { x: Int -> x > 1 }
JavaUsage.foo(x)
}
@@ -0,0 +1,18 @@
FILE: main.kt
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Nothing|): kotlin/Boolean <kind=EXACTLY_ONCE> {
>(R|<local>/x|, Int(1))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(): kotlin/Boolean <kind=EXACTLY_ONCE> {
>(<Unresolved name: it>#, Int(1))
}
)
lval x: R|kotlin/Function1<kotlin/Int, kotlin/Boolean>| = fun <anonymous>(x: R|kotlin/Int|): kotlin/Boolean {
>(R|<local>/x|, Int(1))
}
Q|JavaUsage|.<Inapplicable(INAPPLICABLE): [/JavaUsage.foo]>#(R|<local>/x|)
}
@@ -0,0 +1,16 @@
// FILE: JavaClass.java
public class JavaClass {
public static void foo(Runnable x) {}
public void bar(Runnable x) {}
}
// FILE: main.kt
fun main() {
JavaClass.foo {
""
}
JavaClass().bar {
""
}
}
@@ -0,0 +1,11 @@
FILE: main.kt
public final fun main(): R|kotlin/Unit| {
Q|JavaClass|.R|/JavaClass.foo|(<L> = foo@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
String()
}
)
R|/JavaClass.JavaClass|().R|/JavaClass.bar|(<L> = bar@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
String()
}
)
}
@@ -0,0 +1,32 @@
// FILE: MyRunnable.java
public interface MyRunnable {
boolean foo(int x);
default void bar() {}
}
// FILE: DerivedRunnable.java
public interface DerivedRunnable extends MyRunnable {
default void baz() {}
}
// FILE: JavaUsage.java
public class JavaUsage {
public static void foo(DerivedRunnable x) {}
}
// FILE: main.kt
fun foo(m: MyRunnable) {}
fun main() {
JavaUsage.foo {
x ->
x > 1
}
JavaUsage.foo({ it > 1 })
val x = { x: Int -> x > 1 }
JavaUsage.foo(x)
}
@@ -0,0 +1,18 @@
FILE: main.kt
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
>(R|<local>/x|, Int(1))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
>(R|<local>/it|, Int(1))
}
)
lval x: R|kotlin/Function1<kotlin/Int, kotlin/Boolean>| = fun <anonymous>(x: R|kotlin/Int|): kotlin/Boolean {
>(R|<local>/x|, Int(1))
}
Q|JavaUsage|.R|/JavaUsage.foo|(R|<local>/x|)
}
@@ -0,0 +1,34 @@
// FILE: MyRunnable.java
public interface MyRunnable {
Object foo(int x);
default void bar() {}
}
// FILE: DerivedRunnable.java
public interface DerivedRunnable extends MyRunnable {
@Override
Boolean foo(int x);
default void baz() {}
}
// FILE: JavaUsage.java
public class JavaUsage {
public static void foo(DerivedRunnable x) {}
}
// FILE: main.kt
fun foo(m: MyRunnable) {}
fun main() {
JavaUsage.foo {
x ->
x > 1
}
JavaUsage.foo({ it > 1 })
val x = { x: Int -> x > 1 }
JavaUsage.foo(x)
}
@@ -0,0 +1,18 @@
FILE: main.kt
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Int|): R|ft<kotlin/Boolean, kotlin/Boolean?>!| <kind=EXACTLY_ONCE> {
>(R|<local>/x|, Int(1))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(it: R|kotlin/Int|): R|ft<kotlin/Boolean, kotlin/Boolean?>!| <kind=EXACTLY_ONCE> {
>(R|<local>/it|, Int(1))
}
)
lval x: R|kotlin/Function1<kotlin/Int, kotlin/Boolean>| = fun <anonymous>(x: R|kotlin/Int|): kotlin/Boolean {
>(R|<local>/x|, Int(1))
}
Q|JavaUsage|.R|/JavaUsage.foo|(R|<local>/x|)
}
@@ -0,0 +1,26 @@
// FILE: MyRunnable.java
public interface MyRunnable {
boolean foo(int x);
}
// FILE: JavaUsage.java
public class JavaUsage {
public static void foo(MyRunnable x) {}
}
// FILE: main.kt
fun foo(m: MyRunnable) {}
fun main() {
JavaUsage.foo {
x ->
x > 1
}
JavaUsage.foo({ it > 1 })
val x = { x: Int -> x > 1 }
JavaUsage.foo(x)
}
@@ -0,0 +1,18 @@
FILE: main.kt
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
>(R|<local>/x|, Int(1))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
>(R|<local>/it|, Int(1))
}
)
lval x: R|kotlin/Function1<kotlin/Int, kotlin/Boolean>| = fun <anonymous>(x: R|kotlin/Int|): kotlin/Boolean {
>(R|<local>/x|, Int(1))
}
Q|JavaUsage|.R|/JavaUsage.foo|(R|<local>/x|)
}
@@ -91,4 +91,52 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/diagnostics/j+k/outerInnerClasses.kt");
}
}
@TestMetadata("compiler/fir/resolve/testData/diagnostics/samConversions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SamConversions extends AbstractFirDiagnosticsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInSamConversions() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/resolve/testData/diagnostics/samConversions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("genericSam.kt")
public void testGenericSam() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/genericSam.kt");
}
@TestMetadata("kotlinSam.kt")
public void testKotlinSam() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/kotlinSam.kt");
}
@TestMetadata("notSamBecauseOfSupertype.kt")
public void testNotSamBecauseOfSupertype() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/notSamBecauseOfSupertype.kt");
}
@TestMetadata("runnable.kt")
public void testRunnable() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/runnable.kt");
}
@TestMetadata("samSupertype.kt")
public void testSamSupertype() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/samSupertype.kt");
}
@TestMetadata("samSupertypeWithOverride.kt")
public void testSamSupertypeWithOverride() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/samSupertypeWithOverride.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/samConversions/simple.kt");
}
}
}
@@ -2,8 +2,8 @@ FILE fqName:<root> fileName:/samByProjectedType.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public open fun bar (j: <root>.J<*>?): kotlin.Unit declared in <root>.H' type=kotlin.Unit origin=null
j: FUN_EXPR type=kotlin.Function1<kotlin.Any, kotlin.Any> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.Any) returnType:kotlin.Any
j: FUN_EXPR type=kotlin.Function1<kotlin.Any, kotlin.Any?> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.Any) returnType:kotlin.Any?
VALUE_PARAMETER name:x index:0 type:kotlin.Any
BLOCK_BODY
GET_VAR 'x: kotlin.Any declared in <root>.test1.<anonymous>' type=kotlin.Any origin=null
@@ -38,22 +38,22 @@ FILE fqName:<root> fileName:/samConversionToGeneric.kt
BLOCK_BODY
TYPE_OP type=kotlin.Function1<kotlin.String, kotlin.String> origin=CAST typeOperand=kotlin.Function1<kotlin.String, kotlin.String>
GET_VAR 'a: kotlin.Any declared in <root>.test5' type=kotlin.Any origin=null
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/H.bar]>#' type=IrErrorType
GET_VAR 'a: kotlin.Any declared in <root>.test5' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
CALL 'public open fun bar (j: <root>.J<X of <uninitialized parent>?>?): kotlin.Unit declared in <root>.H' type=kotlin.Unit origin=null
j: GET_VAR 'a: kotlin.Any declared in <root>.test5' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
FUN name:test6 visibility:public modality:FINAL <T> (a:kotlin.Function1<T of <root>.test6, T of <root>.test6>) returnType:kotlin.Unit
TYPE_PARAMETER name:T index:0 variance: superTypes:[]
VALUE_PARAMETER name:a index:0 type:kotlin.Function1<T of <root>.test6, T of <root>.test6>
BLOCK_BODY
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/H.bar]>#' type=IrErrorType
GET_VAR 'a: kotlin.Function1<T of <root>.test6, T of <root>.test6> declared in <root>.test6' type=kotlin.Function1<T of <root>.test6, T of <root>.test6> origin=null
CALL 'public open fun bar (j: <root>.J<X of <uninitialized parent>?>?): kotlin.Unit declared in <root>.H' type=kotlin.Unit origin=null
j: GET_VAR 'a: kotlin.Function1<T of <root>.test6, T of <root>.test6> declared in <root>.test6' type=kotlin.Function1<T of <root>.test6, T of <root>.test6> origin=null
FUN name:test7 visibility:public modality:FINAL <T> (a:kotlin.Any) returnType:kotlin.Unit
TYPE_PARAMETER name:T index:0 variance: superTypes:[]
VALUE_PARAMETER name:a index:0 type:kotlin.Any
BLOCK_BODY
TYPE_OP type=kotlin.Function1<T of <root>.test7, T of <root>.test7> origin=CAST typeOperand=kotlin.Function1<T of <root>.test7, T of <root>.test7>
GET_VAR 'a: kotlin.Any declared in <root>.test7' type=kotlin.Any origin=null
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/H.bar]>#' type=IrErrorType
GET_VAR 'a: kotlin.Any declared in <root>.test7' type=kotlin.Function1<T of <root>.test7, T of <root>.test7> origin=null
CALL 'public open fun bar (j: <root>.J<X of <uninitialized parent>?>?): kotlin.Unit declared in <root>.H' type=kotlin.Unit origin=null
j: GET_VAR 'a: kotlin.Any declared in <root>.test7' type=kotlin.Function1<T of <root>.test7, T of <root>.test7> origin=null
FUN name:test8 visibility:public modality:FINAL <> (efn:kotlin.Function1<kotlin.String, kotlin.String>) returnType:IrErrorType
VALUE_PARAMETER name:efn index:0 type:kotlin.Function1<kotlin.String, kotlin.String>
BLOCK_BODY
@@ -63,8 +63,8 @@ FILE fqName:<root> fileName:/samConversionToGeneric.kt
FUN name:test9 visibility:public modality:FINAL <> (efn:kotlin.Function1<kotlin.String, kotlin.String>) returnType:kotlin.Unit
VALUE_PARAMETER name:efn index:0 type:kotlin.Function1<kotlin.String, kotlin.String>
BLOCK_BODY
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/H.bar]>#' type=IrErrorType
GET_VAR 'efn: kotlin.Function1<kotlin.String, kotlin.String> declared in <root>.test9' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
CALL 'public open fun bar (j: <root>.J<X of <uninitialized parent>?>?): kotlin.Unit declared in <root>.H' type=kotlin.Unit origin=null
j: GET_VAR 'efn: kotlin.Function1<kotlin.String, kotlin.String> declared in <root>.test9' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
FUN name:test10 visibility:public modality:FINAL <> (fn:kotlin.Function1<kotlin.Int, kotlin.String>) returnType:kotlin.Unit
VALUE_PARAMETER name:fn index:0 type:kotlin.Function1<kotlin.Int, kotlin.String>
BLOCK_BODY
@@ -28,17 +28,19 @@ FILE fqName:<root> fileName:/samConversions.kt
$receiver: VALUE_PARAMETER name:<this> type:<root>.J
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit>
BLOCK_BODY
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/J.run2]>#' type=IrErrorType
GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test3' type=kotlin.Function0<kotlin.Unit> origin=null
GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test3' type=kotlin.Function0<kotlin.Unit> origin=null
CALL 'public open fun run2 (r1: java.lang.Runnable?, r2: java.lang.Runnable?): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=null
$this: GET_VAR '<this>: <root>.J declared in <root>.J' type=<root>.J origin=null
r1: GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test3' type=kotlin.Function0<kotlin.Unit> origin=null
r2: GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test3' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test4 visibility:public modality:FINAL <> ($receiver:<root>.J, a:kotlin.Function0<kotlin.Unit>, b:kotlin.Function0<kotlin.Unit>, flag:kotlin.Boolean) returnType:kotlin.Unit
$receiver: VALUE_PARAMETER name:<this> type:<root>.J
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit>
VALUE_PARAMETER name:b index:1 type:kotlin.Function0<kotlin.Unit>
VALUE_PARAMETER name:flag index:2 type:kotlin.Boolean
BLOCK_BODY
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/J.runIt]>#' type=IrErrorType
WHEN type=kotlin.Function0<kotlin.Unit> origin=IF
CALL 'public open fun runIt (r: java.lang.Runnable?): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=null
$this: GET_VAR '<this>: <root>.J declared in <root>.J' type=<root>.J origin=null
r: WHEN type=kotlin.Function0<kotlin.Unit> origin=IF
BRANCH
if: GET_VAR 'flag: kotlin.Boolean declared in <root>.test4' type=kotlin.Boolean origin=null
then: GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test4' type=kotlin.Function0<kotlin.Unit> origin=null
@@ -33,13 +33,14 @@ FILE fqName:<root> fileName:/samConversionsWithSmartCasts.kt
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit>
VALUE_PARAMETER name:b index:1 type:kotlin.Function0<kotlin.Unit>
BLOCK_BODY
WHEN type=IrErrorType origin=IF
WHEN type=kotlin.Unit origin=IF
BRANCH
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=java.lang.Runnable
GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test4' type=kotlin.Function0<kotlin.Unit> origin=null
then: ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/J.run2]>#' type=IrErrorType
GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test4' type=java.lang.Runnable origin=null
GET_VAR 'b: kotlin.Function0<kotlin.Unit> declared in <root>.test4' type=kotlin.Function0<kotlin.Unit> origin=null
then: CALL 'public open fun run2 (r1: java.lang.Runnable?, r2: java.lang.Runnable?): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=null
$this: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.J' type=<root>.J origin=null
r1: GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test4' type=java.lang.Runnable origin=null
r2: GET_VAR 'b: kotlin.Function0<kotlin.Unit> declared in <root>.test4' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test5 visibility:public modality:FINAL <> (a:kotlin.Any) returnType:kotlin.Unit
VALUE_PARAMETER name:a index:0 type:kotlin.Any
BLOCK_BODY
@@ -68,8 +69,9 @@ FILE fqName:<root> fileName:/samConversionsWithSmartCasts.kt
BLOCK_BODY
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=CAST typeOperand=kotlin.Function0<kotlin.Unit>
GET_VAR 'a: kotlin.Any declared in <root>.test6' type=kotlin.Any origin=null
ERROR_CALL 'Unresolved reference: <Inapplicable(INAPPLICABLE): [/J.run1]>#' type=IrErrorType
GET_VAR 'a: kotlin.Any declared in <root>.test6' type=kotlin.Function0<kotlin.Unit> origin=null
CALL 'public open fun run1 (r: java.lang.Runnable?): kotlin.Unit declared in <root>.J' type=kotlin.Unit origin=null
$this: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.J' type=<root>.J origin=null
r: GET_VAR 'a: kotlin.Any declared in <root>.test6' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:test7 visibility:public modality:FINAL <> (a:kotlin.Function1<kotlin.Int, kotlin.Int>) returnType:kotlin.Unit
VALUE_PARAMETER name:a index:0 type:kotlin.Function1<kotlin.Int, kotlin.Int>
BLOCK_BODY