diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index fbeb98410e9..47212e2320b 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -21649,6 +21649,24 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/staticCallErrorMessage.kt"); } + @Test + @TestMetadata("typeParameterWithMixedNullableAndNotNullableBounds.kt") + public void testTypeParameterWithMixedNullableAndNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNotNullableBounds.kt") + public void testTypeParameterWithMultipleNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNullableBounds.kt") + public void testTypeParameterWithMultipleNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java index ba87e6e0869..4f52a8e1307 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/Fir2IrTextTestGenerated.java @@ -2737,6 +2737,24 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { runTest("compiler/testData/ir/irText/types/nullChecks/platformTypeReceiver.kt"); } + @Test + @TestMetadata("typeParameterWithMixedNullableAndNotNullableBounds.kt") + public void testTypeParameterWithMixedNullableAndNotNullableBounds() throws Exception { + runTest("compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNotNullableBounds.kt") + public void testTypeParameterWithMultipleNotNullableBounds() throws Exception { + runTest("compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNullableBounds.kt") + public void testTypeParameterWithMultipleNullableBounds() throws Exception { + runTest("compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt"); + } + @Nested @TestMetadata("compiler/testData/ir/irText/types/nullChecks/nullCheckOnLambdaResult") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt index 8b16bcd27f2..448c862302e 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.types import org.jetbrains.kotlin.builtins.functions.FunctionClassKind import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.name.ClassId @@ -165,8 +166,8 @@ val ConeKotlinType.canBeNull: Boolean return when (this) { is ConeFlexibleType -> upperBound.canBeNull is ConeDefinitelyNotNullType -> false - is ConeTypeParameterType -> this.lookupTag.typeParameterSymbol.fir.bounds.any { it.canBeNull } - is ConeIntersectionType -> intersectedTypes.any { it.canBeNull } + is ConeTypeParameterType -> this.lookupTag.typeParameterSymbol.fir.bounds.all { it.coneType.canBeNull } + is ConeIntersectionType -> intersectedTypes.all { it.canBeNull } else -> isNullable } } @@ -180,4 +181,4 @@ val ConeKotlinType?.functionTypeKind: FunctionClassKind? } val FirResolvedTypeRef.functionTypeKind: FunctionClassKind? - get() = type.functionTypeKind \ No newline at end of file + get() = type.functionTypeKind diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt new file mode 100644 index 00000000000..4dfab0de58d --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt @@ -0,0 +1,26 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM, JVM_IR + +// Note: This fails on non-FIR because of KT-45903 (missing not-null assertion on argument). + +// FILE: typeParameterWithMixedNullableAndNotNullableBounds.kt +fun f(x: T): Int where T : CharSequence?, T : Comparable { + try { + return x.compareTo(x) + } catch (e: NullPointerException) { + return 42 + } +} + +fun box() = try { + val r = f(J.s()) + if (r == 42) "FAIL" else "Unexpected, x.compareTo(x) should have NPE'd" +} catch (e: NullPointerException) { + "OK" +} + + +// FILE: J.java +public class J { + public static String s() { return null; } +} diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt new file mode 100644 index 00000000000..8552a5b4b0f --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt @@ -0,0 +1,22 @@ +// TARGET_BACKEND: JVM +// FILE: typeParameterWithMultipleNotNullableBounds.kt +fun f(x: T): Int where T : CharSequence, T : Comparable { + try { + return x.compareTo(x) + } catch (e: NullPointerException) { + return 42 + } +} + +fun box() = try { + val r = f(J.s()) + if (r == 42) "FAIL" else "Unexpected, x.compareTo(x) should have NPE'd" +} catch (e: NullPointerException) { + "OK" +} + + +// FILE: J.java +public class J { + public static String s() { return null; } +} diff --git a/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt b/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt new file mode 100644 index 00000000000..c4bd58ecccd --- /dev/null +++ b/compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt @@ -0,0 +1,12 @@ +// TARGET_BACKEND: JVM +// FILE: typeParameterWithMultipleNullableBounds.kt +fun f(x: T): Int? where T : CharSequence?, T : Comparable? { + return x?.compareTo(x) +} + +fun box() = f(J.s()) ?: "OK" + +// FILE: J.java +public class J { + public static String s() { return null; } +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.fir.kt.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.fir.kt.txt new file mode 100644 index 00000000000..459eb3b27f9 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.fir.kt.txt @@ -0,0 +1,8 @@ +fun f(x: T): Int where T : CharSequence?, T : Comparable { + return x.compareTo(other = x) +} + +fun test() { + f<@FlexibleNullability String?>(x = s() /*!! @FlexibleNullability String */) /*~> Unit */ + f<@FlexibleNullability String?>(x = #STRING /*!! @FlexibleNullability String */) /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.fir.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.fir.txt new file mode 100644 index 00000000000..59e707f4164 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.fir.txt @@ -0,0 +1,21 @@ +FILE fqName: fileName:/typeParameterWithMixedNullableAndNotNullableBounds.kt + FUN name:f visibility:public modality:FINAL (x:T of .f) returnType:kotlin.Int + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence?; kotlin.Comparable.f>] + VALUE_PARAMETER name:x index:0 type:T of .f + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (x: T of .f): kotlin.Int declared in ' + CALL 'public abstract fun compareTo (other: T of kotlin.Comparable): kotlin.Int [operator] declared in kotlin.Comparable' type=kotlin.Int origin=null + $this: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + other: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: TYPE_OP type=@[FlexibleNullability] kotlin.String origin=IMPLICIT_NOTNULL typeOperand=@[FlexibleNullability] kotlin.String + CALL 'public open fun s (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: TYPE_OP type=@[FlexibleNullability] kotlin.String origin=IMPLICIT_NOTNULL typeOperand=@[FlexibleNullability] kotlin.String + GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:STRING type:@[FlexibleNullability] kotlin.String? visibility:public [static]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt new file mode 100644 index 00000000000..14a74098cb1 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt @@ -0,0 +1,16 @@ +// FILE: typeParameterWithMixedNullableAndNotNullableBounds.kt +fun f(x: T): Int where T : CharSequence?, T : Comparable { + return x.compareTo(x) +} + +fun test() { + f(J.s()) + f(J.STRING) +} + + +// FILE: J.java +public class J { + public static String STRING = s() + public static String s() { return null; } +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt.txt new file mode 100644 index 00000000000..27ce264e226 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt.txt @@ -0,0 +1,8 @@ +fun f(x: T): Int where T : CharSequence?, T : Comparable { + return x.compareTo(other = x) +} + +fun test() { + f<@FlexibleNullability String?>(x = s()) /*~> Unit */ + f<@FlexibleNullability String?>(x = super.#STRING) /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.txt new file mode 100644 index 00000000000..26b059bd966 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.txt @@ -0,0 +1,19 @@ +FILE fqName: fileName:/typeParameterWithMixedNullableAndNotNullableBounds.kt + FUN name:f visibility:public modality:FINAL (x:T of .f) returnType:kotlin.Int + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence?; kotlin.Comparable.f>] + VALUE_PARAMETER name:x index:0 type:T of .f + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (x: T of .f): kotlin.Int declared in ' + CALL 'public abstract fun compareTo (other: T of kotlin.Comparable): kotlin.Int [operator] declared in kotlin.Comparable' type=kotlin.Int origin=null + $this: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + other: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: CALL 'public open fun s (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:STRING type:@[FlexibleNullability] kotlin.String? visibility:public [static]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.fir.kt.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.fir.kt.txt new file mode 100644 index 00000000000..e5bb1f207e2 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.fir.kt.txt @@ -0,0 +1,8 @@ +fun f(x: T): Int where T : CharSequence, T : Comparable { + return x.compareTo(other = x) +} + +fun test() { + f<@FlexibleNullability String?>(x = s() /*!! @FlexibleNullability String */) /*~> Unit */ + f<@FlexibleNullability String?>(x = #STRING /*!! @FlexibleNullability String */) /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.fir.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.fir.txt new file mode 100644 index 00000000000..2817951d04a --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.fir.txt @@ -0,0 +1,21 @@ +FILE fqName: fileName:/typeParameterWithMultipleNotNullableBounds.kt + FUN name:f visibility:public modality:FINAL (x:T of .f) returnType:kotlin.Int + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence; kotlin.Comparable.f>] + VALUE_PARAMETER name:x index:0 type:T of .f + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (x: T of .f): kotlin.Int declared in ' + CALL 'public abstract fun compareTo (other: T of kotlin.Comparable): kotlin.Int [operator] declared in kotlin.Comparable' type=kotlin.Int origin=null + $this: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + other: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: TYPE_OP type=@[FlexibleNullability] kotlin.String origin=IMPLICIT_NOTNULL typeOperand=@[FlexibleNullability] kotlin.String + CALL 'public open fun s (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: TYPE_OP type=@[FlexibleNullability] kotlin.String origin=IMPLICIT_NOTNULL typeOperand=@[FlexibleNullability] kotlin.String + GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:STRING type:@[FlexibleNullability] kotlin.String? visibility:public [static]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt new file mode 100644 index 00000000000..08f0c668869 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt @@ -0,0 +1,16 @@ +// FILE: typeParameterWithMultipleNotNullableBounds.kt +fun f(x: T): Int where T : CharSequence, T : Comparable { + return x.compareTo(x) +} + +fun test() { + f(J.s()) + f(J.STRING) +} + + +// FILE: J.java +public class J { + public static String STRING = s() + public static String s() { return null; } +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt.txt new file mode 100644 index 00000000000..13f3b1f4580 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt.txt @@ -0,0 +1,8 @@ +fun f(x: T): Int where T : CharSequence, T : Comparable { + return x.compareTo(other = x) +} + +fun test() { + f<@FlexibleNullability String?>(x = s()) /*~> Unit */ + f<@FlexibleNullability String?>(x = super.#STRING) /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.txt new file mode 100644 index 00000000000..acbafe111c9 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.txt @@ -0,0 +1,19 @@ +FILE fqName: fileName:/typeParameterWithMultipleNotNullableBounds.kt + FUN name:f visibility:public modality:FINAL (x:T of .f) returnType:kotlin.Int + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence; kotlin.Comparable.f>] + VALUE_PARAMETER name:x index:0 type:T of .f + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (x: T of .f): kotlin.Int declared in ' + CALL 'public abstract fun compareTo (other: T of kotlin.Comparable): kotlin.Int [operator] declared in kotlin.Comparable' type=kotlin.Int origin=null + $this: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + other: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: CALL 'public open fun s (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int declared in ' type=kotlin.Int origin=null + : @[FlexibleNullability] kotlin.String? + x: GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:STRING type:@[FlexibleNullability] kotlin.String? visibility:public [static]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.fir.kt.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.fir.kt.txt new file mode 100644 index 00000000000..390331de46e --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.fir.kt.txt @@ -0,0 +1,14 @@ +fun f(x: T): Int? where T : CharSequence?, T : Comparable? { + return { // BLOCK + val tmp0_safe_receiver: T = x + when { + EQEQ(arg0 = tmp0_safe_receiver, arg1 = null) -> null + else -> tmp0_safe_receiver.compareTo(other = x) + } + } +} + +fun test() { + f<@FlexibleNullability String?>(x = s()) /*~> Unit */ + f<@FlexibleNullability String?>(x = #STRING) /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.fir.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.fir.txt new file mode 100644 index 00000000000..42ecdc1faf2 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.fir.txt @@ -0,0 +1,30 @@ +FILE fqName: fileName:/typeParameterWithMultipleNullableBounds.kt + FUN name:f visibility:public modality:FINAL (x:T of .f) returnType:kotlin.Int? + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence?; kotlin.Comparable.f>?] + VALUE_PARAMETER name:x index:0 type:T of .f + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (x: T of .f): kotlin.Int? declared in ' + BLOCK type=kotlin.Int? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:T of .f [val] + GET_VAR 'x: T of .f declared in .f' type=T of .f 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 tmp_0: T of .f [val] declared in .f' type=T of .f 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 compareTo (other: T of kotlin.Comparable): kotlin.Int [operator] declared in kotlin.Comparable' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp_0: T of .f [val] declared in .f' type=T of .f origin=null + other: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int? declared in ' type=kotlin.Int? origin=null + : @[FlexibleNullability] kotlin.String? + x: CALL 'public open fun s (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int? declared in ' type=kotlin.Int? origin=null + : @[FlexibleNullability] kotlin.String? + x: GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:STRING type:@[FlexibleNullability] kotlin.String? visibility:public [static]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt new file mode 100644 index 00000000000..4a12a76cb9f --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt @@ -0,0 +1,16 @@ +// FILE: typeParameterWithMultipleNullableBounds.kt +fun f(x: T): Int? where T : CharSequence?, T : Comparable? { + return x?.compareTo(x) +} + +fun test() { + f(J.s()) + f(J.STRING) +} + + +// FILE: J.java +public class J { + public static String STRING = s() + public static String s() { return null; } +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt.txt new file mode 100644 index 00000000000..e210d06aec3 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt.txt @@ -0,0 +1,14 @@ +fun f(x: T): Int? where T : CharSequence?, T : Comparable? { + return { // BLOCK + val tmp0_safe_receiver: T = x + when { + EQEQ(arg0 = tmp0_safe_receiver, arg1 = null) -> null + else -> tmp0_safe_receiver.compareTo(other = x) + } + } +} + +fun test() { + f<@FlexibleNullability String?>(x = s()) /*~> Unit */ + f<@FlexibleNullability String?>(x = super.#STRING) /*~> Unit */ +} diff --git a/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.txt b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.txt new file mode 100644 index 00000000000..42ecdc1faf2 --- /dev/null +++ b/compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.txt @@ -0,0 +1,30 @@ +FILE fqName: fileName:/typeParameterWithMultipleNullableBounds.kt + FUN name:f visibility:public modality:FINAL (x:T of .f) returnType:kotlin.Int? + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence?; kotlin.Comparable.f>?] + VALUE_PARAMETER name:x index:0 type:T of .f + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun f (x: T of .f): kotlin.Int? declared in ' + BLOCK type=kotlin.Int? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:T of .f [val] + GET_VAR 'x: T of .f declared in .f' type=T of .f 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 tmp_0: T of .f [val] declared in .f' type=T of .f 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 compareTo (other: T of kotlin.Comparable): kotlin.Int [operator] declared in kotlin.Comparable' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp_0: T of .f [val] declared in .f' type=T of .f origin=null + other: GET_VAR 'x: T of .f declared in .f' type=T of .f origin=null + FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int? declared in ' type=kotlin.Int? origin=null + : @[FlexibleNullability] kotlin.String? + x: CALL 'public open fun s (): @[FlexibleNullability] kotlin.String? declared in .J' type=@[FlexibleNullability] kotlin.String? origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun f (x: T of .f): kotlin.Int? declared in ' type=kotlin.Int? origin=null + : @[FlexibleNullability] kotlin.String? + x: GET_FIELD 'FIELD IR_EXTERNAL_JAVA_DECLARATION_STUB name:STRING type:@[FlexibleNullability] kotlin.String? visibility:public [static]' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 23cf40106af..e272f504839 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -21631,6 +21631,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/staticCallErrorMessage.kt"); } + @Test + @TestMetadata("typeParameterWithMixedNullableAndNotNullableBounds.kt") + public void testTypeParameterWithMixedNullableAndNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNotNullableBounds.kt") + public void testTypeParameterWithMultipleNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNullableBounds.kt") + public void testTypeParameterWithMultipleNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 5aab98bb6d1..7a93883b9bd 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -21649,6 +21649,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/staticCallErrorMessage.kt"); } + @Test + @TestMetadata("typeParameterWithMixedNullableAndNotNullableBounds.kt") + public void testTypeParameterWithMixedNullableAndNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNotNullableBounds.kt") + public void testTypeParameterWithMultipleNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNullableBounds.kt") + public void testTypeParameterWithMultipleNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt"); + } + @Nested @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java index 32e22a487e0..af1d4293eb6 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/ir/IrTextTestGenerated.java @@ -2737,6 +2737,24 @@ public class IrTextTestGenerated extends AbstractIrTextTest { runTest("compiler/testData/ir/irText/types/nullChecks/platformTypeReceiver.kt"); } + @Test + @TestMetadata("typeParameterWithMixedNullableAndNotNullableBounds.kt") + public void testTypeParameterWithMixedNullableAndNotNullableBounds() throws Exception { + runTest("compiler/testData/ir/irText/types/nullChecks/typeParameterWithMixedNullableAndNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNotNullableBounds.kt") + public void testTypeParameterWithMultipleNotNullableBounds() throws Exception { + runTest("compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNotNullableBounds.kt"); + } + + @Test + @TestMetadata("typeParameterWithMultipleNullableBounds.kt") + public void testTypeParameterWithMultipleNullableBounds() throws Exception { + runTest("compiler/testData/ir/irText/types/nullChecks/typeParameterWithMultipleNullableBounds.kt"); + } + @Nested @TestMetadata("compiler/testData/ir/irText/types/nullChecks/nullCheckOnLambdaResult") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a7fcab4ffae..502fc5e398e 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -18025,6 +18025,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/kt24258.kt"); } + @TestMetadata("typeParameterWithMixedNullableAndNotNullableBounds.kt") + public void ignoreTypeParameterWithMixedNullableAndNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMixedNullableAndNotNullableBounds.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -18133,6 +18138,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/staticCallErrorMessage.kt"); } + @TestMetadata("typeParameterWithMultipleNotNullableBounds.kt") + public void testTypeParameterWithMultipleNotNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNotNullableBounds.kt"); + } + + @TestMetadata("typeParameterWithMultipleNullableBounds.kt") + public void testTypeParameterWithMultipleNullableBounds() throws Exception { + runTest("compiler/testData/codegen/box/javaInterop/notNullAssertions/typeParameterWithMultipleNullableBounds.kt"); + } + @TestMetadata("compiler/testData/codegen/box/javaInterop/notNullAssertions/enhancedNullability") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)