[FIR2IR] Convert explicit receiver in advance

This commit is contained in:
Mikhail Glukhikh
2020-04-08 14:48:01 +03:00
parent b815cb7e4a
commit e1c78b31a6
23 changed files with 58 additions and 52 deletions
@@ -265,7 +265,8 @@ class Fir2IrVisitor(
} else {
functionCall
}
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef)
val explicitReceiverExpression = convertToIrReceiverExpression(functionCall.explicitReceiver)
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef, explicitReceiverExpression)
}
private fun FirFunctionCall.resolvedNamedFunctionSymbol(): FirNamedFunctionSymbol? {
@@ -278,7 +279,8 @@ class Fir2IrVisitor(
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any?): IrElement {
return callGenerator.convertToIrCall(qualifiedAccessExpression, qualifiedAccessExpression.typeRef)
val explicitReceiverExpression = convertToIrReceiverExpression(qualifiedAccessExpression.explicitReceiver)
return callGenerator.convertToIrCall(qualifiedAccessExpression, qualifiedAccessExpression.typeRef, explicitReceiverExpression)
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: Any?): IrElement {
@@ -333,11 +335,15 @@ class Fir2IrVisitor(
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement {
return callGenerator.convertToIrCallableReference(callableReferenceAccess)
val explicitReceiverExpression = convertToIrReceiverExpression(
callableReferenceAccess.explicitReceiver, callableReferenceMode = true
)
return callGenerator.convertToIrCallableReference(callableReferenceAccess, explicitReceiverExpression)
}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement {
return callGenerator.convertToIrSetCall(variableAssignment)
val explicitReceiverExpression = convertToIrReceiverExpression(variableAssignment.explicitReceiver)
return callGenerator.convertToIrSetCall(variableAssignment, explicitReceiverExpression)
}
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Any?): IrElement =
@@ -365,6 +371,14 @@ class Fir2IrVisitor(
}
}
private fun convertToIrReceiverExpression(expression: FirExpression?, callableReferenceMode: Boolean = false): IrExpression? {
return when (expression) {
null -> null
is FirResolvedQualifier -> callGenerator.convertToGetObject(expression, callableReferenceMode)
else -> convertToIrExpression(expression)
}
}
private fun FirBlock.mapToIrStatements(): List<IrStatement?> {
val irRawStatements = statements.map { it.toIrStatement() }
val result = mutableListOf<IrStatement?>()
@@ -44,7 +44,10 @@ internal class CallAndReferenceGenerator(
private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() }
fun convertToIrCallableReference(callableReferenceAccess: FirCallableReferenceAccess): IrExpression {
fun convertToIrCallableReference(
callableReferenceAccess: FirCallableReferenceAccess,
explicitReceiverExpression: IrExpression?
): IrExpression {
val symbol = callableReferenceAccess.calleeReference.toSymbol(session, classifierStorage, declarationStorage, conversionScope)
val type = callableReferenceAccess.typeRef.toIrType()
return callableReferenceAccess.convertWithOffsets { startOffset, endOffset ->
@@ -91,22 +94,27 @@ internal class CallAndReferenceGenerator(
)
}
}
}.applyTypeArguments(callableReferenceAccess).applyReceivers(callableReferenceAccess)
}.applyTypeArguments(callableReferenceAccess).applyReceivers(callableReferenceAccess, explicitReceiverExpression)
}
fun convertToIrCall(qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef): IrExpression {
fun convertToIrCall(
qualifiedAccess: FirQualifiedAccess,
typeRef: FirTypeRef,
explicitReceiverExpression: IrExpression?
): IrExpression {
val explicitReceiver = qualifiedAccess.explicitReceiver
if (!qualifiedAccess.safe || explicitReceiver == null) {
return convertToUnsafeIrCall(qualifiedAccess, typeRef)
return convertToUnsafeIrCall(qualifiedAccess, typeRef, explicitReceiverExpression)
}
return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
val type = typeRef.toIrType()
val callableSymbol = (qualifiedAccess.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirCallableSymbol<*>
val typeShouldBeNotNull = callableSymbol?.fir?.returnTypeRef?.coneTypeSafe<ConeKotlinType>()?.isNullable == false
val unsafeIrCall = convertToUnsafeIrCall(qualifiedAccess, typeRef, makeNotNull = typeShouldBeNotNull)
val unsafeIrCall = convertToUnsafeIrCall(
qualifiedAccess, typeRef, explicitReceiverExpression, makeNotNull = typeShouldBeNotNull
)
IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.SAFE_CALL).apply {
val receiver = visitor.convertToIrExpression(explicitReceiver)
val receiverVariable = declarationStorage.declareTemporaryVariable(receiver).apply {
val receiverVariable = declarationStorage.declareTemporaryVariable(explicitReceiverExpression!!).apply {
parent = conversionScope.parentFromStack()
}
statements += receiverVariable
@@ -135,7 +143,7 @@ internal class CallAndReferenceGenerator(
}
private fun convertToUnsafeIrCall(
qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef, makeNotNull: Boolean = false
qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef, explicitReceiverExpression: IrExpression?, makeNotNull: Boolean = false
): IrExpression {
val type = typeRef.toIrType().let { if (makeNotNull) it.makeNotNull() else it }
val symbol = qualifiedAccess.calleeReference.toSymbol(
@@ -181,10 +189,11 @@ internal class CallAndReferenceGenerator(
is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
else -> generateErrorCallExpression(startOffset, endOffset, qualifiedAccess.calleeReference, type)
}
}.applyCallArguments(qualifiedAccess as? FirCall).applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess)
}.applyCallArguments(qualifiedAccess as? FirCall)
.applyTypeArguments(qualifiedAccess).applyReceivers(qualifiedAccess, explicitReceiverExpression)
}
fun convertToIrSetCall(variableAssignment: FirVariableAssignment): IrExpression {
fun convertToIrSetCall(variableAssignment: FirVariableAssignment, explicitReceiverExpression: IrExpression?): IrExpression {
val type = irBuiltIns.unitType
val calleeReference = variableAssignment.calleeReference
val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage, conversionScope, preferGetter = false)
@@ -218,7 +227,7 @@ internal class CallAndReferenceGenerator(
is IrVariableSymbol -> IrSetVariableImpl(startOffset, endOffset, type, symbol, assignedValue, origin)
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
}
}.applyTypeArguments(variableAssignment).applyReceivers(variableAssignment)
}.applyTypeArguments(variableAssignment).applyReceivers(variableAssignment, explicitReceiverExpression)
}
fun convertToIrConstructorCall(annotationCall: FirAnnotationCall): IrExpression {
@@ -257,7 +266,7 @@ internal class CallAndReferenceGenerator(
return convertToGetObject(qualifier, callableReferenceMode = false)!!
}
private fun convertToGetObject(qualifier: FirResolvedQualifier, callableReferenceMode: Boolean): IrExpression? {
internal fun convertToGetObject(qualifier: FirResolvedQualifier, callableReferenceMode: Boolean): IrExpression? {
val typeRef = qualifier.typeRef as? FirResolvedTypeRef
val classSymbol = (typeRef?.type as? ConeClassLikeType)?.lookupTag?.toSymbol(session)
if (callableReferenceMode && classSymbol is FirRegularClassSymbol) {
@@ -351,22 +360,26 @@ internal class CallAndReferenceGenerator(
}
}
private fun FirQualifiedAccess.findIrDispatchReceiver(): IrExpression? = findIrReceiver(isDispatch = true)
private fun FirQualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression: IrExpression?): IrExpression? =
findIrReceiver(explicitReceiverExpression, isDispatch = true)
private fun FirQualifiedAccess.findIrExtensionReceiver(): IrExpression? = findIrReceiver(isDispatch = false)
private fun FirQualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression: IrExpression?): IrExpression? =
findIrReceiver(explicitReceiverExpression, isDispatch = false)
private fun FirQualifiedAccess.findIrReceiver(isDispatch: Boolean): IrExpression? {
private fun FirQualifiedAccess.findIrReceiver(explicitReceiverExpression: IrExpression?, isDispatch: Boolean): IrExpression? {
val firReceiver = if (isDispatch) dispatchReceiver else extensionReceiver
if (firReceiver == explicitReceiver) {
// TODO: remove after fix of KT-35730 (temporary hack to prevent receiver duplication)
if (!isDispatch && dispatchReceiver is FirNoReceiverExpression) {
return visitor.convertToIrExpression(firReceiver)
}
return explicitReceiverExpression
}
if (firReceiver is FirResolvedQualifier) {
return convertToGetObject(firReceiver, callableReferenceMode = this is FirCallableReferenceAccess)
}
return firReceiver.takeIf { it !is FirNoReceiverExpression }?.let { visitor.convertToIrExpression(it) }
?: explicitReceiver?.let {
if (it is FirResolvedQualifier) {
return convertToGetObject(it, callableReferenceMode = this is FirCallableReferenceAccess)
}
visitor.convertToIrExpression(it)
}
?: explicitReceiverExpression
?: run {
if (this is FirCallableReferenceAccess) return null
val name = if (isDispatch) "Dispatch" else "Extension"
@@ -376,32 +389,32 @@ internal class CallAndReferenceGenerator(
}
}
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess): IrExpression {
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess, explicitReceiverExpression: IrExpression?): IrExpression {
return when (this) {
is IrCallWithIndexedArgumentsBase -> {
val ownerFunction = symbol.owner as? IrFunction
if (ownerFunction?.dispatchReceiverParameter != null) {
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver()
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
}
if (ownerFunction?.extensionReceiverParameter != null) {
extensionReceiver = qualifiedAccess.findIrExtensionReceiver()
extensionReceiver = qualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression)
}
this
}
is IrNoArgumentsCallableReferenceBase -> {
val ownerPropertyGetter = (symbol.owner as? IrProperty)?.getter
if (ownerPropertyGetter?.dispatchReceiverParameter != null) {
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver()
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
}
if (ownerPropertyGetter?.extensionReceiverParameter != null) {
extensionReceiver = qualifiedAccess.findIrExtensionReceiver()
extensionReceiver = qualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression)
}
this
}
is IrFieldExpressionBase -> {
val ownerField = symbol.owner
if (!ownerField.isStatic) {
receiver = qualifiedAccess.findIrDispatchReceiver()
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
}
this
}
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun Array<String>.test1(): Array<String> {
val func = { i:Int -> this}
return func(1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class C {
private fun String.ext() : String = ""
private fun f() {}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class C{
private var v : Int = 0
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface Callback {
fun invoke(): String
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// KOTLIN_CONFIGURATION_FLAGS: CONSTRUCTOR_CALL_NORMALIZATION_MODE=enable
@@ -1,5 +1,4 @@
// !LANGUAGE: +NormalizeConstructorCalls
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
open class A(val s: String)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
//WITH_REFLECT
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
inline class R(private val r: Int) {
fun test() = object {
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
inline class R(private val r: Int) {
fun test() =
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
val d = 42.0
val c = 'C'
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String {
return (object { val r = "OK" } ?: null)!!.r
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !JVM_DEFAULT_MODE: all-compatibility
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !JVM_DEFAULT_MODE: compatibility
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A {
var a: String = "Fail"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A(
val a: String = object {
override fun toString(): String = "OK"
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS, NATIVE
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS, NATIVE
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A {
fun foo() = "OK"
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
package test
private val prop = "O"