From 6c0cd70a22200ab195ea1de2962d08e84f6c4ca0 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 21 Jan 2016 19:09:46 +0300 Subject: [PATCH] Introduce PureReifiable annotation It prevents reporting unsafe substitution warning on expressions like 'arrayOf(arrayOf(""))' --- build.xml | 3 -- ...ifiedTypeParameterSubstitutionChecker.java | 9 ++++- compiler/testData/builtin-classes-kotlin.txt | 8 ++--- .../commonSystem/theSameFunctionInArgs.kt | 2 +- .../testsWithStdLib/pureReifiable.kt | 12 +++++++ .../testsWithStdLib/pureReifiable.txt | 4 +++ .../pureReifiableArrayOperations.kt | 18 ++++++++++ .../pureReifiableArrayOperations.txt | 3 ++ .../DiagnosticsTestWithStdLibGenerated.java | 12 +++++++ core/builtins/native/kotlin/Library.kt | 4 ++- core/builtins/src/kotlin/ArrayIntrinsics.kt | 8 +++-- .../kotlin/internal/InternalAnnotations.kt | 25 +++++++++++++ .../kotlin/builtins/KotlinBuiltIns.java | 3 +- .../decompiler/builtIns/kotlin_package.stubs | 36 +++++++++++++++++++ .../decompiler/builtIns/kotlin_package.text | 8 ++--- libraries/tools/runtime/pom.xml | 3 -- 16 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/pureReifiable.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/pureReifiable.txt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.txt create mode 100644 core/builtins/src/kotlin/internal/InternalAnnotations.kt diff --git a/build.xml b/build.xml index 037b520e17b..c897734128d 100644 --- a/build.xml +++ b/build.xml @@ -489,7 +489,6 @@ - @@ -954,7 +953,6 @@ - @@ -1106,7 +1104,6 @@ - diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReifiedTypeParameterSubstitutionChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReifiedTypeParameterSubstitutionChecker.java index c01becf7d95..a977a99a61b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReifiedTypeParameterSubstitutionChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/ReifiedTypeParameterSubstitutionChecker.java @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.diagnostics.Errors; +import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; @@ -53,7 +54,7 @@ public class ReifiedTypeParameterSubstitutionChecker implements CallChecker { context.trace.report( Errors.REIFIED_TYPE_FORBIDDEN_SUBSTITUTION.on(getElementToReport(context, parameter.getIndex()), argument)); } - else if (TypeUtilsKt.unsafeAsReifiedArgument(argument)) { + else if (TypeUtilsKt.unsafeAsReifiedArgument(argument) && !hasPureReifiableAnnotation(parameter)) { context.trace.report( Errors.REIFIED_TYPE_UNSAFE_SUBSTITUTION.on(getElementToReport(context, parameter.getIndex()), argument)); } @@ -61,6 +62,12 @@ public class ReifiedTypeParameterSubstitutionChecker implements CallChecker { } } + private static final FqName PURE_REIFIABLE_ANNOTATION_FQ_NAME = new FqName("kotlin.internal.PureReifiable"); + + private static boolean hasPureReifiableAnnotation(@NotNull TypeParameterDescriptor parameter) { + return parameter.getAnnotations().hasAnnotation(PURE_REIFIABLE_ANNOTATION_FQ_NAME); + } + @NotNull private static PsiElement getElementToReport(@NotNull BasicCallResolutionContext context, int parameterIndex) { if (context.call.getTypeArguments().size() > parameterIndex) { diff --git a/compiler/testData/builtin-classes-kotlin.txt b/compiler/testData/builtin-classes-kotlin.txt index 58b75d8943d..36c27ecf1db 100644 --- a/compiler/testData/builtin-classes-kotlin.txt +++ b/compiler/testData/builtin-classes-kotlin.txt @@ -1,6 +1,6 @@ package-fragment kotlin -public inline fun Array(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.Array +public inline fun Array(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.Array public inline fun BooleanArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.BooleanArray public inline fun ByteArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.ByteArray public inline fun CharArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.CharArray @@ -9,13 +9,13 @@ public inline fun FloatArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function public inline fun IntArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.IntArray public inline fun LongArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.LongArray public inline fun ShortArray(/*0*/ size: kotlin.Int, /*1*/ init: kotlin.Function1): kotlin.ShortArray -public inline fun arrayOf(/*0*/ vararg elements: T /*kotlin.Array*/): kotlin.Array -public fun arrayOfNulls(/*0*/ size: kotlin.Int): kotlin.Array +public inline fun arrayOf(/*0*/ vararg elements: T /*kotlin.Array*/): kotlin.Array +public fun arrayOfNulls(/*0*/ size: kotlin.Int): kotlin.Array public fun booleanArrayOf(/*0*/ vararg elements: kotlin.Boolean /*kotlin.BooleanArray*/): kotlin.BooleanArray public fun byteArrayOf(/*0*/ vararg elements: kotlin.Byte /*kotlin.ByteArray*/): kotlin.ByteArray public fun charArrayOf(/*0*/ vararg elements: kotlin.Char /*kotlin.CharArray*/): kotlin.CharArray public fun doubleArrayOf(/*0*/ vararg elements: kotlin.Double /*kotlin.DoubleArray*/): kotlin.DoubleArray -public inline fun emptyArray(): kotlin.Array +public inline fun emptyArray(): kotlin.Array public fun floatArrayOf(/*0*/ vararg elements: kotlin.Float /*kotlin.FloatArray*/): kotlin.FloatArray public fun intArrayOf(/*0*/ vararg elements: kotlin.Int /*kotlin.IntArray*/): kotlin.IntArray public fun longArrayOf(/*0*/ vararg elements: kotlin.Long /*kotlin.LongArray*/): kotlin.LongArray diff --git a/compiler/testData/diagnostics/tests/inference/commonSystem/theSameFunctionInArgs.kt b/compiler/testData/diagnostics/tests/inference/commonSystem/theSameFunctionInArgs.kt index c68b5b9c953..ee5966fe5f2 100644 --- a/compiler/testData/diagnostics/tests/inference/commonSystem/theSameFunctionInArgs.kt +++ b/compiler/testData/diagnostics/tests/inference/commonSystem/theSameFunctionInArgs.kt @@ -1,6 +1,6 @@ // !CHECK_TYPE fun test() { - val array = arrayOf(arrayOf(1)) + val array = arrayOf(arrayOf(1)) array checkType { _>>() } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/pureReifiable.kt b/compiler/testData/diagnostics/testsWithStdLib/pureReifiable.kt new file mode 100644 index 00000000000..648e86cbe34 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/pureReifiable.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +inline fun foo(x: T) {} + +fun test() { + foo>(listOf("")) + foo(listOf("")) + + foo>(arrayOf("")) + foo(arrayOf("")) +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/pureReifiable.txt b/compiler/testData/diagnostics/testsWithStdLib/pureReifiable.txt new file mode 100644 index 00000000000..60737b9165f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/pureReifiable.txt @@ -0,0 +1,4 @@ +package + +@kotlin.Suppress(names = {"INVISIBLE_MEMBER", "INVISIBLE_REFERENCE"}) public inline fun foo(/*0*/ x: T): kotlin.Unit +public fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.kt b/compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.kt new file mode 100644 index 00000000000..57cad51a93e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.kt @@ -0,0 +1,18 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + +fun test() { + arrayOf>(listOf("")) + arrayOf(listOf("")) + + arrayOf>(arrayOf("")) + arrayOf(arrayOf("")) + + arrayOfNulls>(1) + + Array>(1) { arrayOf("") } + Array(1) { arrayOf("") } + Array(1) { arrayOf("") } + + emptyArray>() + val x: Array> = emptyArray() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.txt b/compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.txt new file mode 100644 index 00000000000..93e27f34c8c --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.txt @@ -0,0 +1,3 @@ +package + +public fun test(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 2a517c313ef..0930f8f302e 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -125,6 +125,18 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("pureReifiable.kt") + public void testPureReifiable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/pureReifiable.kt"); + doTest(fileName); + } + + @TestMetadata("pureReifiableArrayOperations.kt") + public void testPureReifiableArrayOperations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/pureReifiableArrayOperations.kt"); + doTest(fileName); + } + @TestMetadata("RedeclarationMainInMultiFileClass.kt") public void testRedeclarationMainInMultiFileClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/RedeclarationMainInMultiFileClass.kt"); diff --git a/core/builtins/native/kotlin/Library.kt b/core/builtins/native/kotlin/Library.kt index 217a6e5ffe2..a37edfd2c0b 100644 --- a/core/builtins/native/kotlin/Library.kt +++ b/core/builtins/native/kotlin/Library.kt @@ -16,6 +16,8 @@ package kotlin +import kotlin.internal.PureReifiable + /** * Returns a string representation of the object. Can be called with a null receiver, in which case * it returns the string "null". @@ -31,4 +33,4 @@ public operator fun String?.plus(other: Any?): String /** * Returns an array of objects of the given type with the given [size], initialized with null values. */ -public fun arrayOfNulls(size: Int): Array +public fun arrayOfNulls(size: Int): Array diff --git a/core/builtins/src/kotlin/ArrayIntrinsics.kt b/core/builtins/src/kotlin/ArrayIntrinsics.kt index ec75c2b5bf8..0d21ccff3da 100644 --- a/core/builtins/src/kotlin/ArrayIntrinsics.kt +++ b/core/builtins/src/kotlin/ArrayIntrinsics.kt @@ -16,11 +16,13 @@ package kotlin +import kotlin.internal.PureReifiable + /** * Returns an array with the specified [size], where each element is calculated by calling the specified * [init] function. The `init` function returns an array element given its index. */ -public inline fun Array(size: Int, init: (Int) -> T): Array { +public inline fun Array(size: Int, init: (Int) -> T): Array { val result = arrayOfNulls(size) for (i in 0..size - 1) result[i] = init(i) @@ -126,14 +128,14 @@ public inline fun BooleanArray(size: Int, init: (Int) -> Boolean): BooleanArray /** * Returns an empty array of the specified type [T]. */ -public inline fun emptyArray(): Array = arrayOfNulls(0) as Array +public inline fun emptyArray(): Array = arrayOfNulls(0) as Array // Array "constructor" /** * Returns an array containing the specified elements. */ -public inline fun arrayOf(vararg elements: T) : Array = elements as Array +public inline fun arrayOf(vararg elements: T) : Array = elements as Array // "constructors" for primitive types array /** diff --git a/core/builtins/src/kotlin/internal/InternalAnnotations.kt b/core/builtins/src/kotlin/internal/InternalAnnotations.kt new file mode 100644 index 00000000000..f9ff5125a86 --- /dev/null +++ b/core/builtins/src/kotlin/internal/InternalAnnotations.kt @@ -0,0 +1,25 @@ +/* + * 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. + */ + +package kotlin.internal + +/** + * Specifies that the corresponding type parameter is not used for unsafe operations such as casts or 'is' checks + * That means it's completely safe to use generic types as argument for such parameter. + */ +@Target(AnnotationTarget.TYPE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +internal annotation class PureReifiable diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index c81f23fcce5..6416a374dc9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -58,7 +58,8 @@ public abstract class KotlinBuiltIns { COLLECTIONS_PACKAGE_FQ_NAME, RANGES_PACKAGE_FQ_NAME, ANNOTATION_PACKAGE_FQ_NAME, - ReflectionTypesKt.getKOTLIN_REFLECT_FQ_NAME() + ReflectionTypesKt.getKOTLIN_REFLECT_FQ_NAME(), + BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier("internal")) ); protected final ModuleDescriptorImpl builtInsModule; diff --git a/idea/testData/decompiler/builtIns/kotlin_package.stubs b/idea/testData/decompiler/builtIns/kotlin_package.stubs index d883e2cd942..6f05dd3f3f5 100644 --- a/idea/testData/decompiler/builtIns/kotlin_package.stubs +++ b/idea/testData/decompiler/builtIns/kotlin_package.stubs @@ -7,6 +7,15 @@ PsiJetFileStubImpl[package=kotlin] TYPE_PARAMETER_LIST: TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=T] MODIFIER_LIST:[reified] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=PureReifiable] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=kotlin] + REFERENCE_EXPRESSION:[referencedName=internal] + REFERENCE_EXPRESSION:[referencedName=PureReifiable] VALUE_PARAMETER_LIST: VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=size] TYPE_REFERENCE: @@ -274,6 +283,15 @@ PsiJetFileStubImpl[package=kotlin] TYPE_PARAMETER_LIST: TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=T] MODIFIER_LIST:[reified] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=PureReifiable] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=kotlin] + REFERENCE_EXPRESSION:[referencedName=internal] + REFERENCE_EXPRESSION:[referencedName=PureReifiable] VALUE_PARAMETER_LIST: VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=elements] MODIFIER_LIST:[vararg] @@ -295,6 +313,15 @@ PsiJetFileStubImpl[package=kotlin] TYPE_PARAMETER_LIST: TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=T] MODIFIER_LIST:[reified] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=PureReifiable] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=kotlin] + REFERENCE_EXPRESSION:[referencedName=internal] + REFERENCE_EXPRESSION:[referencedName=PureReifiable] VALUE_PARAMETER_LIST: VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=size] TYPE_REFERENCE: @@ -378,6 +405,15 @@ PsiJetFileStubImpl[package=kotlin] TYPE_PARAMETER_LIST: TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=T] MODIFIER_LIST:[reified] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=PureReifiable] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=kotlin] + REFERENCE_EXPRESSION:[referencedName=internal] + REFERENCE_EXPRESSION:[referencedName=PureReifiable] VALUE_PARAMETER_LIST: TYPE_REFERENCE: USER_TYPE:[isAbsoluteInRootPackage=false] diff --git a/idea/testData/decompiler/builtIns/kotlin_package.text b/idea/testData/decompiler/builtIns/kotlin_package.text index f1847db3e14..d5172790b88 100644 --- a/idea/testData/decompiler/builtIns/kotlin_package.text +++ b/idea/testData/decompiler/builtIns/kotlin_package.text @@ -3,7 +3,7 @@ package kotlin -public inline fun Array(size: kotlin.Int, init: (kotlin.Int) -> T): kotlin.Array { /* compiled code */ } +public inline fun Array(size: kotlin.Int, init: (kotlin.Int) -> T): kotlin.Array { /* compiled code */ } public inline fun BooleanArray(size: kotlin.Int, init: (kotlin.Int) -> kotlin.Boolean): kotlin.BooleanArray { /* compiled code */ } @@ -21,9 +21,9 @@ public inline fun LongArray(size: kotlin.Int, init: (kotlin.Int) -> kotlin.Long) public inline fun ShortArray(size: kotlin.Int, init: (kotlin.Int) -> kotlin.Short): kotlin.ShortArray { /* compiled code */ } -public inline fun arrayOf(vararg elements: T): kotlin.Array { /* compiled code */ } +public inline fun arrayOf(vararg elements: T): kotlin.Array { /* compiled code */ } -public fun arrayOfNulls(size: kotlin.Int): kotlin.Array { /* compiled code */ } +public fun arrayOfNulls(size: kotlin.Int): kotlin.Array { /* compiled code */ } public fun booleanArrayOf(vararg elements: kotlin.Boolean): kotlin.BooleanArray { /* compiled code */ } @@ -33,7 +33,7 @@ public fun charArrayOf(vararg elements: kotlin.Char): kotlin.CharArray { /* comp public fun doubleArrayOf(vararg elements: kotlin.Double): kotlin.DoubleArray { /* compiled code */ } -public inline fun emptyArray(): kotlin.Array { /* compiled code */ } +public inline fun emptyArray(): kotlin.Array { /* compiled code */ } public fun floatArrayOf(vararg elements: kotlin.Float): kotlin.FloatArray { /* compiled code */ } diff --git a/libraries/tools/runtime/pom.xml b/libraries/tools/runtime/pom.xml index 6f42590feb1..da587cd5dda 100644 --- a/libraries/tools/runtime/pom.xml +++ b/libraries/tools/runtime/pom.xml @@ -24,9 +24,6 @@ **/*.kotlin_* - - kotlin/internal/**/* -