[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 { } else {
functionCall functionCall
} }
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef) val explicitReceiverExpression = convertToIrReceiverExpression(functionCall.explicitReceiver)
return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef, explicitReceiverExpression)
} }
private fun FirFunctionCall.resolvedNamedFunctionSymbol(): FirNamedFunctionSymbol? { private fun FirFunctionCall.resolvedNamedFunctionSymbol(): FirNamedFunctionSymbol? {
@@ -278,7 +279,8 @@ class Fir2IrVisitor(
} }
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any?): IrElement { 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 { override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: Any?): IrElement {
@@ -333,11 +335,15 @@ class Fir2IrVisitor(
} }
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { 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 { 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 = 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?> { private fun FirBlock.mapToIrStatements(): List<IrStatement?> {
val irRawStatements = statements.map { it.toIrStatement() } val irRawStatements = statements.map { it.toIrStatement() }
val result = mutableListOf<IrStatement?>() val result = mutableListOf<IrStatement?>()
@@ -44,7 +44,10 @@ internal class CallAndReferenceGenerator(
private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() } 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 symbol = callableReferenceAccess.calleeReference.toSymbol(session, classifierStorage, declarationStorage, conversionScope)
val type = callableReferenceAccess.typeRef.toIrType() val type = callableReferenceAccess.typeRef.toIrType()
return callableReferenceAccess.convertWithOffsets { startOffset, endOffset -> 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 val explicitReceiver = qualifiedAccess.explicitReceiver
if (!qualifiedAccess.safe || explicitReceiver == null) { if (!qualifiedAccess.safe || explicitReceiver == null) {
return convertToUnsafeIrCall(qualifiedAccess, typeRef) return convertToUnsafeIrCall(qualifiedAccess, typeRef, explicitReceiverExpression)
} }
return qualifiedAccess.convertWithOffsets { startOffset, endOffset -> return qualifiedAccess.convertWithOffsets { startOffset, endOffset ->
val type = typeRef.toIrType() val type = typeRef.toIrType()
val callableSymbol = (qualifiedAccess.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirCallableSymbol<*> val callableSymbol = (qualifiedAccess.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirCallableSymbol<*>
val typeShouldBeNotNull = callableSymbol?.fir?.returnTypeRef?.coneTypeSafe<ConeKotlinType>()?.isNullable == false 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 { IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.SAFE_CALL).apply {
val receiver = visitor.convertToIrExpression(explicitReceiver) val receiverVariable = declarationStorage.declareTemporaryVariable(explicitReceiverExpression!!).apply {
val receiverVariable = declarationStorage.declareTemporaryVariable(receiver).apply {
parent = conversionScope.parentFromStack() parent = conversionScope.parentFromStack()
} }
statements += receiverVariable statements += receiverVariable
@@ -135,7 +143,7 @@ internal class CallAndReferenceGenerator(
} }
private fun convertToUnsafeIrCall( private fun convertToUnsafeIrCall(
qualifiedAccess: FirQualifiedAccess, typeRef: FirTypeRef, 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 symbol = qualifiedAccess.calleeReference.toSymbol( val symbol = qualifiedAccess.calleeReference.toSymbol(
@@ -181,10 +189,11 @@ internal class CallAndReferenceGenerator(
is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol) is IrEnumEntrySymbol -> IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
else -> generateErrorCallExpression(startOffset, endOffset, qualifiedAccess.calleeReference, type) 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 type = irBuiltIns.unitType
val calleeReference = variableAssignment.calleeReference val calleeReference = variableAssignment.calleeReference
val symbol = calleeReference.toSymbol(session, classifierStorage, declarationStorage, conversionScope, preferGetter = false) 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) is IrVariableSymbol -> IrSetVariableImpl(startOffset, endOffset, type, symbol, assignedValue, origin)
else -> generateErrorCallExpression(startOffset, endOffset, calleeReference) else -> generateErrorCallExpression(startOffset, endOffset, calleeReference)
} }
}.applyTypeArguments(variableAssignment).applyReceivers(variableAssignment) }.applyTypeArguments(variableAssignment).applyReceivers(variableAssignment, explicitReceiverExpression)
} }
fun convertToIrConstructorCall(annotationCall: FirAnnotationCall): IrExpression { fun convertToIrConstructorCall(annotationCall: FirAnnotationCall): IrExpression {
@@ -257,7 +266,7 @@ internal class CallAndReferenceGenerator(
return convertToGetObject(qualifier, callableReferenceMode = false)!! 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 typeRef = qualifier.typeRef as? FirResolvedTypeRef
val classSymbol = (typeRef?.type as? ConeClassLikeType)?.lookupTag?.toSymbol(session) val classSymbol = (typeRef?.type as? ConeClassLikeType)?.lookupTag?.toSymbol(session)
if (callableReferenceMode && classSymbol is FirRegularClassSymbol) { 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 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) { if (firReceiver is FirResolvedQualifier) {
return convertToGetObject(firReceiver, callableReferenceMode = this is FirCallableReferenceAccess) return convertToGetObject(firReceiver, callableReferenceMode = this is FirCallableReferenceAccess)
} }
return firReceiver.takeIf { it !is FirNoReceiverExpression }?.let { visitor.convertToIrExpression(it) } return firReceiver.takeIf { it !is FirNoReceiverExpression }?.let { visitor.convertToIrExpression(it) }
?: explicitReceiver?.let { ?: explicitReceiverExpression
if (it is FirResolvedQualifier) {
return convertToGetObject(it, callableReferenceMode = this is FirCallableReferenceAccess)
}
visitor.convertToIrExpression(it)
}
?: run { ?: run {
if (this is FirCallableReferenceAccess) return null if (this is FirCallableReferenceAccess) return null
val name = if (isDispatch) "Dispatch" else "Extension" 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) { return when (this) {
is IrCallWithIndexedArgumentsBase -> { is IrCallWithIndexedArgumentsBase -> {
val ownerFunction = symbol.owner as? IrFunction val ownerFunction = symbol.owner as? IrFunction
if (ownerFunction?.dispatchReceiverParameter != null) { if (ownerFunction?.dispatchReceiverParameter != null) {
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver() dispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
} }
if (ownerFunction?.extensionReceiverParameter != null) { if (ownerFunction?.extensionReceiverParameter != null) {
extensionReceiver = qualifiedAccess.findIrExtensionReceiver() extensionReceiver = qualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression)
} }
this this
} }
is IrNoArgumentsCallableReferenceBase -> { is IrNoArgumentsCallableReferenceBase -> {
val ownerPropertyGetter = (symbol.owner as? IrProperty)?.getter val ownerPropertyGetter = (symbol.owner as? IrProperty)?.getter
if (ownerPropertyGetter?.dispatchReceiverParameter != null) { if (ownerPropertyGetter?.dispatchReceiverParameter != null) {
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver() dispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
} }
if (ownerPropertyGetter?.extensionReceiverParameter != null) { if (ownerPropertyGetter?.extensionReceiverParameter != null) {
extensionReceiver = qualifiedAccess.findIrExtensionReceiver() extensionReceiver = qualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression)
} }
this this
} }
is IrFieldExpressionBase -> { is IrFieldExpressionBase -> {
val ownerField = symbol.owner val ownerField = symbol.owner
if (!ownerField.isStatic) { if (!ownerField.isStatic) {
receiver = qualifiedAccess.findIrDispatchReceiver() receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
} }
this this
} }
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun Array<String>.test1(): Array<String> { fun Array<String>.test1(): Array<String> {
val func = { i:Int -> this} val func = { i:Int -> this}
return func(1) return func(1)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class C { class C {
private fun String.ext() : String = "" private fun String.ext() : String = ""
private fun f() {} private fun f() {}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class C{ class C{
private var v : Int = 0 private var v : Int = 0
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface Callback { interface Callback {
fun invoke(): String fun invoke(): String
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
// KOTLIN_CONFIGURATION_FLAGS: CONSTRUCTOR_CALL_NORMALIZATION_MODE=enable // KOTLIN_CONFIGURATION_FLAGS: CONSTRUCTOR_CALL_NORMALIZATION_MODE=enable
@@ -1,5 +1,4 @@
// !LANGUAGE: +NormalizeConstructorCalls // !LANGUAGE: +NormalizeConstructorCalls
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_RUNTIME // WITH_RUNTIME
open class A(val s: String) open class A(val s: String)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
//WITH_REFLECT //WITH_REFLECT
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses // !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
inline class R(private val r: Int) { inline class R(private val r: Int) {
fun test() = object { fun test() = object {
@@ -1,5 +1,4 @@
// !LANGUAGE: +InlineClasses // !LANGUAGE: +InlineClasses
// IGNORE_BACKEND_FIR: JVM_IR
inline class R(private val r: Int) { inline class R(private val r: Int) {
fun test() = fun test() =
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
val d = 42.0 val d = 42.0
val c = 'C' val c = 'C'
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun box(): String { fun box(): String {
return (object { val r = "OK" } ?: null)!!.r return (object { val r = "OK" } ?: null)!!.r
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !JVM_DEFAULT_MODE: all-compatibility // !JVM_DEFAULT_MODE: all-compatibility
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// JVM_TARGET: 1.8 // JVM_TARGET: 1.8
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !JVM_DEFAULT_MODE: compatibility // !JVM_DEFAULT_MODE: compatibility
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// JVM_TARGET: 1.8 // JVM_TARGET: 1.8
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// !JVM_DEFAULT_MODE: all // !JVM_DEFAULT_MODE: all
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// JVM_TARGET: 1.8 // JVM_TARGET: 1.8
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A { class A {
var a: String = "Fail" var a: String = "Fail"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
class A( class A(
val a: String = object { val a: String = object {
override fun toString(): String = "OK" override fun toString(): String = "OK"
-1
View File
@@ -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
View File
@@ -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
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
open class A { open class A {
fun foo() = "OK" fun foo() = "OK"
} }
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
package test package test
private val prop = "O" private val prop = "O"