JVM_IR: avoid scope violation in BridgeLowering
This commit is contained in:
@@ -347,4 +347,32 @@ val IrDeclaration.isStaticInlineClassReplacement: Boolean
|
||||
|
||||
fun IrDeclaration.isFromJava(): Boolean =
|
||||
origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB ||
|
||||
parent is IrDeclaration && (parent as IrDeclaration).isFromJava()
|
||||
parent is IrDeclaration && (parent as IrDeclaration).isFromJava()
|
||||
|
||||
val IrType.upperBound: IrType
|
||||
get() = erasedUpperBound.symbol.starProjectedType
|
||||
|
||||
fun IrType.eraseToScope(scopeOwner: IrTypeParametersContainer): IrType = eraseToScope(collectVisibleTypeParameters(scopeOwner))
|
||||
|
||||
fun IrType.eraseToScope(visibleTypeParameters: Set<IrTypeParameter>): IrType {
|
||||
require(this is IrSimpleType) { error("Unexpected IrType kind: ${render()}") }
|
||||
return when (classifier) {
|
||||
is IrClassSymbol -> IrSimpleTypeImpl(classifier, hasQuestionMark, arguments.map { it.eraseToScope(visibleTypeParameters) }, annotations)
|
||||
is IrTypeParameterSymbol -> if (classifier.owner in visibleTypeParameters) this else upperBound
|
||||
else -> error("unknown IrType classifier kind: ${classifier.owner.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrTypeArgument.eraseToScope(visibleTypeParameters: Set<IrTypeParameter>): IrTypeArgument = when (this) {
|
||||
is IrStarProjection -> this
|
||||
is IrTypeProjection -> makeTypeProjection(type.eraseToScope(visibleTypeParameters), variance)
|
||||
else -> error("unknown type projection kind: ${render()}")
|
||||
}
|
||||
|
||||
fun collectVisibleTypeParameters(scopeOwner: IrTypeParametersContainer): Set<IrTypeParameter> =
|
||||
generateSequence(scopeOwner) { current ->
|
||||
val parent = current.parent as? IrTypeParametersContainer
|
||||
parent.takeUnless { parent is IrClass && current is IrClass && !current.isInner && !current.isLocal }
|
||||
}
|
||||
.flatMap { it.typeParameters }
|
||||
.toSet()
|
||||
|
||||
+19
-17
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.copyCorrespondingPropertyFrom
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isFromJava
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isJvmAbstract
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.*
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
@@ -459,7 +456,8 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
modality = if (specialBridge.isFinal) Modality.FINAL else Modality.OPEN
|
||||
origin = if (specialBridge.isSynthetic) IrDeclarationOrigin.BRIDGE else IrDeclarationOrigin.BRIDGE_SPECIAL
|
||||
name = Name.identifier(specialBridge.signature.name)
|
||||
returnType = specialBridge.substitutedReturnType ?: specialBridge.overridden.returnType.eraseTypeParameters()
|
||||
returnType = specialBridge.substitutedReturnType?.eraseToScope(target.parentAsClass)
|
||||
?: specialBridge.overridden.returnType.eraseTypeParameters()
|
||||
}.apply {
|
||||
context.functionsWithSpecialBridges.add(target)
|
||||
|
||||
@@ -548,26 +546,30 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
from: IrSimpleFunction,
|
||||
substitutedParameterTypes: List<IrType>? = null
|
||||
) {
|
||||
val visibleTypeParameters = collectVisibleTypeParameters(this)
|
||||
// This is a workaround for a bug affecting fake overrides. Sometimes we encounter fake overrides
|
||||
// with dispatch receivers pointing at a superclass instead of the current class.
|
||||
dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this, type = irClass.defaultType)
|
||||
extensionReceiverParameter = from.extensionReceiverParameter?.copyWithTypeErasure(this)
|
||||
extensionReceiverParameter = from.extensionReceiverParameter?.copyWithTypeErasure(this, visibleTypeParameters)
|
||||
valueParameters = if (substitutedParameterTypes != null) {
|
||||
from.valueParameters.zip(substitutedParameterTypes).map { (param, type) ->
|
||||
param.copyWithTypeErasure(this, type)
|
||||
param.copyWithTypeErasure(this, visibleTypeParameters, type)
|
||||
}
|
||||
} else {
|
||||
from.valueParameters.map { it.copyWithTypeErasure(this) }
|
||||
from.valueParameters.map { it.copyWithTypeErasure(this, visibleTypeParameters) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrValueParameter.copyWithTypeErasure(target: IrSimpleFunction, substitutedType: IrType? = null): IrValueParameter =
|
||||
copyTo(
|
||||
target, IrDeclarationOrigin.BRIDGE,
|
||||
type = (substitutedType ?: type.eraseTypeParameters()),
|
||||
// Currently there are no special bridge methods with vararg parameters, so we don't track substituted vararg element types.
|
||||
varargElementType = varargElementType?.eraseTypeParameters()
|
||||
)
|
||||
private fun IrValueParameter.copyWithTypeErasure(
|
||||
target: IrSimpleFunction,
|
||||
visibleTypeParameters: Set<IrTypeParameter>,
|
||||
substitutedType: IrType? = null
|
||||
): IrValueParameter = copyTo(
|
||||
target, IrDeclarationOrigin.BRIDGE,
|
||||
type = (substitutedType?.eraseToScope(visibleTypeParameters) ?: type.eraseTypeParameters()),
|
||||
// Currently there are no special bridge methods with vararg parameters, so we don't track substituted vararg element types.
|
||||
varargElementType = varargElementType?.eraseToScope(visibleTypeParameters)
|
||||
)
|
||||
|
||||
private fun IrBuilderWithScope.delegatingCall(
|
||||
bridge: IrSimpleFunction,
|
||||
@@ -576,10 +578,10 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
|
||||
) = irCastIfNeeded(irCall(target, origin = IrStatementOrigin.BRIDGE_DELEGATION, superQualifierSymbol = superQualifierSymbol).apply {
|
||||
for ((param, targetParam) in bridge.explicitParameters.zip(target.explicitParameters)) {
|
||||
putArgument(targetParam, irGet(param).let { argument ->
|
||||
if (param == bridge.dispatchReceiverParameter) argument else irCastIfNeeded(argument, targetParam.type)
|
||||
if (param == bridge.dispatchReceiverParameter) argument else irCastIfNeeded(argument, targetParam.type.upperBound)
|
||||
})
|
||||
}
|
||||
}, bridge.returnType)
|
||||
}, bridge.returnType.upperBound)
|
||||
|
||||
private fun IrBuilderWithScope.irCastIfNeeded(expression: IrExpression, to: IrType): IrExpression =
|
||||
if (expression.type == to || to.isAny() || to.isNullableAny()) expression else irImplicitCast(expression, to)
|
||||
|
||||
Reference in New Issue
Block a user