This commit is contained in:
Igor Chevdar
2021-07-30 20:32:56 +05:00
parent da4113af88
commit 2c068b8c5a
2 changed files with 86 additions and 0 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMo
import org.jetbrains.kotlin.backend.konan.MemoryModel
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
@@ -149,6 +150,26 @@ internal val copyDefaultValuesToActualPhase = konanUnitPhase(
description = "Copy default values from expect to actual declarations"
)
/*
* Sometimes psi2ir produces IR with non-trivial variance in super types of SAM conversions (this is a language design issue).
* Earlier this was solved with just erasing all such variances but this might lead to some other hard to debug problems,
* so after handling the majority of corner cases correctly in psi2ir it is safe to assume that such cases don't get here and
* even if they do, then it's better to throw an error right away than to dig out weird crashes down the pipeline or even at runtime.
* We explicitly check this, also fixing older klibs built with previous compiler versions by applying the same trick as before.
*/
internal val checkSamSuperTypesPhase = konanUnitPhase(
op = {
irModule!!.files
.forEach { SamSuperTypesChecker(this, it, mode = SamSuperTypesChecker.Mode.THROW).run() }
// TODO: This is temporary for handling klibs produced with earlier compiler versions.
irModules.values
.flatMap { it.files }
.forEach { SamSuperTypesChecker(this, it, mode = SamSuperTypesChecker.Mode.ERASE).run() }
},
name = "CheckSamSuperTypes",
description = "Check SAM conversions super types"
)
internal val serializerPhase = konanUnitPhase(
op = {
val expectActualLinker = config.configuration.get(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER) ?: false
@@ -424,6 +445,7 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
psiToIrPhase then
destroySymbolTablePhase then
copyDefaultValuesToActualPhase then
checkSamSuperTypesPhase then
serializerPhase then
specialBackendChecksPhase then
namedUnitPhase(
@@ -484,5 +506,6 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
disableIf(destroySymbolTablePhase, isDescriptorsOnlyLibrary)
disableIf(copyDefaultValuesToActualPhase, isDescriptorsOnlyLibrary)
disableIf(specialBackendChecksPhase, isDescriptorsOnlyLibrary)
disableIf(checkSamSuperTypesPhase, isDescriptorsOnlyLibrary)
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.Variance
internal class SamSuperTypesChecker(private val context: Context,
private val irFile: IrFile,
private val mode: Mode) {
enum class Mode {
ERASE,
THROW
}
private fun IrType.eraseProjections(owner: IrElement): IrType {
if (this !is IrSimpleType) return this
return buildSimpleType {
this.classifier = this@eraseProjections.classifier
this.hasQuestionMark = this@eraseProjections.hasQuestionMark
this.annotations = this@eraseProjections.annotations
this.arguments = this@eraseProjections.arguments.mapIndexed { index, argument ->
if (argument !is IrTypeProjection)
argument
else {
if (mode == Mode.THROW && argument.variance != Variance.INVARIANT) {
context.reportCompilationError(
"Unexpected variance in super type argument: ${argument.variance} @$index", irFile, owner)
}
makeTypeProjection(argument.type.eraseProjections(owner), Variance.INVARIANT)
}
}
}
}
fun run() {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
expression.transformChildrenVoid(this)
if (expression.operator == IrTypeOperator.SAM_CONVERSION)
expression.typeOperand = expression.typeOperand.eraseProjections(expression)
return expression
}
})
}
}