JVM_IR: avoid scope violation in BridgeLowering

This commit is contained in:
Georgy Bronnikov
2020-08-10 22:03:36 +03:00
parent e10d8e51b6
commit 9929047f5d
2 changed files with 48 additions and 18 deletions
@@ -347,4 +347,32 @@ val IrDeclaration.isStaticInlineClassReplacement: Boolean
fun IrDeclaration.isFromJava(): Boolean = fun IrDeclaration.isFromJava(): Boolean =
origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB || 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()
@@ -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.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.ir.copyCorrespondingPropertyFrom import org.jetbrains.kotlin.backend.jvm.ir.*
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.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil 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 modality = if (specialBridge.isFinal) Modality.FINAL else Modality.OPEN
origin = if (specialBridge.isSynthetic) IrDeclarationOrigin.BRIDGE else IrDeclarationOrigin.BRIDGE_SPECIAL origin = if (specialBridge.isSynthetic) IrDeclarationOrigin.BRIDGE else IrDeclarationOrigin.BRIDGE_SPECIAL
name = Name.identifier(specialBridge.signature.name) name = Name.identifier(specialBridge.signature.name)
returnType = specialBridge.substitutedReturnType ?: specialBridge.overridden.returnType.eraseTypeParameters() returnType = specialBridge.substitutedReturnType?.eraseToScope(target.parentAsClass)
?: specialBridge.overridden.returnType.eraseTypeParameters()
}.apply { }.apply {
context.functionsWithSpecialBridges.add(target) context.functionsWithSpecialBridges.add(target)
@@ -548,26 +546,30 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
from: IrSimpleFunction, from: IrSimpleFunction,
substitutedParameterTypes: List<IrType>? = null substitutedParameterTypes: List<IrType>? = null
) { ) {
val visibleTypeParameters = collectVisibleTypeParameters(this)
// This is a workaround for a bug affecting fake overrides. Sometimes we encounter fake overrides // 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. // with dispatch receivers pointing at a superclass instead of the current class.
dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this, type = irClass.defaultType) dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this, type = irClass.defaultType)
extensionReceiverParameter = from.extensionReceiverParameter?.copyWithTypeErasure(this) extensionReceiverParameter = from.extensionReceiverParameter?.copyWithTypeErasure(this, visibleTypeParameters)
valueParameters = if (substitutedParameterTypes != null) { valueParameters = if (substitutedParameterTypes != null) {
from.valueParameters.zip(substitutedParameterTypes).map { (param, type) -> from.valueParameters.zip(substitutedParameterTypes).map { (param, type) ->
param.copyWithTypeErasure(this, type) param.copyWithTypeErasure(this, visibleTypeParameters, type)
} }
} else { } else {
from.valueParameters.map { it.copyWithTypeErasure(this) } from.valueParameters.map { it.copyWithTypeErasure(this, visibleTypeParameters) }
} }
} }
private fun IrValueParameter.copyWithTypeErasure(target: IrSimpleFunction, substitutedType: IrType? = null): IrValueParameter = private fun IrValueParameter.copyWithTypeErasure(
copyTo( target: IrSimpleFunction,
target, IrDeclarationOrigin.BRIDGE, visibleTypeParameters: Set<IrTypeParameter>,
type = (substitutedType ?: type.eraseTypeParameters()), substitutedType: IrType? = null
// Currently there are no special bridge methods with vararg parameters, so we don't track substituted vararg element types. ): IrValueParameter = copyTo(
varargElementType = varargElementType?.eraseTypeParameters() 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( private fun IrBuilderWithScope.delegatingCall(
bridge: IrSimpleFunction, bridge: IrSimpleFunction,
@@ -576,10 +578,10 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
) = irCastIfNeeded(irCall(target, origin = IrStatementOrigin.BRIDGE_DELEGATION, superQualifierSymbol = superQualifierSymbol).apply { ) = irCastIfNeeded(irCall(target, origin = IrStatementOrigin.BRIDGE_DELEGATION, superQualifierSymbol = superQualifierSymbol).apply {
for ((param, targetParam) in bridge.explicitParameters.zip(target.explicitParameters)) { for ((param, targetParam) in bridge.explicitParameters.zip(target.explicitParameters)) {
putArgument(targetParam, irGet(param).let { argument -> 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 = private fun IrBuilderWithScope.irCastIfNeeded(expression: IrExpression, to: IrType): IrExpression =
if (expression.type == to || to.isAny() || to.isNullableAny()) expression else irImplicitCast(expression, to) if (expression.type == to || to.isAny() || to.isNullableAny()) expression else irImplicitCast(expression, to)