[FIR2IR] Function reference type approximation hack KT-49526
This commit is contained in:
committed by
TeamCityServer
parent
070e860669
commit
ed836f28f4
+39
-4
@@ -7,21 +7,19 @@ package org.jetbrains.kotlin.fir.backend.generators
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
||||||
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.backend.*
|
import org.jetbrains.kotlin.fir.backend.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||||
import org.jetbrains.kotlin.fir.dispatchReceiverClassOrNull
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
|
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirDelegateFieldReference
|
import org.jetbrains.kotlin.fir.references.FirDelegateFieldReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirReference
|
import org.jetbrains.kotlin.fir.references.FirReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
|
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
|
||||||
import org.jetbrains.kotlin.fir.render
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
|
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
@@ -30,6 +28,7 @@ import org.jetbrains.kotlin.fir.resolve.toSymbol
|
|||||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
|
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -43,6 +42,7 @@ import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
|
|||||||
import org.jetbrains.kotlin.ir.util.isInterface
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.isUnchanging
|
import org.jetbrains.kotlin.psi2ir.generators.isUnchanging
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
|
||||||
class CallAndReferenceGenerator(
|
class CallAndReferenceGenerator(
|
||||||
@@ -63,7 +63,8 @@ class CallAndReferenceGenerator(
|
|||||||
callableReferenceAccess: FirCallableReferenceAccess,
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
explicitReceiverExpression: IrExpression?
|
explicitReceiverExpression: IrExpression?
|
||||||
): IrExpression {
|
): IrExpression {
|
||||||
val type = callableReferenceAccess.typeRef.toIrType()
|
val type = approximateFunctionReferenceType(callableReferenceAccess.typeRef.coneType).toIrType()
|
||||||
|
|
||||||
val callableSymbol = callableReferenceAccess.calleeReference.toResolvedCallableSymbol()
|
val callableSymbol = callableReferenceAccess.calleeReference.toResolvedCallableSymbol()
|
||||||
if (callableSymbol?.origin == FirDeclarationOrigin.SamConstructor) {
|
if (callableSymbol?.origin == FirDeclarationOrigin.SamConstructor) {
|
||||||
assert(explicitReceiverExpression == null) {
|
assert(explicitReceiverExpression == null) {
|
||||||
@@ -171,6 +172,40 @@ class CallAndReferenceGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun approximateFunctionReferenceType(kotlinType: ConeKotlinType): ConeKotlinType {
|
||||||
|
// This is a hack to support intersection types in function references on JVM.
|
||||||
|
// Function reference type KFunctionN<T1, ..., TN, R> might contain intersection types in its top-level arguments.
|
||||||
|
// Intersection types in expressions and local variable declarations usually don't bother us.
|
||||||
|
// However, in case of function references type mapping affects behavior:
|
||||||
|
// resulting function reference class will have a bridge method, which will downcast its arguments to the expected types.
|
||||||
|
// This would cause ClassCastException in case of usual type approximation,
|
||||||
|
// because '{ X1 & ... & Xm }' would be approximated to 'Nothing'.
|
||||||
|
// JVM_OLD just relies on type mapping for generic argument types in such case.
|
||||||
|
if (!kotlinType.isKFunctionType(session))
|
||||||
|
return kotlinType
|
||||||
|
if (kotlinType !is ConeSimpleKotlinType)
|
||||||
|
return kotlinType
|
||||||
|
if (kotlinType.typeArguments.none { it.type is ConeIntersectionType })
|
||||||
|
return kotlinType
|
||||||
|
val functionParameterTypes = kotlinType.typeArguments.take(kotlinType.typeArguments.size - 1)
|
||||||
|
val functionReturnType = kotlinType.typeArguments.last()
|
||||||
|
return ConeClassLikeTypeImpl(
|
||||||
|
(kotlinType as ConeClassLikeType).lookupTag,
|
||||||
|
(functionParameterTypes.map { approximateFunctionReferenceParameterType(it) } + functionReturnType).toTypedArray(),
|
||||||
|
kotlinType.isNullable,
|
||||||
|
kotlinType.attributes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun approximateFunctionReferenceParameterType(typeProjection: ConeTypeProjection): ConeTypeProjection {
|
||||||
|
if (typeProjection.isStarProjection) return typeProjection
|
||||||
|
val intersectionType = typeProjection as? ConeIntersectionType ?: return typeProjection
|
||||||
|
val newType = intersectionType.alternativeType
|
||||||
|
?: session.typeContext.commonSuperType(intersectionType.intersectedTypes.toList()) as? ConeKotlinType
|
||||||
|
?: return typeProjection
|
||||||
|
return newType.toTypeProjection(typeProjection.kind)
|
||||||
|
}
|
||||||
|
|
||||||
private fun computeFieldSymbolForCallableReference(
|
private fun computeFieldSymbolForCallableReference(
|
||||||
callableReferenceAccess: FirCallableReferenceAccess,
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
symbol: IrFieldSymbol
|
symbol: IrFieldSymbol
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// FIR_STATUS: callable reference type approximation hack not implemented
|
|
||||||
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// CHECK_BYTECODE_LISTING
|
// CHECK_BYTECODE_LISTING
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// IGNORE_BACKEND: NATIVE
|
// IGNORE_BACKEND: NATIVE
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// FIR_STATUS: callable reference type approximation hack not implemented
|
|
||||||
|
|
||||||
fun <T> id(x: T): T = x
|
fun <T> id(x: T): T = x
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// IGNORE_BACKEND: NATIVE
|
// IGNORE_BACKEND: NATIVE
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// FIR_STATUS: callable reference type approximation hack not implemented
|
|
||||||
|
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ FILE fqName:<root> fileName:/kt49526.kt
|
|||||||
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Boolean
|
FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Boolean
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
VAR name:ref type:kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> [val]
|
VAR name:ref type:kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> [val]
|
||||||
FUNCTION_REFERENCE 'public abstract fun contains (element: E of kotlin.collections.List): kotlin.Boolean [operator] declared in kotlin.collections.List' type=kotlin.reflect.KFunction1<kotlin.Nothing, kotlin.Boolean> origin=null reflectionTarget=<same>
|
FUNCTION_REFERENCE 'public abstract fun contains (element: E of kotlin.collections.List): kotlin.Boolean [operator] declared in kotlin.collections.List' type=kotlin.reflect.KFunction1<kotlin.Any, kotlin.Boolean> origin=null reflectionTarget=<same>
|
||||||
$this: CALL 'public final fun plus <T> (element: T of kotlin.collections.CollectionsKt.plus): kotlin.collections.List<T of kotlin.collections.CollectionsKt.plus> [operator] declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Any> origin=PLUS
|
$this: CALL 'public final fun plus <T> (element: T of kotlin.collections.CollectionsKt.plus): kotlin.collections.List<T of kotlin.collections.CollectionsKt.plus> [operator] declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Any> origin=PLUS
|
||||||
<T>: kotlin.Comparable<kotlin.Nothing>
|
<T>: kotlin.Comparable<kotlin.Nothing>
|
||||||
$receiver: CALL 'public final fun listOf <T> (element: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List<T of kotlin.collections.CollectionsKt.listOf> declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Char> origin=null
|
$receiver: CALL 'public final fun listOf <T> (element: T of kotlin.collections.CollectionsKt.listOf): kotlin.collections.List<T of kotlin.collections.CollectionsKt.listOf> declared in kotlin.collections.CollectionsKt' type=kotlin.collections.List<kotlin.Char> origin=null
|
||||||
|
|||||||
Reference in New Issue
Block a user