From 9929047f5d44ac45b6fb9820e42c953a913fb350 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Mon, 10 Aug 2020 22:03:36 +0300 Subject: [PATCH] JVM_IR: avoid scope violation in BridgeLowering --- .../kotlin/backend/jvm/ir/IrUtils.kt | 30 +++++++++++++++- .../backend/jvm/lower/BridgeLowering.kt | 36 ++++++++++--------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index afa12be2cf5..16b0eeaace4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -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() \ No newline at end of file + 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): 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): 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 = + 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() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index 905a3921791..97abfba815c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -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? = 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, + 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)