[FIR2IR] Support SAM constructors

This commit is contained in:
simon.ogorodnik
2020-05-20 20:27:52 +03:00
parent dbc564e74e
commit ac1769a474
25 changed files with 37 additions and 55 deletions
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.fir.backend.generators package org.jetbrains.kotlin.fir.backend.generators
import org.jetbrains.kotlin.fir.backend.* import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
@@ -153,10 +151,27 @@ internal class CallAndReferenceGenerator(
} }
} }
private fun FirQualifiedAccess.tryConvertToSamConstructorCall(type: IrType): IrTypeOperatorCall? {
val calleeReference = calleeReference as? FirResolvedNamedReference ?: return null
val fir = calleeReference.resolvedSymbol.fir
if (this is FirFunctionCall && fir is FirSimpleFunction && fir.origin == FirDeclarationOrigin.SamConstructor) {
return convertWithOffsets { startOffset, endOffset ->
IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.SAM_CONVERSION, type).apply {
argument = visitor.convertToIrExpression(this@tryConvertToSamConstructorCall.argument)
}
}
}
return null
}
private fun convertToUnsafeIrCall( private fun convertToUnsafeIrCall(
qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef, explicitReceiverExpression: IrExpression?, makeNotNull: Boolean = false qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef, explicitReceiverExpression: IrExpression?, makeNotNull: Boolean = false
): IrExpression { ): IrExpression {
val type = typeRef.toIrType().let { if (makeNotNull) it.makeNotNull() else it } val type = typeRef.toIrType().let { if (makeNotNull) it.makeNotNull() else it }
val samConstructorCall = qualifiedAccess.tryConvertToSamConstructorCall(type)
if (samConstructorCall != null) return samConstructorCall
val symbol = qualifiedAccess.calleeReference.toSymbol( val symbol = qualifiedAccess.calleeReference.toSymbol(
session, session,
classifierStorage, classifierStorage,
@@ -1,5 +1,4 @@
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_DCE_DRIVEN // SKIP_DCE_DRIVEN
@@ -1,5 +1,4 @@
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// SKIP_DCE_DRIVEN // SKIP_DCE_DRIVEN
@@ -1,6 +1,5 @@
// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_DCE_DRIVEN // SKIP_DCE_DRIVEN
// This test should check argument coercion between the SAM and the lambda. // This test should check argument coercion between the SAM and the lambda.
@@ -1,5 +1,4 @@
// !LANGUAGE: +FunctionalInterfaceConversion // !LANGUAGE: +FunctionalInterfaceConversion
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_DCE_DRIVEN // SKIP_DCE_DRIVEN
fun interface S { fun interface S {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
fun test(a: Any?) { fun test(a: Any?) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
import java.io.* import java.io.*
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// SKIP_JDK6 // SKIP_JDK6
// FULL_JDK // FULL_JDK
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
var result = "FAIL" var result = "FAIL"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
var result = "FAIL" var result = "FAIL"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
class Box(val s: String) { class Box(val s: String) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// TODO: muted automatically, investigate should it be ran for JS or not // TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS, NATIVE // IGNORE_BACKEND: JS, NATIVE
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
// FILE: Test.java // FILE: Test.java
@@ -22,6 +22,6 @@ FILE fqName:<root> fileName:/castFromAny.kt
TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=CAST typeOperand=kotlin.Function0<kotlin.Unit> TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=CAST typeOperand=kotlin.Function0<kotlin.Unit>
GET_VAR 'a: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null GET_VAR 'a: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
CALL 'public abstract fun invoke (): kotlin.Unit declared in <root>.KRunnable' type=kotlin.Unit origin=null CALL 'public abstract fun invoke (): kotlin.Unit declared in <root>.KRunnable' type=kotlin.Unit origin=null
$this: CALL 'public final fun KRunnable (block: kotlin.Function0<kotlin.Unit>): <root>.KRunnable declared in <root>' type=<root>.KRunnable origin=null $this: TYPE_OP type=<root>.KRunnable origin=SAM_CONVERSION typeOperand=<root>.KRunnable
block: TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.Function0<kotlin.Unit> TYPE_OP type=kotlin.Function0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.Function0<kotlin.Unit>
GET_VAR 'a: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null GET_VAR 'a: kotlin.Any? declared in <root>.test' type=kotlin.Any? origin=null
@@ -29,8 +29,8 @@ FILE fqName:<root> fileName:/samConversionOnCallableReference.kt
FUN name:testSamConstructor visibility:public modality:FINAL <> () returnType:<root>.KRunnable FUN name:testSamConstructor visibility:public modality:FINAL <> () returnType:<root>.KRunnable
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun testSamConstructor (): <root>.KRunnable declared in <root>' RETURN type=kotlin.Nothing from='public final fun testSamConstructor (): <root>.KRunnable declared in <root>'
CALL 'public final fun KRunnable (block: kotlin.Function0<kotlin.Unit>): <root>.KRunnable declared in <root>' type=<root>.KRunnable origin=null TYPE_OP type=<root>.KRunnable origin=SAM_CONVERSION typeOperand=<root>.KRunnable
block: FUNCTION_REFERENCE 'public final fun foo0 (): kotlin.Unit declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Unit> origin=null reflectionTarget=<same> FUNCTION_REFERENCE 'public final fun foo0 (): kotlin.Unit declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Unit> origin=null reflectionTarget=<same>
FUN name:testSamCosntructorOnAdapted visibility:public modality:FINAL <> () returnType:IrErrorType FUN name:testSamCosntructorOnAdapted visibility:public modality:FINAL <> () returnType:IrErrorType
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun testSamCosntructorOnAdapted (): IrErrorType declared in <root>' RETURN type=kotlin.Nothing from='public final fun testSamCosntructorOnAdapted (): IrErrorType declared in <root>'
@@ -2,8 +2,8 @@ FILE fqName:<root> fileName:/samConstructors.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:java.lang.Runnable FUN name:test1 visibility:public modality:FINAL <> () returnType:java.lang.Runnable
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test1 (): java.lang.Runnable declared in <root>' RETURN type=kotlin.Nothing from='public final fun test1 (): java.lang.Runnable declared in <root>'
CALL 'public final fun Runnable (block: kotlin.Function0<kotlin.Unit>): java.lang.Runnable declared in java.lang' type=java.lang.Runnable origin=null TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
block: FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.Unit declared in <root>.test1' RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.Unit declared in <root>.test1'
@@ -12,21 +12,20 @@ FILE fqName:<root> fileName:/samConstructors.kt
VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit> VALUE_PARAMETER name:a index:0 type:kotlin.Function0<kotlin.Unit>
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test2 (a: kotlin.Function0<kotlin.Unit>): java.lang.Runnable declared in <root>' RETURN type=kotlin.Nothing from='public final fun test2 (a: kotlin.Function0<kotlin.Unit>): java.lang.Runnable declared in <root>'
CALL 'public final fun Runnable (block: kotlin.Function0<kotlin.Unit>): java.lang.Runnable declared in java.lang' type=java.lang.Runnable origin=null TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
block: GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test2' type=kotlin.Function0<kotlin.Unit> origin=null GET_VAR 'a: kotlin.Function0<kotlin.Unit> declared in <root>.test2' type=kotlin.Function0<kotlin.Unit> origin=null
FUN name:foo visibility:public modality:FINAL <> () returnType:kotlin.Unit FUN name:foo visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY BLOCK_BODY
FUN name:test3 visibility:public modality:FINAL <> () returnType:java.lang.Runnable FUN name:test3 visibility:public modality:FINAL <> () returnType:java.lang.Runnable
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test3 (): java.lang.Runnable declared in <root>' RETURN type=kotlin.Nothing from='public final fun test3 (): java.lang.Runnable declared in <root>'
CALL 'public final fun Runnable (block: kotlin.Function0<kotlin.Unit>): java.lang.Runnable declared in java.lang' type=java.lang.Runnable origin=null TYPE_OP type=java.lang.Runnable origin=SAM_CONVERSION typeOperand=java.lang.Runnable
block: FUNCTION_REFERENCE 'public final fun foo (): kotlin.Unit declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Unit> origin=null reflectionTarget=<same> FUNCTION_REFERENCE 'public final fun foo (): kotlin.Unit declared in <root>' type=kotlin.reflect.KFunction0<kotlin.Unit> origin=null reflectionTarget=<same>
FUN name:test4 visibility:public modality:FINAL <> () returnType:java.util.Comparator<kotlin.Int?> FUN name:test4 visibility:public modality:FINAL <> () returnType:java.util.Comparator<kotlin.Int?>
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test4 (): java.util.Comparator<kotlin.Int?> declared in <root>' RETURN type=kotlin.Nothing from='public final fun test4 (): java.util.Comparator<kotlin.Int?> declared in <root>'
CALL 'public final fun Comparator <T> (block: kotlin.Function2<T of java.util.Comparator?, T of java.util.Comparator?, kotlin.Int>): java.util.Comparator<T of java.util.Comparator> declared in java.util' type=java.util.Comparator<kotlin.Int?> origin=null TYPE_OP type=java.util.Comparator<kotlin.Int?> origin=SAM_CONVERSION typeOperand=java.util.Comparator<kotlin.Int?>
<T>: kotlin.Int? FUN_EXPR type=kotlin.Function2<kotlin.Int?, kotlin.Int?, kotlin.Int> origin=LAMBDA
block: FUN_EXPR type=kotlin.Function2<kotlin.Int?, kotlin.Int?, kotlin.Int> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (a:kotlin.Int?, b:kotlin.Int?) returnType:kotlin.Int FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (a:kotlin.Int?, b:kotlin.Int?) returnType:kotlin.Int
VALUE_PARAMETER name:a index:0 type:kotlin.Int? VALUE_PARAMETER name:a index:0 type:kotlin.Int?
VALUE_PARAMETER name:b index:1 type:kotlin.Int? VALUE_PARAMETER name:b index:1 type:kotlin.Int?
@@ -2,9 +2,8 @@ FILE fqName:<root> fileName:/samConversionToGeneric.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:<root>.J<kotlin.String?> FUN name:test1 visibility:public modality:FINAL <> () returnType:<root>.J<kotlin.String?>
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test1 (): <root>.J<kotlin.String?> declared in <root>' RETURN type=kotlin.Nothing from='public final fun test1 (): <root>.J<kotlin.String?> declared in <root>'
CALL 'public final fun J <T> (block: kotlin.Function1<T of <root>.J?, T of <root>.J?>): <root>.J<T of <root>.J> declared in <root>' type=<root>.J<kotlin.String?> origin=null TYPE_OP type=<root>.J<kotlin.String?> origin=SAM_CONVERSION typeOperand=<root>.J<kotlin.String?>
<T>: kotlin.String? FUN_EXPR type=kotlin.Function1<kotlin.String?, kotlin.String?> origin=LAMBDA
block: FUN_EXPR type=kotlin.Function1<kotlin.String?, kotlin.String?> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.String?) returnType:kotlin.String? FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.String?) returnType:kotlin.String?
VALUE_PARAMETER name:x index:0 type:kotlin.String? VALUE_PARAMETER name:x index:0 type:kotlin.String?
BLOCK_BODY BLOCK_BODY
@@ -13,9 +12,8 @@ FILE fqName:<root> fileName:/samConversionToGeneric.kt
FUN name:test2 visibility:public modality:FINAL <> () returnType:<root>.J<kotlin.String?> FUN name:test2 visibility:public modality:FINAL <> () returnType:<root>.J<kotlin.String?>
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test2 (): <root>.J<kotlin.String?> declared in <root>' RETURN type=kotlin.Nothing from='public final fun test2 (): <root>.J<kotlin.String?> declared in <root>'
CALL 'public final fun J <T> (block: kotlin.Function1<T of <root>.J?, T of <root>.J?>): <root>.J<T of <root>.J> declared in <root>' type=<root>.J<kotlin.String?> origin=null TYPE_OP type=<root>.J<kotlin.String?> origin=SAM_CONVERSION typeOperand=<root>.J<kotlin.String?>
<T>: kotlin.String? FUN_EXPR type=kotlin.Function1<kotlin.String, kotlin.String> origin=LAMBDA
block: FUN_EXPR type=kotlin.Function1<kotlin.String, kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.String) returnType:kotlin.String FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (x:kotlin.String) returnType:kotlin.String
VALUE_PARAMETER name:x index:0 type:kotlin.String VALUE_PARAMETER name:x index:0 type:kotlin.String
BLOCK_BODY BLOCK_BODY
@@ -75,9 +73,8 @@ FILE fqName:<root> fileName:/samConversionToGeneric.kt
VALUE_PARAMETER name:efn index:0 type:kotlin.Function1<kotlin.String, kotlin.String> VALUE_PARAMETER name:efn index:0 type:kotlin.Function1<kotlin.String, kotlin.String>
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test8 (efn: kotlin.Function1<kotlin.String, kotlin.String>): <root>.J<kotlin.String?> declared in <root>' RETURN type=kotlin.Nothing from='public final fun test8 (efn: kotlin.Function1<kotlin.String, kotlin.String>): <root>.J<kotlin.String?> declared in <root>'
CALL 'public final fun J <T> (block: kotlin.Function1<T of <root>.J?, T of <root>.J?>): <root>.J<T of <root>.J> declared in <root>' type=<root>.J<kotlin.String?> origin=null TYPE_OP type=<root>.J<kotlin.String?> origin=SAM_CONVERSION typeOperand=<root>.J<kotlin.String?>
<T>: kotlin.String? GET_VAR 'efn: kotlin.Function1<kotlin.String, kotlin.String> declared in <root>.test8' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
block: GET_VAR 'efn: kotlin.Function1<kotlin.String, kotlin.String> declared in <root>.test8' type=kotlin.Function1<kotlin.String, kotlin.String> origin=null
FUN name:test9 visibility:public modality:FINAL <> (efn:kotlin.Function1<kotlin.String, kotlin.String>) returnType:kotlin.Unit 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> VALUE_PARAMETER name:efn index:0 type:kotlin.Function1<kotlin.String, kotlin.String>
BLOCK_BODY BLOCK_BODY
-12
View File
@@ -1,12 +0,0 @@
FILE fqName:<root> fileName:/samAdapter.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
VAR name:hello type:java.lang.Runnable [val]
CALL 'public final fun Runnable (block: kotlin.Function0<kotlin.Unit>): java.lang.Runnable declared in java.lang' type=java.lang.Runnable origin=null
block: FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CALL 'public final fun println (message: kotlin.Any?): kotlin.Unit [inline] declared in kotlin.io' type=kotlin.Unit origin=null
message: CONST String type=kotlin.String value="Hello, world!"
CALL 'public abstract fun run (): kotlin.Unit declared in java.lang.Runnable' type=kotlin.Unit origin=null
$this: GET_VAR 'val hello: java.lang.Runnable [val] declared in <root>.test1' type=java.lang.Runnable origin=null
+1
View File
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// WITH_RUNTIME // WITH_RUNTIME
fun test1() { fun test1() {