FIR2IR: apply SAM conversion to arguments of functional type.

This commit is contained in:
Jinseong Jeon
2020-05-14 21:56:03 -07:00
committed by Mikhail Glukhikh
parent 599c5dd474
commit 615636ed55
25 changed files with 235 additions and 223 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.backend
import com.intellij.psi.PsiCompiledElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirElement
@@ -41,6 +42,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.isFakeOverride
import org.jetbrains.kotlin.ir.util.properties
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
@@ -472,6 +474,7 @@ fun FirClass<*>.getSamIfAny(): FirSimpleFunction? =
val IrType.isSamType: Boolean
get() {
val irClass = classOrNull ?: return false
if (irClass.owner.kind != ClassKind.INTERFACE) return false
val am = irClass.functions.singleOrNull { it.owner.modality == Modality.ABSTRACT }
return am != null
}
@@ -17,6 +17,8 @@ import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.calls.isExtensionFunctionType
import org.jetbrains.kotlin.fir.resolve.calls.isFunctional
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -27,10 +29,7 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrErrorCallExpression
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
@@ -417,17 +416,24 @@ internal class CallAndReferenceGenerator(
argument: FirExpression,
parameter: FirValueParameter?
): IrExpression {
if (parameter == null ||
parameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true
) return this
if (argument !is FirLambdaArgumentExpression) return this
if (argument.expression !is FirAnonymousFunction) return this
if (argument.expression.typeRef == parameter.returnTypeRef) return this
if (parameter == null || !needSamConversion(argument, parameter)) {
return this
}
val samType = parameter.returnTypeRef.toIrType()
// Make sure the converted IrType owner indeed has a single abstract method, since FunctionReferenceLowering relies on it.
if (!samType.isSamType) return this
return IrTypeOperatorCallImpl(this.startOffset, this.endOffset, samType, IrTypeOperator.SAM_CONVERSION, samType, this)
}
private fun needSamConversion(argument: FirExpression, parameter: FirValueParameter): Boolean {
// If the expected type is a built-in functional type, we don't need SAM conversion.
if (parameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true) {
return false
}
// On the other hand, the actual type should be a functional type.
return argument.isFunctional(session)
}
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
return when (this) {
is IrMemberAccessExpressionBase -> {
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystem
import org.jetbrains.kotlin.types.model.CaptureStatus
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun Candidate.resolveArgumentExpression(
/*
csBuilder: ConstraintSystemBuilder,
@@ -310,11 +309,7 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
val firFunction = symbol.fir as? FirFunction<*> ?: return null
if (!samResolver.shouldRunSamConversionForFunction(firFunction)) return null
val argumentIsFunctional = when ((argument as? FirWrappedArgumentExpression)?.expression ?: argument) {
is FirAnonymousFunction, is FirCallableReferenceAccess -> true
else -> argument.typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true
}
if (!argumentIsFunctional) return null
if (!argument.isFunctional(session)) return null
// TODO: resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
@@ -323,6 +318,12 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
} ?: return null
}
fun FirExpression.isFunctional(session: FirSession): Boolean =
when ((this as? FirWrappedArgumentExpression)?.expression ?: this) {
is FirAnonymousFunction, is FirCallableReferenceAccess -> true
else -> typeRef.coneTypeSafe<ConeKotlinType>()?.isBuiltinFunctionalType(session) == true
}
internal fun FirExpression.getExpectedType(
session: FirSession,
parameter: FirValueParameter/*, languageVersionSettings: LanguageVersionSettings*/
@@ -340,7 +341,6 @@ internal fun FirExpression.getExpectedType(
}
}
fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!")
}