diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/parameters/isMarkedNullable.kt b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/isMarkedNullable.kt new file mode 100644 index 00000000000..52009e065e5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/isMarkedNullable.kt @@ -0,0 +1,18 @@ +import kotlin.reflect.* +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class A { + fun foo(p1: String, p2: String?, p3: T, p4: U, p5: U?) { } +} + +fun Any?.ext() {} + +fun box(): String { + val ps = A::class.declaredFunctions.single().parameters.map { it.type.isMarkedNullable } + assertEquals(listOf(false, false, true, false, false, true), ps) + + assertTrue(Any?::ext.parameters.single().type.isMarkedNullable) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 28cd9799b52..f005b89c563 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3228,6 +3228,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("isMarkedNullable.kt") + public void testIsMarkedNullable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters/isMarkedNullable.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("propertySetter.kt") public void testPropertySetter() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters/propertySetter.kt"); diff --git a/core/builtins/src/kotlin/reflect/KParameter.kt b/core/builtins/src/kotlin/reflect/KParameter.kt index 552bee4da25..c5f60a6a473 100644 --- a/core/builtins/src/kotlin/reflect/KParameter.kt +++ b/core/builtins/src/kotlin/reflect/KParameter.kt @@ -34,4 +34,9 @@ public interface KParameter { * compiled without the debug information, and others. */ public val name: String? + + /** + * Type of this parameter. + */ + public val type: KType } diff --git a/core/builtins/src/kotlin/reflect/KType.kt b/core/builtins/src/kotlin/reflect/KType.kt new file mode 100644 index 00000000000..9875e0fe5f4 --- /dev/null +++ b/core/builtins/src/kotlin/reflect/KType.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2015 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. + */ + +package kotlin.reflect + +/** + * Represents a type. Type is usually either a class with optional type arguments, + * or a type parameter of some declaration, plus nullability. + */ +public interface KType { + /** + * `true` if this type was marked nullable in the source code. + * + * For Kotlin types, it means that `null` value is allowed to be represented by this type. + * In practice it means that the type was declared with a question mark at the end. + * For non-Kotlin types, it means the type or the symbol which was declared with this type + * is annotated with a runtime-retained nullability annotation such as [javax.annotation.Nullable]. + * + * Note that even if [isMarkedNullable] is false, values of the type can still be `null`. + * This may happen if it is a type of the type parameter with a nullable upper bound: + * + * ``` + * fun foo(t: T) { + * // isMarkedNullable == false for t's type, but t can be null here + * } + * ``` + */ + public val isMarkedNullable: Boolean +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt index 517d387055c..58344eedbf6 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KParameterImpl.kt @@ -19,6 +19,7 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import kotlin.reflect.KParameter +import kotlin.reflect.KType class KParameterImpl( override val index: Int, @@ -32,4 +33,7 @@ class KParameterImpl( val name = valueParameter.name return if (name.isSpecial) null else name.asString() } + + override val type: KType + get() = KTypeImpl(descriptor.getType()) } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt new file mode 100644 index 00000000000..8c22b4d6909 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTypeImpl.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2015 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. + */ + +package kotlin.reflect.jvm.internal + +import org.jetbrains.kotlin.types.JetType +import kotlin.reflect.KType + +class KTypeImpl(val type: JetType) : KType { + override val isMarkedNullable: Boolean + get() = type.isMarkedNullable +}