From 57c1b3e0e21525f3922fc6d2eaaaaca3b5260299 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 26 Aug 2016 17:31:02 +0300 Subject: [PATCH] '!!' operator --- .../generators/OperatorExpressionGenerator.kt | 24 ++++++++++++++++ .../kotlin/psi2ir/generators/Primitives.kt | 3 ++ .../ir/irText/expressions/bangbang.kt | 3 ++ .../ir/irText/expressions/bangbang.txt | 28 +++++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 6 ++++ 5 files changed, 64 insertions(+) create mode 100644 compiler/testData/ir/irText/expressions/bangbang.kt create mode 100644 compiler/testData/ir/irText/expressions/bangbang.txt 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 c1c784ca5fd..fca32f724c4 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 @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable import java.lang.AssertionError @@ -60,6 +61,7 @@ class OperatorExpressionGenerator( return when (irOperator) { null -> throw AssertionError("Unexpected postfix operator: $ktOperator") in INCREMENT_DECREMENT_OPERATORS -> generatePostfixIncrementDecrementOperator(expression, irOperator) + IrOperator.EXCLEXCL -> generateExclExclOperator(expression, irOperator) else -> createDummyExpression(expression, ktOperator.toString()) } } @@ -272,6 +274,28 @@ class OperatorExpressionGenerator( } } + 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 = createRematerializableOrTemporary(scope, 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()) + + return if (irBlock.statements.isEmpty()) { + irIfThenElse + } + else { + irBlock.addStatement(irIfThenElse) + irBlock + } + } + private fun generatePrefixOperatorAsCall(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression { val resolvedCall = getResolvedCall(expression)!! return CallGenerator(statementGenerator).generateCall(expression, statementGenerator.pregenerateCall(resolvedCall), irOperator) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt index b59a74f46d7..e2140a387a6 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Primitives.kt @@ -35,6 +35,9 @@ fun GeneratorContext.equalsNull(startOffset: Int, endOffset: Int, argument: IrEx primitiveOp2(startOffset, endOffset, irBuiltIns.eqeq, IrOperator.EQEQ, argument, constNull(startOffset, endOffset)) +fun GeneratorContext.throwNpe(startOffset: Int, endOffset: Int, operator: IrOperator): IrExpression = + IrNullaryPrimitiveImpl(startOffset, endOffset, operator, irBuiltIns.throwNpe) + // a || b == if (a) true else b fun GeneratorContext.oror(startOffset: Int, endOffset: Int, a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.OROR): IrWhen = IrIfThenElseImpl(startOffset, endOffset, builtIns.booleanType, diff --git a/compiler/testData/ir/irText/expressions/bangbang.kt b/compiler/testData/ir/irText/expressions/bangbang.kt new file mode 100644 index 00000000000..36ca3020fa6 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/bangbang.kt @@ -0,0 +1,3 @@ +fun test1(a: Any?) = a!! + +fun test2(a: Any?) = a?.hashCode()!! \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/bangbang.txt b/compiler/testData/ir/irText/expressions/bangbang.txt new file mode 100644 index 00000000000..8b7d77ffbea --- /dev/null +++ b/compiler/testData/ir/irText/expressions/bangbang.txt @@ -0,0 +1,28 @@ +FILE /bangbang.kt + FUN public fun test1(/*0*/ a: kotlin.Any?): kotlin.Any + BLOCK_BODY + RETURN type=kotlin.Nothing from=test1 + WHEN type=kotlin.Any operator=null + if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ + arg0: GET_VAR a type=kotlin.Any? operator=null + arg1: CONST Null type=kotlin.Nothing? value='null' + then: CALL .THROW_NPE type=kotlin.Nothing operator=EXCLEXCL + else: GET_VAR a type=kotlin.Any? operator=null + FUN public fun test2(/*0*/ a: kotlin.Any?): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from=test2 + BLOCK type=kotlin.Int operator=EXCLEXCL + VAR val tmp1_notnull: kotlin.Int? + WHEN type=kotlin.Int? operator=SAFE_CALL + if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ + arg0: GET_VAR a type=kotlin.Any? operator=null + arg1: CONST Null type=kotlin.Nothing? value='null' + then: CONST Null type=kotlin.Nothing? value='null' + else: CALL .hashCode type=kotlin.Int operator=null + $this: GET_VAR a type=kotlin.Any? operator=null + WHEN type=kotlin.Int operator=null + if: CALL .EQEQ type=kotlin.Boolean operator=EQEQ + arg0: GET_VAR tmp1_notnull type=kotlin.Int? operator=null + arg1: CONST Null type=kotlin.Nothing? value='null' + then: CALL .THROW_NPE type=kotlin.Nothing operator=EXCLEXCL + else: GET_VAR tmp1_notnull type=kotlin.Int? operator=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 805d0f0fab2..f939438f2dd 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -112,6 +112,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("bangbang.kt") + public void testBangbang() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/bangbang.kt"); + doTest(fileName); + } + @TestMetadata("booleanOperators.kt") public void testBooleanOperators() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/booleanOperators.kt");