Fix type safe barrier bridges for generics with non-trivial upper bound
This commit is contained in:
committed by
Stanislav Erokhin
parent
8c5bb6420a
commit
77fcc0d010
+1
-1
@@ -1459,7 +1459,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
} else {
|
} else {
|
||||||
// E.g. when generating type operation with reified type parameter in the original body of inline function.
|
// E.g. when generating type operation with reified type parameter in the original body of inline function.
|
||||||
kTrue
|
kTrue
|
||||||
// TODO: this code should be unreachable, however [BridgesBuilding] generates IR with such type checks.
|
// TODO: this code should be unreachable, recheck.
|
||||||
}
|
}
|
||||||
functionGenerationContext.br(bbExit)
|
functionGenerationContext.br(bbExit)
|
||||||
val bbInstanceOfResult = functionGenerationContext.currentBlock
|
val bbInstanceOfResult = functionGenerationContext.currentBlock
|
||||||
|
|||||||
+6
-1
@@ -207,7 +207,12 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
|
|||||||
for (i in valueParameters.indices) {
|
for (i in valueParameters.indices) {
|
||||||
if (!typeSafeBarrierDescription.checkParameter(i))
|
if (!typeSafeBarrierDescription.checkParameter(i))
|
||||||
continue
|
continue
|
||||||
val type = originalValueParameters[i].type
|
|
||||||
|
val type = originalValueParameters[i].type.erasureForTypeOperation()
|
||||||
|
// Note: erasing to single type is not entirely correct if type parameter has multiple upper bounds.
|
||||||
|
// In this case the compiler could generate multiple type checks, one for each upper bound.
|
||||||
|
// But let's keep it simple here for now; JVM backend doesn't do this anyway.
|
||||||
|
|
||||||
if (!type.isNullableAny()) {
|
if (!type.isNullableAny()) {
|
||||||
+returnIfBadType(irGet(valueParameters[i]), type,
|
+returnIfBadType(irGet(valueParameters[i]), type,
|
||||||
if (typeSafeBarrierDescription == SpecialGenericSignatures.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
|
if (typeSafeBarrierDescription == SpecialGenericSignatures.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
|
||||||
|
|||||||
+22
-19
@@ -25,30 +25,33 @@ import org.jetbrains.kotlin.ir.util.irCall
|
|||||||
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
|
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
internal fun IrType.erasureForTypeOperation(): IrType {
|
||||||
|
if (this !is IrSimpleType) return this
|
||||||
|
|
||||||
|
return when (val classifier = classifier) {
|
||||||
|
is IrClassSymbol -> this
|
||||||
|
is IrTypeParameterSymbol -> {
|
||||||
|
val upperBound = classifier.owner.superTypes.firstOrNull()
|
||||||
|
?: TODO("${classifier.descriptor} : ${classifier.descriptor.upperBounds}")
|
||||||
|
|
||||||
|
if (this.hasQuestionMark) {
|
||||||
|
// `T?`
|
||||||
|
upperBound.erasureForTypeOperation().makeNullable()
|
||||||
|
} else {
|
||||||
|
upperBound.erasureForTypeOperation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> TODO(classifier.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLoweringPass, IrBuildingTransformer(context) {
|
internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLoweringPass, IrBuildingTransformer(context) {
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildren(this, null)
|
irFile.transformChildren(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrType.erasure(): IrType {
|
private fun IrType.erasure(): IrType = this.erasureForTypeOperation()
|
||||||
if (this !is IrSimpleType) return this
|
|
||||||
|
|
||||||
return when (val classifier = classifier) {
|
|
||||||
is IrClassSymbol -> this
|
|
||||||
is IrTypeParameterSymbol -> {
|
|
||||||
val upperBound = classifier.owner.superTypes.firstOrNull() ?:
|
|
||||||
TODO("${classifier.descriptor} : ${classifier.descriptor.upperBounds}")
|
|
||||||
|
|
||||||
if (this.hasQuestionMark) {
|
|
||||||
// `T?`
|
|
||||||
upperBound.erasure().makeNullable()
|
|
||||||
} else {
|
|
||||||
upperBound.erasure()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> TODO(classifier.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun lowerCast(expression: IrTypeOperatorCall): IrExpression {
|
private fun lowerCast(expression: IrTypeOperatorCall): IrExpression {
|
||||||
builder.at(expression)
|
builder.at(expression)
|
||||||
|
|||||||
@@ -1540,6 +1540,10 @@ task bridges_special(type: KonanLocalTest) {
|
|||||||
source = "codegen/bridges/special.kt"
|
source = "codegen/bridges/special.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task bridges_specialGeneric(type: KonanLocalTest) {
|
||||||
|
source = "codegen/bridges/specialGeneric.kt"
|
||||||
|
}
|
||||||
|
|
||||||
task bridges_nativePointed(type: KonanLocalTest) {
|
task bridges_nativePointed(type: KonanLocalTest) {
|
||||||
source = "codegen/bridges/nativePointed.kt"
|
source = "codegen/bridges/nativePointed.kt"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codegen.bridges.specialGeneric
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
interface Element {
|
||||||
|
val isContained: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
object ContainedElement : Element {
|
||||||
|
override val isContained: Boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
object NotContainedElement : Element {
|
||||||
|
override val isContained: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MySet<E : Element> : Set<E> {
|
||||||
|
override fun contains(element: E): Boolean = element.isContained
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean = TODO()
|
||||||
|
override fun hashCode(): Int = TODO()
|
||||||
|
override fun toString(): String = TODO()
|
||||||
|
|
||||||
|
override val size: Int get() = TODO()
|
||||||
|
override fun isEmpty(): Boolean = TODO()
|
||||||
|
override fun containsAll(elements: Collection<E>): Boolean = TODO()
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<E> = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(): Set<Any> = MySet<Element>()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMySet() {
|
||||||
|
val set = set()
|
||||||
|
assertFalse(set.contains(Any()))
|
||||||
|
assertFalse(set.contains(NotContainedElement))
|
||||||
|
assertTrue(set.contains(ContainedElement))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user