From 06c02e5e8d860c50c34b09fee0c672a0c70d064f Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Wed, 8 Nov 2017 14:11:23 +0300 Subject: [PATCH] backend: Allow fake nullables in FOR loops --- .../backend/konan/lower/ForLoopsLowering.kt | 42 +++-- .../backend/konan/lower/FunctionInlining.kt | 4 +- backend.native/tests/build.gradle | 7 + .../for_loops_let_with_nullable.kt | 151 ++++++++++++++++++ 4 files changed, 190 insertions(+), 14 deletions(-) create mode 100644 backend.native/tests/codegen/controlflow/for_loops_let_with_nullable.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ForLoopsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ForLoopsLowering.kt index da23922b63b..982f34cd219 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ForLoopsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ForLoopsLowering.kt @@ -42,6 +42,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections import org.jetbrains.kotlin.util.OperatorNameConventions @@ -73,14 +74,18 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo private val scopeOwnerSymbol get() = currentScope!!.scope.scopeOwnerSymbol - private val progressionElementClasses: Set = mutableSetOf(symbols.char).apply { + private val progressionElementClasses: List = mutableListOf(symbols.char).apply { addAll(symbols.integerClasses) } - private val progressionElementClassesTypes: Set = mutableSetOf().apply { + private val progressionElementClassesTypes: List = mutableListOf().apply { progressionElementClasses.mapTo(this) { it.descriptor.defaultType } } + private val progressionElementClassesNullableTypes: List = mutableListOf().apply { + progressionElementClassesTypes.mapTo(this) { it.makeNullableAsSpecified(true) } + } + //region Symbols for progression building functions ================================================================ private fun getProgressionBuildingMethods(name: String): Set = getMethodsForProgressionElements(name) { @@ -128,13 +133,22 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo //endregion //region Util methods ============================================================================================== - private fun IrExpression.castIfNecessary(progressionType: ProgressionType, castToChar: Boolean = true): IrExpression { - assert(type in progressionElementClassesTypes) - if (type == progressionType.elementType || (!castToChar && KotlinBuiltIns.isChar(progressionType.elementType))) { - return this + private fun IrExpression.castIfNecessary(progressionType: ProgressionType): IrExpression { + assert(type in progressionElementClassesTypes || type in progressionElementClassesNullableTypes) + return if (type == progressionType.elementType) { + this + } else { + IrCallImpl(startOffset, endOffset, symbols.getFunction(progressionType.numberCastFunctionName, type)) + .apply { dispatchReceiver = this@castIfNecessary } + } + } + + private fun DeclarationIrBuilder.ensureNotNullable(expression: IrExpression): IrExpression { + return if (expression.type.isMarkedNullable) { + irImplicitCast(expression, expression.type.makeNotNullable()) + } else { + expression } - return IrCallImpl(startOffset, endOffset, symbols.getFunction(progressionType.numberCastFunctionName, type)) - .apply { dispatchReceiver = this@castIfNecessary } } private fun IrExpression.unaryMinus(): IrExpression = @@ -163,8 +177,10 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo // Used only by the assert. private fun stepHasRightType(step: IrExpression, progressionType: ProgressionType) = - ((progressionType.isCharProgression() || progressionType.isIntProgression()) && KotlinBuiltIns.isInt(step.type)) || - (progressionType.isLongProgression() && KotlinBuiltIns.isLong(step.type)) + ((progressionType.isCharProgression() || progressionType.isIntProgression()) && + KotlinBuiltIns.isInt(step.type.makeNotNullable())) || + (progressionType.isLongProgression() && + KotlinBuiltIns.isLong(step.type.makeNotNullable())) private fun irCheckProgressionStep(progressionType: ProgressionType, step: IrExpression): Pair { @@ -177,7 +193,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo // so there is no need to cast it. assert(stepHasRightType(step, progressionType)) - val symbol = symbols.checkProgressionStep[step.type] + val symbol = symbols.checkProgressionStep[step.type.makeNotNullable()] ?: throw IllegalArgumentException("Unknown progression element type: ${step.type}") return IrCallImpl(step.startOffset, step.endOffset, symbol).apply { putValueArgument(0, step) @@ -307,6 +323,8 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo with(builder) { with(progressionInfo) { + // Due to features of PSI2IR we can obtain nullable arguments here while actually + // they are non-nullable (the frontend takes care about this). So we need to cast them to non-nullable. val statements = mutableListOf() /** @@ -329,7 +347,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo val stepExpression = (if (increasing) step else step?.unaryMinus()) ?: defaultStep(startOffset, endOffset) - val stepValue = scope.createTemporaryVariable(stepExpression, + val stepValue = scope.createTemporaryVariable(ensureNotNullable(stepExpression), nameHint = "step", origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE).also { statements.add(it) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index 8eadbc0af9a..1d2eb0870c7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -234,8 +234,8 @@ private class Inliner(val globalSubstituteMap: MutableMap