diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java index 9bd182c39b3..40f279a9ddf 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java @@ -1882,6 +1882,11 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { runTest("compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/ir/irText/types/receiverOfIntersectionType.kt"); + } + @TestMetadata("smartCastOnFakeOverrideReceiver.kt") public void testSmartCastOnFakeOverrideReceiver() throws Exception { runTest("compiler/testData/ir/irText/types/smartCastOnFakeOverrideReceiver.kt"); diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt index 84ee88727bf..3b689c5296d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/transformations/InsertImplicitCasts.kt @@ -299,19 +299,19 @@ internal class InsertImplicitCasts( null private fun IrExpression.cast( - expectedType: KotlinType?, - originalExpectedType: KotlinType? = expectedType, + possiblyNonDenotableExpectedType: KotlinType?, + originalExpectedType: KotlinType? = possiblyNonDenotableExpectedType, isLambdaReturnValue: Boolean = false ): IrExpression { - if (expectedType == null) return this - if (expectedType.isError) return this + if (possiblyNonDenotableExpectedType == null) return this + if (possiblyNonDenotableExpectedType.isError) return this + + val expectedType = typeTranslator.approximate(possiblyNonDenotableExpectedType) if (this is IrFunctionExpression && originalExpectedType != null) { recordExpectedLambdaReturnTypeIfAppropriate(expectedType, originalExpectedType) } - // TODO here we can have non-denotable KotlinTypes (both in 'this@cast.type' and 'expectedType'). - val notNullableExpectedType = expectedType.makeNotNullable() val valueType = this.type.originalKotlinType!! diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt index 6dfc86a73dc..3c30da97025 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt @@ -62,27 +62,27 @@ class TypeTranslator( } fun translateType(kotlinType: KotlinType): IrType = - translateType(kotlinType, kotlinType, Variance.INVARIANT).type + translateType(kotlinType, Variance.INVARIANT).type - private fun translateType(kotlinType: KotlinType, approximatedKotlinType: KotlinType, variance: Variance): IrTypeProjection { - val approximatedType = LegacyTypeApproximation().approximate(kotlinType) + private fun translateType(kotlinType: KotlinType, variance: Variance): IrTypeProjection { + val flexibleApproximatedType = approximate(kotlinType) when { - approximatedType.isError -> - return IrErrorTypeImpl(approximatedKotlinType, translateTypeAnnotations(approximatedType.annotations), variance) - approximatedType.isDynamic() -> - return IrDynamicTypeImpl(approximatedKotlinType, translateTypeAnnotations(approximatedType.annotations), variance) - approximatedType.isFlexible() -> - return translateType(approximatedType.upperIfFlexible(), approximatedType, variance) + flexibleApproximatedType.isError -> + return IrErrorTypeImpl(flexibleApproximatedType, translateTypeAnnotations(flexibleApproximatedType.annotations), variance) + flexibleApproximatedType.isDynamic() -> + return IrDynamicTypeImpl(flexibleApproximatedType, translateTypeAnnotations(flexibleApproximatedType.annotations), variance) } + val approximatedType = flexibleApproximatedType.upperIfFlexible() + val ktTypeConstructor = approximatedType.constructor val ktTypeDescriptor = ktTypeConstructor.declarationDescriptor ?: throw AssertionError("No descriptor for type $approximatedType") return IrSimpleTypeBuilder().apply { - this.kotlinType = approximatedKotlinType - hasQuestionMark = approximatedType.isMarkedNullable + this.kotlinType = flexibleApproximatedType + this.hasQuestionMark = approximatedType.isMarkedNullable this.variance = variance this.abbreviation = approximatedType.getAbbreviation()?.toIrTypeAbbreviation() when (ktTypeDescriptor) { @@ -116,46 +116,42 @@ class TypeTranslator( ) } - private inner class LegacyTypeApproximation { + fun approximate(ktType: KotlinType): KotlinType { + val properlyApproximatedType = approximateByKotlinRules(ktType) - fun approximate(ktType: KotlinType): KotlinType { - val properlyApproximatedType = approximateByKotlinRules(ktType) - - // If there's an intersection type, take the most common supertype of its intermediate supertypes. - // That's what old back-end effectively does. - val typeConstructor = properlyApproximatedType.constructor - if (typeConstructor is IntersectionTypeConstructor) { - val commonSupertype = CommonSupertypes.commonSupertype(typeConstructor.supertypes) - return approximate(commonSupertype.replaceArgumentsWithStarProjections()) - } - - // Other types should be approximated properly. Right? Riiight? - return properlyApproximatedType + // If there's an intersection type, take the most common supertype of its intermediate supertypes. + // That's what old back-end effectively does. + val typeConstructor = properlyApproximatedType.constructor + if (typeConstructor is IntersectionTypeConstructor) { + val commonSupertype = CommonSupertypes.commonSupertype(typeConstructor.supertypes) + return approximate(commonSupertype.replaceArgumentsWithStarProjections()) } - private val isWithNewInference = languageVersionSettings.supportsFeature(LanguageFeature.NewInference) - - private fun approximateByKotlinRules(ktType: KotlinType): KotlinType = - if (isWithNewInference) { - if (ktType.constructor.isDenotable && ktType.arguments.isEmpty()) - ktType - else - typeApproximatorForNI.approximateDeclarationType( - ktType, - local = false, - languageVersionSettings = languageVersionSettings - ) - } else { - // Hack to preserve *-projections in arguments in OI. - // Expected to be removed as soon as OI is deprecated. - if (ktType.constructor.isDenotable) - ktType - else - approximateCapturedTypes(ktType).upper - } - + // Assume that other types are approximated properly. + return properlyApproximatedType } + private val isWithNewInference = languageVersionSettings.supportsFeature(LanguageFeature.NewInference) + + private fun approximateByKotlinRules(ktType: KotlinType): KotlinType = + if (isWithNewInference) { + if (ktType.constructor.isDenotable && ktType.arguments.isEmpty()) + ktType + else + typeApproximatorForNI.approximateDeclarationType( + ktType, + local = false, + languageVersionSettings = languageVersionSettings + ) + } else { + // Hack to preserve *-projections in arguments in OI. + // Expected to be removed as soon as OI is deprecated. + if (ktType.constructor.isDenotable) + ktType + else + approximateCapturedTypes(ktType).upper + } + private fun translateTypeAnnotations(annotations: Annotations): List = annotations.mapNotNull(constantValueGenerator::generateAnnotationConstructorCall) @@ -164,6 +160,6 @@ class TypeTranslator( if (it.isStarProjection) IrStarProjectionImpl else - translateType(it.type, it.type, it.projectionKind) + translateType(it.type, it.projectionKind) } } diff --git a/compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt b/compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt new file mode 100644 index 00000000000..bc8c3ae535b --- /dev/null +++ b/compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt @@ -0,0 +1,20 @@ +interface K + +interface I : K { + fun ff(): String +} + +interface J : K {} + +class A: I, J { + override fun ff() = "OK" +} + +class B: I, J { + override fun ff() = "Irrelevant" +} + +fun box(): String { + val v = if (true) A() else B() + return v.ff() +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt b/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt index 390eea3c281..0ffed6ae349 100644 --- a/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt +++ b/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.txt @@ -36,15 +36,15 @@ FILE fqName: fileName:/implicitCastToTypeParameter.kt $receiver: VALUE_PARAMETER name: type:.Foo.> BLOCK_BODY RETURN type=kotlin.Nothing from='public final fun (): T of .? [inline] declared in ' - WHEN type=kotlin.Any? origin=IF - BRANCH - if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=T of . - GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null - then: TYPE_OP type=kotlin.Any origin=IMPLICIT_CAST typeOperand=kotlin.Any - GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null - BRANCH - if: CONST Boolean type=kotlin.Boolean value=true - then: CONST Null type=kotlin.Nothing? value=null + TYPE_OP type=T of .? origin=IMPLICIT_CAST typeOperand=T of .? + WHEN type=kotlin.Any? origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=T of . + GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null + then: GET_VAR ': .Foo.> declared in .' type=.Foo.> origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Null type=kotlin.Nothing? value=null CLASS CLASS name:Bar modality:FINAL visibility:public superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Bar.Bar> TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] diff --git a/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.txt b/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.txt index 067527ec2f1..0764bcd22a7 100644 --- a/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.txt +++ b/compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.txt @@ -95,19 +95,21 @@ FILE fqName: fileName:/localVariableOfIntersectionType_NI.kt VALUE_PARAMETER name:z index:2 type:.Z BLOCK_BODY CALL 'public abstract fun foo (): kotlin.Unit declared in .IA' type=kotlin.Unit origin=null - $this: CALL 'public abstract fun (): T of .Inv declared in .Inv' type=kotlin.Any origin=GET_PROPERTY - $this: CALL 'public abstract fun create (x: .In.Z.create>, y: .In.Z.create>): .Inv.Z.create> declared in .Z' type=.Inv origin=null - : kotlin.Any - $this: GET_VAR 'z: .Z declared in .test' type=.Z origin=null - x: GET_VAR 'a: .In<.IA> declared in .test' type=.In<.IA> origin=null - y: GET_VAR 'b: .In<.IB> declared in .test' type=.In<.IB> origin=null + $this: TYPE_OP type=.IA origin=IMPLICIT_CAST typeOperand=.IA + CALL 'public abstract fun (): T of .Inv declared in .Inv' type=kotlin.Any origin=GET_PROPERTY + $this: CALL 'public abstract fun create (x: .In.Z.create>, y: .In.Z.create>): .Inv.Z.create> declared in .Z' type=.Inv origin=null + : kotlin.Any + $this: GET_VAR 'z: .Z declared in .test' type=.Z origin=null + x: GET_VAR 'a: .In<.IA> declared in .test' type=.In<.IA> origin=null + y: GET_VAR 'b: .In<.IB> declared in .test' type=.In<.IB> origin=null CALL 'public abstract fun bar (): kotlin.Unit declared in .IB' type=kotlin.Unit origin=null - $this: CALL 'public abstract fun (): T of .Inv declared in .Inv' type=kotlin.Any origin=GET_PROPERTY - $this: CALL 'public abstract fun create (x: .In.Z.create>, y: .In.Z.create>): .Inv.Z.create> declared in .Z' type=.Inv origin=null - : kotlin.Any - $this: GET_VAR 'z: .Z declared in .test' type=.Z origin=null - x: GET_VAR 'a: .In<.IA> declared in .test' type=.In<.IA> origin=null - y: GET_VAR 'b: .In<.IB> declared in .test' type=.In<.IB> origin=null + $this: TYPE_OP type=.IB origin=IMPLICIT_CAST typeOperand=.IB + CALL 'public abstract fun (): T of .Inv declared in .Inv' type=kotlin.Any origin=GET_PROPERTY + $this: CALL 'public abstract fun create (x: .In.Z.create>, y: .In.Z.create>): .Inv.Z.create> declared in .Z' type=.Inv origin=null + : kotlin.Any + $this: GET_VAR 'z: .Z declared in .test' type=.Z origin=null + x: GET_VAR 'a: .In<.IA> declared in .test' type=.In<.IA> origin=null + y: GET_VAR 'b: .In<.IB> declared in .test' type=.In<.IB> origin=null VAR name:t type:kotlin.Any [val] CALL 'public abstract fun (): T of .Inv declared in .Inv' type=kotlin.Any origin=GET_PROPERTY $this: CALL 'public abstract fun create (x: .In.Z.create>, y: .In.Z.create>): .Inv.Z.create> declared in .Z' type=.Inv origin=null @@ -116,6 +118,8 @@ FILE fqName: fileName:/localVariableOfIntersectionType_NI.kt x: GET_VAR 'a: .In<.IA> declared in .test' type=.In<.IA> origin=null y: GET_VAR 'b: .In<.IB> declared in .test' type=.In<.IB> origin=null CALL 'public abstract fun foo (): kotlin.Unit declared in .IA' type=kotlin.Unit origin=null - $this: GET_VAR 'val t: kotlin.Any [val] declared in .test' type=kotlin.Any origin=null + $this: TYPE_OP type=.IA origin=IMPLICIT_CAST typeOperand=.IA + GET_VAR 'val t: kotlin.Any [val] declared in .test' type=kotlin.Any origin=null CALL 'public abstract fun bar (): kotlin.Unit declared in .IB' type=kotlin.Unit origin=null - $this: GET_VAR 'val t: kotlin.Any [val] declared in .test' type=kotlin.Any origin=null + $this: TYPE_OP type=.IB origin=IMPLICIT_CAST typeOperand=.IB + GET_VAR 'val t: kotlin.Any [val] declared in .test' type=kotlin.Any origin=null diff --git a/compiler/testData/ir/irText/types/receiverOfIntersectionType.fir.txt b/compiler/testData/ir/irText/types/receiverOfIntersectionType.fir.txt new file mode 100644 index 00000000000..16484d5b08c --- /dev/null +++ b/compiler/testData/ir/irText/types/receiverOfIntersectionType.fir.txt @@ -0,0 +1,136 @@ +FILE fqName: fileName:/receiverOfIntersectionType.kt + CLASS INTERFACE name:K modality:ABSTRACT visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.K + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS INTERFACE name:I modality:ABSTRACT visibility:public superTypes:[.K] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.I + FUN name:ff visibility:public modality:ABSTRACT <> ($this:.I) returnType:kotlin.Unit + $this: VALUE_PARAMETER name: type:.I + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS INTERFACE name:J modality:ABSTRACT visibility:public superTypes:[.K] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.J + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS CLASS name:A modality:FINAL visibility:public superTypes:[.I; .J] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.A + CONSTRUCTOR visibility:public <> () returnType:.A [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:A modality:FINAL visibility:public superTypes:[.I; .J]' + FUN name:ff visibility:public modality:FINAL <> ($this:.A) returnType:kotlin.Unit + $this: VALUE_PARAMETER name: type:.A + BLOCK_BODY + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS CLASS name:B modality:FINAL visibility:public superTypes:[.I; .J] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.B + CONSTRUCTOR visibility:public <> () returnType:.B [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:B modality:FINAL visibility:public superTypes:[.I; .J]' + FUN name:ff visibility:public modality:FINAL <> ($this:.B) returnType:kotlin.Unit + $this: VALUE_PARAMETER name: type:.B + BLOCK_BODY + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN name:testIntersection visibility:public modality:FINAL <> (a:.A, b:.B) returnType:kotlin.Unit + VALUE_PARAMETER name:a index:0 type:.A + VALUE_PARAMETER name:b index:1 type:.B + BLOCK_BODY + VAR name:v type:.I [val] + WHEN type=.I origin=IF + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'a: .A declared in .testIntersection' type=.A origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'b: .B declared in .testIntersection' type=.B origin=null + CALL 'public abstract fun ff (): kotlin.Unit declared in .I' type=kotlin.Unit origin=null + $this: GET_VAR 'val v: .I [val] declared in .testIntersection' type=.I origin=null + FUN name:testFlexible1 visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + VAR name:v type:.I? [val] + WHEN type=.I? origin=IF + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun a (): .A? declared in .Java' type=.A? origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun b (): .B? declared in .Java' type=.B? origin=null + CALL 'public abstract fun ff (): kotlin.Unit declared in .I' type=kotlin.Unit origin=null + $this: GET_VAR 'val v: .I? [val] declared in .testFlexible1' type=.I? origin=null + FUN name:testFlexible2 visibility:public modality:FINAL <> (a:.A, b:.B) returnType:kotlin.Unit + VALUE_PARAMETER name:a index:0 type:.A + VALUE_PARAMETER name:b index:1 type:.B + BLOCK_BODY + VAR name:v type:.I? [val] + WHEN type=.I? origin=IF + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun id (x: T of .Java.id?): T of .Java.id? declared in .Java' type=.A? origin=null + : .A? + x: GET_VAR 'a: .A declared in .testFlexible2' type=.A origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun id (x: T of .Java.id?): T of .Java.id? declared in .Java' type=.B? origin=null + : .B? + x: GET_VAR 'b: .B declared in .testFlexible2' type=.B origin=null + CALL 'public abstract fun ff (): kotlin.Unit declared in .I' type=kotlin.Unit origin=null + $this: GET_VAR 'val v: .I? [val] declared in .testFlexible2' type=.I? origin=null diff --git a/compiler/testData/ir/irText/types/receiverOfIntersectionType.kt b/compiler/testData/ir/irText/types/receiverOfIntersectionType.kt new file mode 100644 index 00000000000..c3fdf5b6869 --- /dev/null +++ b/compiler/testData/ir/irText/types/receiverOfIntersectionType.kt @@ -0,0 +1,40 @@ +// !LANGUAGE: +NewInference +// FILE: receiverOfIntersectionType.kt + +interface K + +interface I : K { + fun ff() +} + +interface J : K {} + +class A: I, J { + override fun ff() {} +} + +class B: I, J { + override fun ff() {} +} + +fun testIntersection(a: A, b: B) { + val v = if (true) a else b + v.ff() +} + +fun testFlexible1() { + val v = if (true) Java.a() else Java.b() + v.ff() +} + +fun testFlexible2(a: A, b: B) { + val v = if (true) Java.id(a) else Java.id(b) + v.ff() +} + +// FILE: Java.java +public class Java { + public static A a() { return new A(); } + public static B b() { return new B(); } + public static T id(T x) { return x; } +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/types/receiverOfIntersectionType.txt b/compiler/testData/ir/irText/types/receiverOfIntersectionType.txt new file mode 100644 index 00000000000..6e42c1e26cc --- /dev/null +++ b/compiler/testData/ir/irText/types/receiverOfIntersectionType.txt @@ -0,0 +1,151 @@ +FILE fqName: fileName:/receiverOfIntersectionType.kt + CLASS INTERFACE name:K modality:ABSTRACT visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.K + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS INTERFACE name:I modality:ABSTRACT visibility:public superTypes:[.K] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.I + FUN name:ff visibility:public modality:ABSTRACT <> ($this:.I) returnType:kotlin.Unit + $this: VALUE_PARAMETER name: type:.I + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .K + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int [fake_override] declared in .K + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String [fake_override] declared in .K + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS INTERFACE name:J modality:ABSTRACT visibility:public superTypes:[.K] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.J + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .K + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int [fake_override] declared in .K + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String [fake_override] declared in .K + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS CLASS name:A modality:FINAL visibility:public superTypes:[.I; .J] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.A + CONSTRUCTOR visibility:public <> () returnType:.A [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:A modality:FINAL visibility:public superTypes:[.I; .J]' + FUN name:ff visibility:public modality:OPEN <> ($this:.A) returnType:kotlin.Unit + overridden: + public abstract fun ff (): kotlin.Unit declared in .I + $this: VALUE_PARAMETER name: type:.A + BLOCK_BODY + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .I + public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .J + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int [fake_override] declared in .I + public open fun hashCode (): kotlin.Int [fake_override] declared in .J + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String [fake_override] declared in .I + public open fun toString (): kotlin.String [fake_override] declared in .J + $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS CLASS name:B modality:FINAL visibility:public superTypes:[.I; .J] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.B + CONSTRUCTOR visibility:public <> () returnType:.B [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:B modality:FINAL visibility:public superTypes:[.I; .J]' + FUN name:ff visibility:public modality:OPEN <> ($this:.B) returnType:kotlin.Unit + overridden: + public abstract fun ff (): kotlin.Unit declared in .I + $this: VALUE_PARAMETER name: type:.B + BLOCK_BODY + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .I + public open fun equals (other: kotlin.Any?): kotlin.Boolean [fake_override,operator] declared in .J + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int [fake_override] declared in .I + public open fun hashCode (): kotlin.Int [fake_override] declared in .J + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String [fake_override] declared in .I + public open fun toString (): kotlin.String [fake_override] declared in .J + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN name:testIntersection visibility:public modality:FINAL <> (a:.A, b:.B) returnType:kotlin.Unit + VALUE_PARAMETER name:a index:0 type:.A + VALUE_PARAMETER name:b index:1 type:.B + BLOCK_BODY + VAR name:v type:.K [val] + WHEN type=.K origin=IF + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'a: .A declared in .testIntersection' type=.A origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: GET_VAR 'b: .B declared in .testIntersection' type=.B origin=null + CALL 'public abstract fun ff (): kotlin.Unit declared in .I' type=kotlin.Unit origin=null + $this: TYPE_OP type=.I origin=IMPLICIT_CAST typeOperand=.I + GET_VAR 'val v: .K [val] declared in .testIntersection' type=.K origin=null + FUN name:testFlexible1 visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + VAR name:v type:.K? [val] + WHEN type=.K? origin=IF + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun a (): .A? declared in .Java' type=.A? origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun b (): .B? declared in .Java' type=.B? origin=null + CALL 'public abstract fun ff (): kotlin.Unit declared in .I' type=kotlin.Unit origin=null + $this: TYPE_OP type=.I origin=IMPLICIT_CAST typeOperand=.I + TYPE_OP type=.K origin=IMPLICIT_NOTNULL typeOperand=.K + GET_VAR 'val v: .K? [val] declared in .testFlexible1' type=.K? origin=null + FUN name:testFlexible2 visibility:public modality:FINAL <> (a:.A, b:.B) returnType:kotlin.Unit + VALUE_PARAMETER name:a index:0 type:.A + VALUE_PARAMETER name:b index:1 type:.B + BLOCK_BODY + VAR name:v type:.K? [val] + WHEN type=.K? origin=IF + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun id (x: T of .Java.id?): T of .Java.id? declared in .Java' type=.A? origin=null + : .A? + x: GET_VAR 'a: .A declared in .testFlexible2' type=.A origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public open fun id (x: T of .Java.id?): T of .Java.id? declared in .Java' type=.B? origin=null + : .B? + x: GET_VAR 'b: .B declared in .testFlexible2' type=.B origin=null + CALL 'public abstract fun ff (): kotlin.Unit declared in .I' type=kotlin.Unit origin=null + $this: TYPE_OP type=.I origin=IMPLICIT_CAST typeOperand=.I + TYPE_OP type=.K origin=IMPLICIT_NOTNULL typeOperand=.K + GET_VAR 'val v: .K? [val] declared in .testFlexible2' type=.K? origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6a2b6f39cfb..961e2a1f24c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -28255,6 +28255,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/traits/privateInterfaceMethod.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/traits/syntheticAccessor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 5d49b7e9c7c..e631ab5d368 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -27072,6 +27072,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/traits/privateInterfaceMethod.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/traits/syntheticAccessor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 6461069bde2..4bce8fb609e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -26754,6 +26754,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/traits/privateInterfaceMethod.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/traits/syntheticAccessor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index ba6e0d7969f..4d1390c5745 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -26754,6 +26754,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/traits/privateInterfaceMethod.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/traits/syntheticAccessor.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 7d97f7bf4b5..edc0b691c3e 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -1881,6 +1881,11 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { runTest("compiler/testData/ir/irText/types/localVariableOfIntersectionType_NI.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/ir/irText/types/receiverOfIntersectionType.kt"); + } + @TestMetadata("smartCastOnFakeOverrideReceiver.kt") public void testSmartCastOnFakeOverrideReceiver() throws Exception { runTest("compiler/testData/ir/irText/types/smartCastOnFakeOverrideReceiver.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 38e2266043b..316e849ce43 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -21740,6 +21740,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/traits/privateInterfaceMethod.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/traits/syntheticAccessor.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 437d49f92cf..3b475930c39 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -21800,6 +21800,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/traits/privateInterfaceMethod.kt"); } + @TestMetadata("receiverOfIntersectionType.kt") + public void testReceiverOfIntersectionType() throws Exception { + runTest("compiler/testData/codegen/box/traits/receiverOfIntersectionType.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/traits/syntheticAccessor.kt");