From 7170439517a6f01664dd1ce277dddcedabc5ec32 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 8 Aug 2019 16:22:48 +0300 Subject: [PATCH] IR: '!!' is generated as 'CHECK_NOT_NULL' intrinsic ``` fun CHECK_NOT_NULL(x: T?): x = if (x != null) x else throw NullPointerException(...) ``` This allows to compile both Kotlin/JVM and Kotlin/JS effectively. --- .../calls/ExceptionHelperCallsTransformer.kt | 2 +- .../jvm/intrinsics/IrIntrinsicMethods.kt | 6 +- .../generators/OperatorExpressionGenerator.kt | 33 ++++--- .../kotlin/ir/builders/ExpressionHelpers.kt | 12 --- .../kotlin/ir/builders/Primitives.kt | 11 --- .../kotlin/ir/descriptors/IrBuiltIns.kt | 50 ++++++++--- .../dynamic/dynamicExclExclOperator.txt | 15 +--- .../ir/irText/expressions/bangbang.fir.txt | 60 +++++++++++++ .../ir/irText/expressions/bangbang.kt | 10 ++- .../ir/irText/expressions/bangbang.txt | 86 +++++++++++-------- .../eqeqRhsConditionPossiblyAffectingLhs.txt | 15 +--- .../ir/irText/expressions/kt30020.txt | 78 +++++++---------- 12 files changed, 217 insertions(+), 161 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/ExceptionHelperCallsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/ExceptionHelperCallsTransformer.kt index 33f2f7e4fe2..e8866b11b87 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/ExceptionHelperCallsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/ExceptionHelperCallsTransformer.kt @@ -19,7 +19,7 @@ class ExceptionHelperCallsTransformer(private val context: JsIrBackendContext) : } private val helperMapping = mapOf( - context.irBuiltIns.throwNpeSymbol to referenceFunction(kotlinPackageFqn.child(Name.identifier("THROW_NPE"))), + // context.irBuiltIns.throwNpeSymbol to referenceFunction(kotlinPackageFqn.child(Name.identifier("THROW_NPE"))), -- TODO checkNotNullSymbol context.irBuiltIns.throwCceSymbol to referenceFunction(kotlinPackageFqn.child(Name.identifier("THROW_CCE"))), context.irBuiltIns.throwIseSymbol to referenceFunction(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))), context.irBuiltIns.noWhenBranchMatchedExceptionSymbol to referenceFunction(kotlinPackageFqn.child(Name.identifier("noWhenBranchMatchedException"))) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt index bf427b737b0..a405cb7fca5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt @@ -45,7 +45,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { private val intrinsicsMap = ( listOf( - Key(KOTLIN_JVM, FqName("T"),"", emptyList()) to JavaClassProperty, + Key(KOTLIN_JVM, FqName("T"), "", emptyList()) to JavaClassProperty, Key( KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass.toSafe(), @@ -96,7 +96,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { irBuiltIns.enumValueOfSymbol.toKey()!! to IrEnumValueOf, irBuiltIns.noWhenBranchMatchedExceptionSymbol.toKey()!! to IrNoWhenBranchMatchedException, irBuiltIns.illegalArgumentExceptionSymbol.toKey()!! to IrIllegalArgumentException, - irBuiltIns.throwNpeSymbol.toKey()!! to ThrowNPE, + // irBuiltIns.throwNpeSymbol.toKey()!! to ThrowNPE, -- TODO checkNotNullSymbol irBuiltIns.andandSymbol.toKey()!! to AndAnd, irBuiltIns.ororSymbol.toKey()!! to OrOr, symbols.unsafeCoerceIntrinsicSymbol.toKey()!! to UnsafeCoerce @@ -136,7 +136,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { primitiveComparisonIntrinsics(irBuiltIns.lessOrEqualFunByOperandType, KtTokens.LTEQ) + primitiveComparisonIntrinsics(irBuiltIns.greaterFunByOperandType, KtTokens.GT) + primitiveComparisonIntrinsics(irBuiltIns.greaterOrEqualFunByOperandType, KtTokens.GTEQ) - ).toMap() + ).toMap() private val PrimitiveType.symbol get() = irBuiltIns.primitiveTypeToIrType[this]!!.classOrNull!! 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 07fec5a51cb..6901294c7a1 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 @@ -40,10 +40,8 @@ import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.intersectTypes -import org.jetbrains.kotlin.types.isDynamic -import org.jetbrains.kotlin.types.isError import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable @@ -488,16 +486,27 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat val irArgument = ktArgument.genExpr() val ktOperator = expression.operationReference - val resultType = irArgument.type.makeNotNull() + val argumentType = context.bindingContext.getType(ktArgument) + ?: throw AssertionError("No type for !! argument") + val expressionType = argumentType.makeNotNullable() - return irBlock(ktOperator.startOffsetSkippingComments, ktOperator.endOffset, origin, resultType) { - val temporary = irTemporary(irArgument, "notnull") - +irIfNull( - resultType, - irGet(temporary.type, temporary.symbol), - irThrowNpe(origin), - irGet(temporary.type, temporary.symbol) - ) + val checkNotNull = context.irBuiltIns.checkNotNull + val checkNotNullSubstituted = + checkNotNull.substitute( + TypeSubstitutor.create( + mapOf(checkNotNull.typeParameters[0].typeConstructor to TypeProjectionImpl(argumentType)) + ) + ) ?: throw AssertionError("Substitution failed for $checkNotNull: T=$argumentType") + + return IrCallImpl( + ktOperator.startOffsetSkippingComments, ktOperator.endOffset, + expressionType.toIrType(), + context.irBuiltIns.checkNotNullSymbol, + checkNotNullSubstituted, + origin + ).apply { + putTypeArgument(0, argumentType.toIrType().makeNotNull()) + putValueArgument(0, irArgument) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt index b43643af9c4..00ce660cb6b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.assertedCast @@ -159,17 +158,6 @@ fun IrBuilderWithScope.irIfThenMaybeElse( fun IrBuilderWithScope.irIfNull(type: IrType, subject: IrExpression, thenPart: IrExpression, elsePart: IrExpression) = irIfThenElse(type, irEqualsNull(subject), thenPart, elsePart) -fun IrBuilderWithScope.irThrowNpe(origin: IrStatementOrigin? = null) = - IrCallImpl( - startOffset, endOffset, - context.irBuiltIns.nothingType, - context.irBuiltIns.throwNpeSymbol, - context.irBuiltIns.throwNpeSymbol.descriptor, - typeArgumentsCount = 0, - valueArgumentsCount = 0, - origin = origin - ) - fun IrBuilderWithScope.irIfThenReturnTrue(condition: IrExpression) = irIfThen(context.irBuiltIns.unitType, condition, irReturnTrue()) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/Primitives.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/Primitives.kt index 6f8f8196987..3ff6930e275 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/Primitives.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/Primitives.kt @@ -68,17 +68,6 @@ fun IrGeneratorContext.equalsNull(startOffset: Int, endOffset: Int, argument: Ir fun IrGeneratorContext.eqeqeq(startOffset: Int, endOffset: Int, argument1: IrExpression, argument2: IrExpression): IrExpression = primitiveOp2(startOffset, endOffset, irBuiltIns.eqeqeqSymbol, irBuiltIns.booleanType, IrStatementOrigin.EQEQEQ, argument1, argument2) -fun IrGeneratorContext.throwNpe(startOffset: Int, endOffset: Int, origin: IrStatementOrigin): IrExpression = - IrCallImpl( - startOffset, endOffset, - irBuiltIns.nothingType, - irBuiltIns.throwNpeSymbol, - irBuiltIns.throwNpeSymbol.descriptor, - typeArgumentsCount = 0, - valueArgumentsCount = 0, - origin = origin - ) - fun IrGeneratorContext.constTrue(startOffset: Int, endOffset: Int) = IrConstImpl.constTrue(startOffset, endOffset, irBuiltIns.booleanType) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt index fa3e9f7175c..734ac89f460 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrBuiltIns.kt @@ -23,10 +23,7 @@ import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.TypeTranslator import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.KotlinTypeFactory -import org.jetbrains.kotlin.types.SimpleType -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.makeNullable class IrBuiltIns( @@ -204,8 +201,8 @@ class IrBuiltIns( val greaterFunByOperandType = primitiveTypesWithComparisons.defineComparisonOperatorForEachType(OperatorNames.GREATER) val ieee754equalsFunByOperandType = - primitiveFloatingPointTypes.associate { - it to defineOperator(OperatorNames.IEEE754_EQUALS, bool, listOf(it.makeNullable(), it.makeNullable())) + primitiveFloatingPointTypes.associateWith { + defineOperator(OperatorNames.IEEE754_EQUALS, bool, listOf(it.makeNullable(), it.makeNullable())) } val booleanNot = builtIns.boolean.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("not"), NoLookupLocation.FROM_BACKEND).single() @@ -213,7 +210,6 @@ class IrBuiltIns( val eqeqeqSymbol = defineOperator(OperatorNames.EQEQEQ, bool, listOf(anyN, anyN)) val eqeqSymbol = defineOperator(OperatorNames.EQEQ, bool, listOf(anyN, anyN)) - val throwNpeSymbol = defineOperator(OperatorNames.THROW_NPE, nothing, listOf()) val throwCceSymbol = defineOperator(OperatorNames.THROW_CCE, nothing, listOf()) val throwIseSymbol = defineOperator(OperatorNames.THROW_ISE, nothing, listOf()) val andandSymbol = defineOperator(OperatorNames.ANDAND, bool, listOf(bool, bool)) @@ -223,15 +219,11 @@ class IrBuiltIns( val eqeqeq = eqeqeqSymbol.descriptor val eqeq = eqeqSymbol.descriptor - val throwNpe = throwNpeSymbol.descriptor val throwCce = throwCceSymbol.descriptor val noWhenBranchMatchedException = noWhenBranchMatchedExceptionSymbol.descriptor val illegalArgumentException = illegalArgumentExceptionSymbol.descriptor - val enumValueOfSymbol = createEnumValueOfFun() - val enumValueOf = enumValueOfSymbol.descriptor - - private fun createEnumValueOfFun(): IrSimpleFunctionSymbol = + val enumValueOfSymbol = SimpleFunctionDescriptorImpl.create( packageFragment, Annotations.EMPTY, @@ -248,10 +240,42 @@ class IrBuiltIns( false, false, false, null, SourceElement.NO_SOURCE ) - val returnType = KotlinTypeFactory.simpleType(Annotations.EMPTY, typeParameterT.typeConstructor, listOf(), false) + val returnType = typeParameterT.typeConstructor.makeNonNullType() initialize(null, null, listOf(typeParameterT), listOf(valueParameterName), returnType, Modality.FINAL, Visibilities.PUBLIC) }.addStub() + val enumValueOf = enumValueOfSymbol.descriptor + + val checkNotNullSymbol = + SimpleFunctionDescriptorImpl.create( + packageFragment, + Annotations.EMPTY, + Name.identifier("CHECK_NOT_NULL"), + CallableMemberDescriptor.Kind.SYNTHESIZED, + SourceElement.NO_SOURCE + ).apply { + val typeParameterT = TypeParameterDescriptorImpl.createForFurtherModification( + this, Annotations.EMPTY, false, Variance.INVARIANT, Name.identifier("T"), 0, SourceElement.NO_SOURCE + ).apply { + addUpperBound(builtIns.anyType) + setInitialized() + } + + val valueParameterX = ValueParameterDescriptorImpl( + this, null, 0, Annotations.EMPTY, Name.identifier("x"), typeParameterT.typeConstructor.makeNullableType(), + false, false, false, null, SourceElement.NO_SOURCE + ) + + initialize( + null, null, + listOf(typeParameterT), listOf(valueParameterX), typeParameterT.typeConstructor.makeNonNullType(), + Modality.FINAL, Visibilities.PUBLIC + ) + }.addStub() + val checkNotNull = checkNotNullSymbol.descriptor + + private fun TypeConstructor.makeNonNullType() = KotlinTypeFactory.simpleType(Annotations.EMPTY, this, listOf(), false) + private fun TypeConstructor.makeNullableType() = KotlinTypeFactory.simpleType(Annotations.EMPTY, this, listOf(), true) val dataClassArrayMemberHashCodeSymbol = defineOperator("dataClassArrayMemberHashCode", int, listOf(any)) val dataClassArrayMemberHashCode = dataClassArrayMemberHashCodeSymbol.descriptor diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicExclExclOperator.txt b/compiler/testData/ir/irJsText/dynamic/dynamicExclExclOperator.txt index 50f1d8f314e..f6520dbc87d 100644 --- a/compiler/testData/ir/irJsText/dynamic/dynamicExclExclOperator.txt +++ b/compiler/testData/ir/irJsText/dynamic/dynamicExclExclOperator.txt @@ -3,15 +3,6 @@ FILE fqName: fileName:/dynamicExclExclOperator.kt VALUE_PARAMETER name:d index:0 type:dynamic BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun test (d: dynamic): dynamic declared in ' - BLOCK type=dynamic origin=EXCLEXCL - VAR IR_TEMPORARY_VARIABLE name:tmp0_notnull type:dynamic [val] - GET_VAR 'd: dynamic declared in .test' type=dynamic origin=null - WHEN type=dynamic origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp0_notnull: dynamic [val] declared in .test' type=dynamic origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CALL 'public final fun THROW_NPE (): kotlin.Nothing declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: GET_VAR 'val tmp0_notnull: dynamic [val] declared in .test' type=dynamic origin=null + CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=dynamic origin=EXCLEXCL + : dynamic + x: GET_VAR 'd: dynamic declared in .test' type=dynamic origin=null diff --git a/compiler/testData/ir/irText/expressions/bangbang.fir.txt b/compiler/testData/ir/irText/expressions/bangbang.fir.txt index 64af4b6c07d..095605802c1 100644 --- a/compiler/testData/ir/irText/expressions/bangbang.fir.txt +++ b/compiler/testData/ir/irText/expressions/bangbang.fir.txt @@ -34,3 +34,63 @@ FILE fqName: fileName:/bangbang.kt BRANCH if: CONST Boolean type=kotlin.Boolean value=true then: GET_VAR 'val : kotlin.Int [val] declared in .test2' type=kotlin.Int origin=null + FUN name:test3 visibility:public modality:FINAL (a:X of .test3) returnType:X of .test3 + TYPE_PARAMETER name:X index:0 variance: superTypes:[] + VALUE_PARAMETER name:a index:0 type:X of .test3 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test3 (a: X of .test3): X of .test3 declared in ' + BLOCK type=X of .test3 origin=EXCLEXCL + VAR name: type:X of .test3 [val] + GET_VAR 'a: X of .test3 declared in .test3' type=X of .test3 origin=null + WHEN type=X of .test3 origin=EXCLEXCL + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val : X of .test3 [val] declared in .test3' type=X of .test3 origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: THROW type=kotlin.Nothing + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'val : X of .test3 [val] declared in .test3' type=X of .test3 origin=null + FUN name:useString visibility:public modality:FINAL <> (s:kotlin.String) returnType:kotlin.Unit + VALUE_PARAMETER name:s index:0 type:kotlin.String + BLOCK_BODY + FUN name:test4 visibility:public modality:FINAL (a:X of .test4) returnType:kotlin.Unit + TYPE_PARAMETER name:X index:0 variance: superTypes:[] + VALUE_PARAMETER name:a index:0 type:X of .test4 + BLOCK_BODY + WHEN type=kotlin.Unit origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.String? + GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + then: BLOCK type=kotlin.Unit origin=EXCLEXCL + VAR name: type:X of .test4 [val] + GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + WHEN type=kotlin.Unit origin=EXCLEXCL + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val : X of .test4 [val] declared in .test4' type=X of .test4 origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: THROW type=kotlin.Nothing + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'val : X of .test4 [val] declared in .test4' type=X of .test4 origin=null + WHEN type=kotlin.Unit origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.String? + GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + then: ERROR_CALL 'Unresolved reference: #' type=IrErrorType + BLOCK type=X of .test4 origin=EXCLEXCL + VAR name: type:X of .test4 [val] + GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + WHEN type=X of .test4 origin=EXCLEXCL + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val : X of .test4 [val] declared in .test4' type=X of .test4 origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: THROW type=kotlin.Nothing + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'val : X of .test4 [val] declared in .test4' type=X of .test4 origin=null diff --git a/compiler/testData/ir/irText/expressions/bangbang.kt b/compiler/testData/ir/irText/expressions/bangbang.kt index 36ca3020fa6..c447c677170 100644 --- a/compiler/testData/ir/irText/expressions/bangbang.kt +++ b/compiler/testData/ir/irText/expressions/bangbang.kt @@ -1,3 +1,11 @@ fun test1(a: Any?) = a!! -fun test2(a: Any?) = a?.hashCode()!! \ No newline at end of file +fun test2(a: Any?) = a?.hashCode()!! + +fun test3(a: X) = a!! + +fun useString(s: String) {} +fun test4(a: X) { + if (a is String?) a!! + if (a is String?) useString(a!!) +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/bangbang.txt b/compiler/testData/ir/irText/expressions/bangbang.txt index 6c7b7301d16..f4ffaf61832 100644 --- a/compiler/testData/ir/irText/expressions/bangbang.txt +++ b/compiler/testData/ir/irText/expressions/bangbang.txt @@ -3,43 +3,57 @@ FILE fqName: fileName:/bangbang.kt VALUE_PARAMETER name:a index:0 type:kotlin.Any? BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun test1 (a: kotlin.Any?): kotlin.Any declared in ' - BLOCK type=kotlin.Any origin=EXCLEXCL - VAR IR_TEMPORARY_VARIABLE name:tmp0_notnull type:kotlin.Any? [val] - GET_VAR 'a: kotlin.Any? declared in .test1' type=kotlin.Any? origin=null - WHEN type=kotlin.Any origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp0_notnull: kotlin.Any? [val] declared in .test1' type=kotlin.Any? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CALL 'public final fun THROW_NPE (): kotlin.Nothing declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: GET_VAR 'val tmp0_notnull: kotlin.Any? [val] declared in .test1' type=kotlin.Any? origin=null + CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.Any origin=EXCLEXCL + : kotlin.Any + x: GET_VAR 'a: kotlin.Any? declared in .test1' type=kotlin.Any? origin=null FUN name:test2 visibility:public modality:FINAL <> (a:kotlin.Any?) returnType:kotlin.Int VALUE_PARAMETER name:a index:0 type:kotlin.Any? BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun test2 (a: kotlin.Any?): kotlin.Int declared in ' - BLOCK type=kotlin.Int origin=EXCLEXCL - VAR IR_TEMPORARY_VARIABLE name:tmp1_notnull type:kotlin.Int? [val] - BLOCK type=kotlin.Int? origin=SAFE_CALL - VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:kotlin.Any? [val] - GET_VAR 'a: kotlin.Any? declared in .test2' type=kotlin.Any? origin=null - WHEN type=kotlin.Int? origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp0_safe_receiver: kotlin.Any? [val] declared in .test2' type=kotlin.Any? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CONST Null type=kotlin.Nothing? value=null - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Any' type=kotlin.Int origin=null - $this: GET_VAR 'val tmp0_safe_receiver: kotlin.Any? [val] declared in .test2' type=kotlin.Any? origin=null - WHEN type=kotlin.Int origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp1_notnull: kotlin.Int? [val] declared in .test2' type=kotlin.Int? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CALL 'public final fun THROW_NPE (): kotlin.Nothing declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: GET_VAR 'val tmp1_notnull: kotlin.Int? [val] declared in .test2' type=kotlin.Int? origin=null + CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.Int origin=EXCLEXCL + : kotlin.Int + x: BLOCK type=kotlin.Int? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:kotlin.Any? [val] + GET_VAR 'a: kotlin.Any? declared in .test2' type=kotlin.Any? origin=null + WHEN type=kotlin.Int? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val tmp0_safe_receiver: kotlin.Any? [val] declared in .test2' type=kotlin.Any? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Any' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp0_safe_receiver: kotlin.Any? [val] declared in .test2' type=kotlin.Any? origin=null + FUN name:test3 visibility:public modality:FINAL (a:X of .test3) returnType:X of .test3 + TYPE_PARAMETER name:X index:0 variance: superTypes:[kotlin.Any?] + VALUE_PARAMETER name:a index:0 type:X of .test3 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun test3 (a: X of .test3): X of .test3 declared in ' + CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=X of .test3 origin=EXCLEXCL + : X of .test3 + x: GET_VAR 'a: X of .test3 declared in .test3' type=X of .test3 origin=null + FUN name:useString visibility:public modality:FINAL <> (s:kotlin.String) returnType:kotlin.Unit + VALUE_PARAMETER name:s index:0 type:kotlin.String + BLOCK_BODY + FUN name:test4 visibility:public modality:FINAL (a:X of .test4) returnType:kotlin.Unit + TYPE_PARAMETER name:X index:0 variance: superTypes:[kotlin.Any?] + VALUE_PARAMETER name:a index:0 type:X of .test4 + BLOCK_BODY + WHEN type=kotlin.Unit origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.String? + GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + then: TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=X of .test4 origin=EXCLEXCL + : X of .test4 + x: GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + WHEN type=kotlin.Unit origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.String? + GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null + then: CALL 'public final fun useString (s: kotlin.String): kotlin.Unit declared in ' type=kotlin.Unit origin=null + s: TYPE_OP type=kotlin.String origin=IMPLICIT_CAST typeOperand=kotlin.String + CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=X of .test4 origin=EXCLEXCL + : X of .test4 + x: GET_VAR 'a: X of .test4 declared in .test4' type=X of .test4 origin=null diff --git a/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt b/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt index 3c8a3bb4343..fa7e97c51cf 100644 --- a/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt +++ b/compiler/testData/ir/irText/expressions/floatingPointComparisons/eqeqRhsConditionPossiblyAffectingLhs.txt @@ -9,18 +9,9 @@ FILE fqName: fileName:/eqeqRhsConditionPossiblyAffectingLhs.kt BRANCH if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=kotlin.Double GET_VAR 'x: kotlin.Any declared in .test' type=kotlin.Any origin=null - then: BLOCK type=kotlin.Nothing origin=EXCLEXCL - VAR IR_TEMPORARY_VARIABLE name:tmp0_notnull type:kotlin.Nothing? [val] - CONST Null type=kotlin.Nothing? value=null - WHEN type=kotlin.Nothing origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp0_notnull: kotlin.Nothing? [val] declared in .test' type=kotlin.Nothing? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CALL 'public final fun THROW_NPE (): kotlin.Nothing declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: GET_VAR 'val tmp0_notnull: kotlin.Nothing? [val] declared in .test' type=kotlin.Nothing? origin=null + then: CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL + : kotlin.Nothing + x: CONST Null type=kotlin.Nothing? value=null BRANCH if: CONST Boolean type=kotlin.Boolean value=true then: TYPE_OP type=kotlin.Double origin=IMPLICIT_CAST typeOperand=kotlin.Double diff --git a/compiler/testData/ir/irText/expressions/kt30020.txt b/compiler/testData/ir/irText/expressions/kt30020.txt index d899e60dbf0..737df95200a 100644 --- a/compiler/testData/ir/irText/expressions/kt30020.txt +++ b/compiler/testData/ir/irText/expressions/kt30020.txt @@ -51,57 +51,39 @@ FILE fqName: fileName:/kt30020.kt element: CONST Int type=kotlin.Int value=4 CALL 'public final fun plusAssign (element: T of kotlin.collections.plusAssign): kotlin.Unit [inline] declared in kotlin.collections' type=kotlin.Unit origin=PLUSEQ : kotlin.Int - $receiver: BLOCK type=kotlin.collections.MutableList origin=EXCLEXCL - VAR IR_TEMPORARY_VARIABLE name:tmp2_notnull type:kotlin.collections.MutableList? [val] - BLOCK type=kotlin.collections.MutableList? origin=SAFE_CALL - VAR IR_TEMPORARY_VARIABLE name:tmp1_safe_receiver type:.X? [val] - GET_VAR 'nx: .X? declared in .test' type=.X? origin=null - WHEN type=kotlin.collections.MutableList? origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp1_safe_receiver: .X? [val] declared in .test' type=.X? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CONST Null type=kotlin.Nothing? value=null - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: CALL 'public abstract fun (): kotlin.collections.MutableList declared in .X' type=kotlin.collections.MutableList origin=GET_PROPERTY - $this: GET_VAR 'val tmp1_safe_receiver: .X? [val] declared in .test' type=.X? origin=null - WHEN type=kotlin.collections.MutableList origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp2_notnull: kotlin.collections.MutableList? [val] declared in .test' type=kotlin.collections.MutableList? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CALL 'public final fun THROW_NPE (): kotlin.Nothing declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: GET_VAR 'val tmp2_notnull: kotlin.collections.MutableList? [val] declared in .test' type=kotlin.collections.MutableList? origin=null + $receiver: CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.collections.MutableList origin=EXCLEXCL + : kotlin.collections.MutableList + x: BLOCK type=kotlin.collections.MutableList? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp1_safe_receiver type:.X? [val] + GET_VAR 'nx: .X? declared in .test' type=.X? origin=null + WHEN type=kotlin.collections.MutableList? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val tmp1_safe_receiver: .X? [val] declared in .test' type=.X? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public abstract fun (): kotlin.collections.MutableList declared in .X' type=kotlin.collections.MutableList origin=GET_PROPERTY + $this: GET_VAR 'val tmp1_safe_receiver: .X? [val] declared in .test' type=.X? origin=null element: CONST Int type=kotlin.Int value=5 CALL 'public final fun plusAssign (element: T of kotlin.collections.plusAssign): kotlin.Unit [inline] declared in kotlin.collections' type=kotlin.Unit origin=PLUSEQ : kotlin.Int - $receiver: BLOCK type=kotlin.collections.MutableList origin=EXCLEXCL - VAR IR_TEMPORARY_VARIABLE name:tmp4_notnull type:kotlin.collections.MutableList? [val] - BLOCK type=kotlin.collections.MutableList? origin=SAFE_CALL - VAR IR_TEMPORARY_VARIABLE name:tmp3_safe_receiver type:.X? [val] - GET_VAR 'nx: .X? declared in .test' type=.X? origin=null - WHEN type=kotlin.collections.MutableList? origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp3_safe_receiver: .X? [val] declared in .test' type=.X? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CONST Null type=kotlin.Nothing? value=null - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: CALL 'public abstract fun f (): kotlin.collections.MutableList declared in .X' type=kotlin.collections.MutableList origin=null - $this: GET_VAR 'val tmp3_safe_receiver: .X? [val] declared in .test' type=.X? origin=null - WHEN type=kotlin.collections.MutableList origin=null - BRANCH - if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ - arg0: GET_VAR 'val tmp4_notnull: kotlin.collections.MutableList? [val] declared in .test' type=kotlin.collections.MutableList? origin=null - arg1: CONST Null type=kotlin.Nothing? value=null - then: CALL 'public final fun THROW_NPE (): kotlin.Nothing declared in kotlin.internal.ir' type=kotlin.Nothing origin=EXCLEXCL - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: GET_VAR 'val tmp4_notnull: kotlin.collections.MutableList? [val] declared in .test' type=kotlin.collections.MutableList? origin=null + $receiver: CALL 'public final fun CHECK_NOT_NULL (x: T of kotlin.internal.ir.CHECK_NOT_NULL?): T of kotlin.internal.ir.CHECK_NOT_NULL declared in kotlin.internal.ir' type=kotlin.collections.MutableList origin=EXCLEXCL + : kotlin.collections.MutableList + x: BLOCK type=kotlin.collections.MutableList? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp2_safe_receiver type:.X? [val] + GET_VAR 'nx: .X? declared in .test' type=.X? origin=null + WHEN type=kotlin.collections.MutableList? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val tmp2_safe_receiver: .X? [val] declared in .test' type=.X? origin=null + arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public abstract fun f (): kotlin.collections.MutableList declared in .X' type=kotlin.collections.MutableList origin=null + $this: GET_VAR 'val tmp2_safe_receiver: .X? [val] declared in .test' type=.X? origin=null element: CONST Int type=kotlin.Int value=6 FUN name:testExtensionReceiver visibility:public modality:FINAL <> ($receiver:kotlin.collections.MutableList) returnType:kotlin.Unit $receiver: VALUE_PARAMETER name: type:kotlin.collections.MutableList