diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt index 97daeba85eb..a0d305966d6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt @@ -62,6 +62,12 @@ fun IrBuilderWithScope.irIfThenElse(type: KotlinType, condition: IrExpression, t fun IrBuilderWithScope.irIfNull(type: KotlinType, subject: IrExpression, thenPart: IrExpression, elsePart: IrExpression) = irIfThenElse(type, irEqualsNull(subject), thenPart, elsePart) +fun IrBuilderWithScope.irThrowNpe(operator: IrOperator) = + IrNullaryPrimitiveImpl(startOffset, endOffset, operator, context.irBuiltIns.throwNpe) + +fun IrBlockBuilder.irThrowNpe() = + irThrowNpe(operator ?: IrOperator.EXCLEXCL) + fun IrBuilderWithScope.irIfThenReturnTrue(condition: IrExpression) = IrIfThenElseImpl(startOffset, endOffset, context.builtIns.unitType, condition, irReturnTrue()) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt index e94881eb8ac..52a648ff38f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.psi2ir.builders +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET @@ -109,6 +110,12 @@ fun T.at(startOffset: Int, endOffset: Int): T { return this } +fun T.at(psiElement: PsiElement): T { + this.startOffset = psiElement.startOffset + this.endOffset = psiElement.endOffset + return this +} + inline fun GeneratorWithScope.irBlock(ktElement: KtElement? = null, operator: IrOperator? = null, resultType: KotlinType? = null, body: IrBlockBuilder.() -> Unit ): IrExpression = diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt index 0cbd136338d..878dee59a64 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/OperatorExpressionGenerator.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset -import org.jetbrains.kotlin.psi2ir.intermediate.createTemporaryVariableInBlock +import org.jetbrains.kotlin.psi2ir.builders.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.types.typeUtil.makeNotNullable @@ -109,19 +109,14 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat private fun generateElvis(expression: KtBinaryExpression): IrExpression { val specialCallForElvis = getResolvedCall(expression)!! - val returnType = specialCallForElvis.resultingDescriptor.returnType!! + val resultType = specialCallForElvis.resultingDescriptor.returnType!! val irArgument0 = statementGenerator.generateExpression(expression.left!!) val irArgument1 = statementGenerator.generateExpression(expression.right!!) - val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, returnType, IrOperator.ELVIS) - val irArgument0Value = scope.createTemporaryVariableInBlock(irArgument0, irBlock, "elvis_lhs") - irBlock.addStatement(IrIfThenElseImpl( - expression.startOffset, expression.endOffset, returnType, - context.equalsNull(expression.startOffset, expression.endOffset, irArgument0Value.load()), - irArgument1, - irArgument0Value.load() - )) - return irBlock + return irBlock(expression, IrOperator.ELVIS, resultType) { + val temporary = defineTemporary(irArgument0, "elvis_lhs") + +irIfNull(resultType, irGet(temporary), irArgument1, irGet(temporary)) + } } private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression { @@ -209,29 +204,22 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat return IrUnaryPrimitiveImpl(expression.startOffset, expression.endOffset, irOperator, compareToZeroDescriptor, irCompareToCall) } - - private fun generateBinaryOperatorAsCall(expression: KtBinaryExpression, irOperator: IrOperator?): IrExpression { - val operatorCall = getResolvedCall(expression)!! - return CallGenerator(statementGenerator).generateCall(expression, statementGenerator.pregenerateCall(operatorCall), irOperator) - } - - - private fun generateExclExclOperator(expression: KtPostfixExpression, irOperator: IrOperator): IrExpression { val ktArgument = expression.baseExpression!! val irArgument = statementGenerator.generateExpression(ktArgument) val ktOperator = expression.operationReference val resultType = irArgument.type.makeNotNullable() - val irBlock = IrBlockImpl(ktOperator.startOffset, ktOperator.endOffset, resultType, irOperator) - val argumentValue = scope.createTemporaryVariableInBlock(irArgument, irBlock, "notnull") - val irIfThenElse = IrIfThenElseImpl(ktOperator.startOffset, ktOperator.endOffset, resultType, - context.equalsNull(ktOperator.startOffset, ktOperator.endOffset, argumentValue.load()), - context.throwNpe(ktOperator.startOffset, ktOperator.endOffset, irOperator), - argumentValue.load()) - irBlock.addStatement(irIfThenElse) - return irBlock + return irBlock(ktOperator, irOperator, resultType) { + val temporary = defineTemporary(irArgument, "notnull") + +irIfNull(resultType, irGet(temporary), irThrowNpe(irOperator), irGet(temporary)) + } + } + + private fun generateBinaryOperatorAsCall(expression: KtBinaryExpression, irOperator: IrOperator?): IrExpression { + val operatorCall = getResolvedCall(expression)!! + return CallGenerator(statementGenerator).generateCall(expression, statementGenerator.pregenerateCall(operatorCall), irOperator) } private fun generatePrefixOperatorAsCall(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression {