JVM_IR KT-49765 bridge for throwing stub should just throw UOE

This commit is contained in:
Dmitry Petrov
2021-12-15 19:10:47 +03:00
committed by teamcity
parent 3f22321643
commit 8c71e38c92
17 changed files with 560 additions and 13 deletions
@@ -430,7 +430,17 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
}.apply {
copyAttributes(target)
copyParametersWithErasure(this@addBridge, bridge.overridden)
body = context.createIrBuilder(symbol, startOffset, endOffset).run { irExprBody(delegatingCall(this@apply, target)) }
// If target is a throwing stub, bridge also should just throw UnsupportedOperationException.
// Otherwise, it might throw ClassCastException when downcasting bridge argument to expected type.
// See KT-49765
body = if (target.isThrowingStub()) {
createThrowingStubBody(context, this)
} else {
context.createIrBuilder(symbol, startOffset, endOffset).run {
irExprBody(delegatingCall(this@apply, target))
}
}
if (!bridge.overridden.returnType.isTypeParameterWithPrimitiveUpperBound()) {
// The generated bridge method overrides all of the symbols which were overridden by its overrides.
@@ -446,6 +456,19 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
}
}
private fun IrSimpleFunction.isThrowingStub(): Boolean {
if (this.origin != IrDeclarationOrigin.IR_BUILTINS_STUB &&
this.origin != IrDeclarationOrigin.BRIDGE &&
this.origin != IrDeclarationOrigin.BRIDGE_SPECIAL
) {
return false
}
val body = this.body as? IrBlockBody ?: return false
if (body.statements.size != 1) return false
val irCall = body.statements[0] as? IrCall ?: return false
return irCall.symbol == context.ir.symbols.throwUnsupportedOperationException
}
private fun IrType.isTypeParameterWithPrimitiveUpperBound(): Boolean =
isTypeParameter() && eraseTypeParameters().isPrimitiveType()
@@ -150,7 +150,7 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl
valueParameters = removeAtStub.valueParameters.map { stubParameter ->
stubParameter.copyWithCustomTypeSubstitution(this) { it }
}
body = createThrowingStubBody(this)
body = createThrowingStubBody(context, this)
}
}
@@ -176,7 +176,7 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyWithSubstitution(this, substitutionMap)
extensionReceiverParameter = function.extensionReceiverParameter?.copyWithSubstitution(this, substitutionMap)
valueParameters = function.valueParameters.map { it.copyWithSubstitution(this, substitutionMap) }
body = createThrowingStubBody(this)
body = createThrowingStubBody(context, this)
}
}
@@ -192,17 +192,8 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl
function.returnType
}
private fun createThrowingStubBody(function: IrSimpleFunction) =
context.createIrBuilder(function.symbol).irBlockBody {
// Function body consist only of throwing UnsupportedOperationException statement
+irCall(this@CollectionStubMethodLowering.context.ir.symbols.throwUnsupportedOperationException)
.apply {
putValueArgument(0, irString("Operation is not supported for read-only collection"))
}
}
private fun isEffectivelyOverriddenBy(superFun: IrSimpleFunction, overridingFun: IrSimpleFunction): Boolean {
// Function 'f0' is overridden by function 'f1' if all of the following conditions are met,
// Function 'f0' is overridden by function 'f1' if all the following conditions are met,
// assuming type parameter Ti of 'f1' is "equal" to type parameter Si of 'f0':
// - names are same;
// - 'f1' has the same number of type parameters,
@@ -390,3 +381,13 @@ internal class CollectionStubMethodLowering(val context: JvmBackendContext) : Cl
private val IrClass.superClassChain: Sequence<IrClass>
get() = generateSequence(this) { it.superClass }
}
fun createThrowingStubBody(context: JvmBackendContext, function: IrSimpleFunction) =
context.createIrBuilder(function.symbol).irBlockBody {
// Function body consist only of throwing UnsupportedOperationException statement
+irCall(context.ir.symbols.throwUnsupportedOperationException)
.apply {
putValueArgument(0, irString("Operation is not supported for read-only collection"))
}
}