Support Array::class literal, forbid Array<X>::class on non-JVM

#KT-31230 Fixed
This commit is contained in:
Alexander Udalov
2019-05-02 18:34:20 +02:00
parent 8103f0ba60
commit f38e4d618e
15 changed files with 156 additions and 13 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.resolve.jvm.checkers.*
import org.jetbrains.kotlin.resolve.jvm.multiplatform.JavaActualAnnotationArgumentExtractor
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
import org.jetbrains.kotlin.types.expressions.FunctionWithBigAritySupport
import org.jetbrains.kotlin.types.expressions.GenericArrayClassLiteralSupport
object JvmPlatformConfigurator : PlatformConfiguratorBase(
additionalDeclarationCheckers = listOf(
@@ -103,6 +104,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
container.useImpl<JvmDefaultSuperCallChecker>()
container.useImpl<JvmSamConversionTransformer>()
container.useInstance(FunctionWithBigAritySupport.LanguageVersionDependent)
container.useInstance(GenericArrayClassLiteralSupport.Enabled)
container.useInstance(JavaActualAnnotationArgumentExtractor())
}
@@ -11,8 +11,6 @@ import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.DefaultImplementation
import org.jetbrains.kotlin.container.PlatformExtensionsClashResolver
import org.jetbrains.kotlin.container.PlatformSpecificExtension
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
@@ -47,6 +45,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.resolve.source.toSourceElement
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
import org.jetbrains.kotlin.types.expressions.FunctionWithBigAritySupport.LanguageVersionDependent
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
@@ -88,7 +87,8 @@ class DoubleColonExpressionResolver(
val languageVersionSettings: LanguageVersionSettings,
val additionalCheckers: Iterable<ClassLiteralChecker>,
val dataFlowValueFactory: DataFlowValueFactory,
val bigAritySupport: FunctionWithBigAritySupport
val bigAritySupport: FunctionWithBigAritySupport,
val genericArrayClassLiteralSupport: GenericArrayClassLiteralSupport
) {
private lateinit var expressionTypingServices: ExpressionTypingServices
@@ -141,7 +141,9 @@ class DoubleColonExpressionResolver(
result as DoubleColonLHS.Type
val descriptor = type.constructor.declarationDescriptor
if (result.possiblyBareType.isBare) {
if (descriptor is ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
if (descriptor is ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray(descriptor) &&
!languageVersionSettings.supportsFeature(LanguageFeature.BareArrayClassLiteral)
) {
c.trace.report(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT.on(expression))
}
}
@@ -481,14 +483,15 @@ class DoubleColonExpressionResolver(
}
private fun isAllowedInClassLiteral(type: KotlinType): Boolean {
val typeConstructor = type.constructor
val descriptor = typeConstructor.declarationDescriptor
when (descriptor) {
when (val descriptor = type.constructor.declarationDescriptor) {
is ClassDescriptor -> {
if (KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
return type.arguments.none { typeArgument ->
typeArgument.isStarProjection || !isAllowedInClassLiteral(typeArgument.type)
if (genericArrayClassLiteralSupport.isEnabled ||
!languageVersionSettings.supportsFeature(LanguageFeature.ProhibitGenericArrayClassLiteral)
) {
if (KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
return type.arguments.none { typeArgument ->
typeArgument.isStarProjection || !isAllowedInClassLiteral(typeArgument.type)
}
}
}
@@ -823,7 +826,7 @@ class DoubleColonExpressionResolver(
}
/**
* By default, function types with big arity are supported. On platforms where they are not supported by default (e.g. JVM),
* By default, function types with big arity are enabled. On platforms where they are not supported by default (e.g. JVM),
* [LanguageVersionDependent] should be used which makes the code check if the corresponding language feature is enabled.
*/
@DefaultImplementation(FunctionWithBigAritySupport.Enabled::class)
@@ -837,4 +840,20 @@ interface FunctionWithBigAritySupport {
object LanguageVersionDependent : FunctionWithBigAritySupport {
override val shouldCheckLanguageVersionSettings: Boolean = true
}
}
}
/**
* Generic array class literals (`Array<String>::class.java`) are enabled on all platforms until 1.4, and only on JVM since 1.4.
*/
@DefaultImplementation(GenericArrayClassLiteralSupport.Disabled::class)
interface GenericArrayClassLiteralSupport {
val isEnabled: Boolean
object Enabled : GenericArrayClassLiteralSupport {
override val isEnabled: Boolean = true
}
object Disabled : GenericArrayClassLiteralSupport {
override val isEnabled: Boolean = false
}
}
@@ -0,0 +1,8 @@
// !LANGUAGE: +BareArrayClassLiteral
fun box(): String {
val x = Array(1) { Any() }
if (x::class != Array::class) return "Fail"
return "OK"
}
@@ -0,0 +1,15 @@
// !LANGUAGE: +BareArrayClassLiteral
// TARGET_BACKEND: JVM
// WITH_REFLECT
import kotlin.test.*
import kotlin.reflect.KClass
fun box(): String {
val any = Array<Any>::class
val bare = Array::class
assertEquals<KClass<*>>(any, bare)
return "OK"
}
@@ -0,0 +1,9 @@
// !LANGUAGE: +BareArrayClassLiteral +ProhibitGenericArrayClassLiteral
val a01 = Array::class
val a02 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Array<!>>::class<!>
val a03 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<Any?>::class<!>
val a04 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<Array<Any?>?>::class<!>
val a05 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>Array<IntArray?>::class<!>
val a06 = kotlin.Array::class
val a07 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>kotlin.Array<IntArray?>::class<!>
@@ -0,0 +1,9 @@
package
public val a01: kotlin.reflect.KClass<kotlin.Array<*>>
public val a02: kotlin.reflect.KClass<kotlin.Array<[ERROR : Array]>>
public val a03: kotlin.reflect.KClass<kotlin.Array<kotlin.Any?>>
public val a04: kotlin.reflect.KClass<kotlin.Array<kotlin.Array<kotlin.Any?>?>>
public val a05: kotlin.reflect.KClass<kotlin.Array<kotlin.IntArray?>>
public val a06: kotlin.reflect.KClass<kotlin.Array<*>>
public val a07: kotlin.reflect.KClass<kotlin.Array<kotlin.IntArray?>>
@@ -0,0 +1,7 @@
val a01 = <!ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT!>Array::class<!>
val a02 = Array<<!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Array<!>>::class
val a03 = Array<Any?>::class
val a04 = Array<Array<Any?>?>::class
val a05 = Array<IntArray?>::class
val a06 = <!ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT!>kotlin.Array::class<!>
val a07 = kotlin.Array<IntArray?>::class
@@ -0,0 +1,9 @@
package
public val a01: kotlin.reflect.KClass<kotlin.Array<*>>
public val a02: kotlin.reflect.KClass<kotlin.Array<[ERROR : Array]>>
public val a03: kotlin.reflect.KClass<kotlin.Array<kotlin.Any?>>
public val a04: kotlin.reflect.KClass<kotlin.Array<kotlin.Array<kotlin.Any?>?>>
public val a05: kotlin.reflect.KClass<kotlin.Array<kotlin.IntArray?>>
public val a06: kotlin.reflect.KClass<kotlin.Array<*>>
public val a07: kotlin.reflect.KClass<kotlin.Array<kotlin.IntArray?>>
@@ -59,6 +59,29 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
runTest("compiler/testData/diagnostics/testsWithJsStdLib/wrongMultipleInheritance.kt");
}
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/classLiteral")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ClassLiteral extends AbstractDiagnosticsTestWithJsStdLib {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInClassLiteral() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib/classLiteral"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("arrays_after.kt")
public void testArrays_after() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/classLiteral/arrays_after.kt");
}
@TestMetadata("arrays_before.kt")
public void testArrays_before() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/classLiteral/arrays_before.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2956,6 +2956,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/bareArray.kt");
}
@TestMetadata("primitiveKClassEquality.kt")
public void testPrimitiveKClassEquality() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/primitiveKClassEquality.kt");
@@ -20612,6 +20617,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/classLiterals/arrays.kt");
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/reflection/classLiterals/bareArray.kt");
}
@TestMetadata("builtinClassLiterals.kt")
public void testBuiltinClassLiterals() throws Exception {
runTest("compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt");
@@ -2956,6 +2956,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/bareArray.kt");
}
@TestMetadata("primitiveKClassEquality.kt")
public void testPrimitiveKClassEquality() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/primitiveKClassEquality.kt");
@@ -20612,6 +20617,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/classLiterals/arrays.kt");
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/reflection/classLiterals/bareArray.kt");
}
@TestMetadata("builtinClassLiterals.kt")
public void testBuiltinClassLiterals() throws Exception {
runTest("compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt");
@@ -2936,6 +2936,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/bareArray.kt");
}
@TestMetadata("primitiveKClassEquality.kt")
public void testPrimitiveKClassEquality() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/primitiveKClassEquality.kt");
@@ -19502,6 +19507,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/classLiterals/arrays.kt");
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/reflection/classLiterals/bareArray.kt");
}
@TestMetadata("builtinClassLiterals.kt")
public void testBuiltinClassLiterals() throws Exception {
runTest("compiler/testData/codegen/box/reflection/classLiterals/builtinClassLiterals.kt");
@@ -102,6 +102,8 @@ enum class LanguageFeature(
ProhibitUseSiteTargetAnnotationsOnSuperTypes(KOTLIN_1_4, kind = BUG_FIX),
ProhibitTypeParametersInClassLiteralsInAnnotationArguments(KOTLIN_1_4, kind = BUG_FIX),
ProhibitComparisonOfIncompatibleEnums(KOTLIN_1_4, kind = BUG_FIX),
BareArrayClassLiteral(KOTLIN_1_4),
ProhibitGenericArrayClassLiteral(KOTLIN_1_4),
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
// Temporarily disabled, see KT-27084/KT-22379
@@ -2421,6 +2421,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/bareArray.kt");
}
@TestMetadata("compiler/testData/codegen/box/classLiteral/bound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2421,6 +2421,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classLiteral"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("bareArray.kt")
public void testBareArray() throws Exception {
runTest("compiler/testData/codegen/box/classLiteral/bareArray.kt");
}
@TestMetadata("compiler/testData/codegen/box/classLiteral/bound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)