diff --git a/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt b/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt new file mode 100644 index 00000000000..bd42c295c65 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt @@ -0,0 +1,20 @@ +// WITH_REFLECT + +import kotlin.reflect.withNullability +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals + +fun nonNull(): String = "" +fun nullable(): String? = "" + +fun box(): String { + val nonNull = ::nonNull.returnType + val nullable = ::nullable.returnType + + assertEquals(nullable.javaType, nullable.withNullability(false).javaType) + assertEquals(nullable.javaType, nullable.withNullability(true).javaType) + assertEquals(nonNull.javaType, nonNull.withNullability(false).javaType) + assertEquals(nullable.javaType, nonNull.withNullability(true).javaType) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/types/withNullability.kt b/compiler/testData/codegen/box/reflection/types/withNullability.kt new file mode 100644 index 00000000000..9383fdc5f8c --- /dev/null +++ b/compiler/testData/codegen/box/reflection/types/withNullability.kt @@ -0,0 +1,30 @@ +// WITH_REFLECT +// FILE: J.java + +public interface J { + String platform(); +} + +// FILE: K.kt + +import kotlin.reflect.withNullability +import kotlin.test.assertEquals + +fun nonNull(): String = "" +fun nullable(): String? = "" + +fun box(): String { + val nonNull = ::nonNull.returnType + val nullable = ::nullable.returnType + val platform = J::platform.returnType + + assertEquals(nonNull, nullable.withNullability(false)) + assertEquals(nullable, nullable.withNullability(true)) + assertEquals(nonNull, nonNull.withNullability(false)) + assertEquals(nullable, nonNull.withNullability(true)) + + assertEquals(nonNull, platform.withNullability(false)) + assertEquals(nullable, platform.withNullability(true)) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 992e1d3c689..7d00e44ed24 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12490,6 +12490,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/types/unit.kt"); doTest(fileName); } + + @TestMetadata("withNullability.kt") + public void testWithNullability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/types/withNullability.kt"); + doTest(fileName); + } } } @@ -13056,6 +13062,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("withNullability.kt") + public void testWithNullability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/types/withNullability.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/codegen/box/reflection/types/createType") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/reflection.jvm/src/kotlin/reflect/KTypes.kt b/core/reflection.jvm/src/kotlin/reflect/KTypes.kt new file mode 100644 index 00000000000..07de73844c3 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/KTypes.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("KTypes") +package kotlin.reflect + +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.isFlexible +import kotlin.reflect.jvm.internal.KTypeImpl + +/** + * Returns a new type with the same classifier, arguments and annotations as the given type, and with the given nullability. + */ +fun KType.withNullability(nullable: Boolean): KType { + if (isMarkedNullable) { + return if (nullable) this else KTypeImpl(TypeUtils.makeNotNullable((this as KTypeImpl).type)) { javaType } + } + + // If the type is not marked nullable, it's either a non-null type or a platform type. + val kotlinType = (this as KTypeImpl).type + if (kotlinType.isFlexible()) return KTypeImpl(TypeUtils.makeNullableAsSpecified(kotlinType, nullable)) { javaType } + + return if (!nullable) this else KTypeImpl(TypeUtils.makeNullable(kotlinType)) { javaType } +}