FIR: Support SAM conversion
This commit is contained in:
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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|)
|
||||
}
|
||||
+31
@@ -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)
|
||||
}
|
||||
+18
@@ -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|)
|
||||
}
|
||||
+34
@@ -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)
|
||||
}
|
||||
+18
@@ -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|)
|
||||
}
|
||||
+48
@@ -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
|
||||
|
||||
+8
-6
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user