Disallow function types with big arity on JVM if LV < 1.3 or API < 1.3
The implementation is a bit obscure because this worked on JS since Kotlin 1.0 and we should not break that; however, on JVM, a diagnostic will be reported with old language/API version #KT-25241 Fixed
This commit is contained in:
+4
@@ -24,11 +24,13 @@ import org.jetbrains.kotlin.load.java.sam.JvmSamConversionTransformer
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConversionResolverImpl
|
||||
import org.jetbrains.kotlin.resolve.PlatformConfigurator
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.BigFunctionTypeAvailabilityChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.jvm.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.checkers.*
|
||||
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
|
||||
import org.jetbrains.kotlin.types.DynamicTypesSettings
|
||||
import org.jetbrains.kotlin.types.expressions.FunctionWithBigAritySupport
|
||||
|
||||
object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
DynamicTypesSettings(),
|
||||
@@ -67,6 +69,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
),
|
||||
|
||||
additionalClassifierUsageCheckers = listOf(
|
||||
BigFunctionTypeAvailabilityChecker
|
||||
),
|
||||
|
||||
additionalAnnotationCheckers = listOf(
|
||||
@@ -100,5 +103,6 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
container.useInstance(JvmTypeSpecificityComparator)
|
||||
container.useImpl<JvmDefaultSuperCallChecker>()
|
||||
container.useImpl<JvmSamConversionTransformer>()
|
||||
container.useInstance(FunctionWithBigAritySupport.LANGUAGE_VERSION_DEPENDENT)
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
object BigFunctionTypeAvailabilityChecker : ClassifierUsageChecker {
|
||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.FunctionTypesWithBigArity)) return
|
||||
|
||||
if (targetDescriptor.defaultType.contains { argumentType ->
|
||||
val descriptor = argumentType.constructor.declarationDescriptor
|
||||
descriptor is FunctionClassDescriptor && descriptor.hasBigArity
|
||||
}) {
|
||||
context.trace.report(
|
||||
Errors.UNSUPPORTED_FEATURE.on(
|
||||
element, LanguageFeature.FunctionTypesWithBigArity to context.languageVersionSettings
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-1
@@ -7,12 +7,15 @@ package org.jetbrains.kotlin.types.expressions
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
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.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -84,7 +87,8 @@ class DoubleColonExpressionResolver(
|
||||
val typeResolver: TypeResolver,
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
val additionalCheckers: Iterable<ClassLiteralChecker>,
|
||||
val dataFlowValueFactory: DataFlowValueFactory
|
||||
val dataFlowValueFactory: DataFlowValueFactory,
|
||||
val bigAritySupport: FunctionWithBigAritySupport
|
||||
) {
|
||||
private lateinit var expressionTypingServices: ExpressionTypingServices
|
||||
|
||||
@@ -592,6 +596,15 @@ class DoubleColonExpressionResolver(
|
||||
)
|
||||
|
||||
context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor)
|
||||
|
||||
if (functionDescriptor.valueParameters.size >= FunctionInvokeDescriptor.BIG_ARITY &&
|
||||
bigAritySupport.shouldCheckLanguageVersionSettings &&
|
||||
!languageVersionSettings.supportsFeature(LanguageFeature.FunctionTypesWithBigArity)
|
||||
) {
|
||||
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(
|
||||
expression, LanguageFeature.FunctionTypesWithBigArity to languageVersionSettings
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun bindPropertyReference(
|
||||
@@ -796,3 +809,15 @@ class DoubleColonExpressionResolver(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// By default, function types with big arity are supported. On platforms where they are not supported by default (e.g. JVM),
|
||||
// LANGUAGE_VERSION_DEPENDENT should be used which makes the code check if the corresponding language feature is enabled.
|
||||
@DefaultImplementation(FunctionWithBigAritySupport::class)
|
||||
class FunctionWithBigAritySupport private constructor(val shouldCheckLanguageVersionSettings: Boolean) {
|
||||
constructor() : this(false)
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val LANGUAGE_VERSION_DEPENDENT = FunctionWithBigAritySupport(true)
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
|
||||
class A(val value: Int) {
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JS_IR, JS
|
||||
|
||||
class A
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A
|
||||
|
||||
fun foo(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A(val value: Int)
|
||||
|
||||
private fun check(actual: A, expected: Int) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// WITH_RUNTIME
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: J.java
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// !LANGUAGE: -FunctionTypesWithBigArity
|
||||
|
||||
// This test does not make sense for JVM because a diagnostic is reported when function types with big arity are not available
|
||||
// (see diagnostics/tests/sourceCompatibility/noBigFunctionTypes.kt)
|
||||
// IGNORE_BACKEND: JVM
|
||||
|
||||
class A
|
||||
|
||||
fun foo(
|
||||
p00: A, p01: A, p02: A, p03: A, p04: A, p05: A, p06: A, p07: A, p08: A, p09: A,
|
||||
p10: A, p11: A, p12: A, p13: A, p14: A, p15: A, p16: A, p17: A, p18: A, p19: A,
|
||||
p20: A, p21: A, p22: A, p23: A, p24: A, p25: A, p26: A, p27: A, p28: A, p29: A
|
||||
): String = "OK"
|
||||
|
||||
fun bar(x: Function30<A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, String>): String {
|
||||
val a = A()
|
||||
return x(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return bar(::foo)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
// Implementing function interface is prohibited in JavaScript
|
||||
// IGNORE_BACKEND: JS_IR, JS
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: Test.java
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JS_IR, JS, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: -FunctionTypesWithBigArity
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
class A
|
||||
|
||||
fun foo(
|
||||
p00: A, p01: A, p02: A, p03: A, p04: A, p05: A, p06: A, p07: A, p08: A, p09: A,
|
||||
p10: A, p11: A, p12: A, p13: A, p14: A, p15: A, p16: A, p17: A, p18: A, p19: A,
|
||||
p20: A, p21: A, p22: A, p23: A, p24: A, p25: A, p26: A, p27: A, p28: A, p29: A
|
||||
) {}
|
||||
|
||||
fun bar(x: Any) {}
|
||||
|
||||
fun test(vararg x: <!UNSUPPORTED_FEATURE!>Function30<!><*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, Unit>) {
|
||||
bar(<!UNSUPPORTED_FEATURE!>::foo<!>)
|
||||
bar(x)
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ x: kotlin.Any): kotlin.Unit
|
||||
public fun foo(/*0*/ p00: A, /*1*/ p01: A, /*2*/ p02: A, /*3*/ p03: A, /*4*/ p04: A, /*5*/ p05: A, /*6*/ p06: A, /*7*/ p07: A, /*8*/ p08: A, /*9*/ p09: A, /*10*/ p10: A, /*11*/ p11: A, /*12*/ p12: A, /*13*/ p13: A, /*14*/ p14: A, /*15*/ p15: A, /*16*/ p16: A, /*17*/ p17: A, /*18*/ p18: A, /*19*/ p19: A, /*20*/ p20: A, /*21*/ p21: A, /*22*/ p22: A, /*23*/ p23: A, /*24*/ p24: A, /*25*/ p25: A, /*26*/ p26: A, /*27*/ p27: A, /*28*/ p28: A, /*29*/ p29: A): kotlin.Unit
|
||||
public fun test(/*0*/ vararg x: kotlin.Function30<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, kotlin.Unit> /*kotlin.Array<out kotlin.Function30<*, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, *, kotlin.Unit>>*/): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
public constructor A()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Generated
+5
@@ -10317,6 +10317,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("subclass.kt")
|
||||
public void testSubclass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt");
|
||||
|
||||
@@ -20427,6 +20427,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/sourceCompatibility/inlineFunctionAlways.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sourceCompatibility/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noCallableReferencesWithEmptyLHS.kt")
|
||||
public void testNoCallableReferencesWithEmptyLHS() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sourceCompatibility/noCallableReferencesWithEmptyLHS.kt");
|
||||
|
||||
Generated
+5
@@ -20427,6 +20427,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/sourceCompatibility/inlineFunctionAlways.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sourceCompatibility/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noCallableReferencesWithEmptyLHS.kt")
|
||||
public void testNoCallableReferencesWithEmptyLHS() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sourceCompatibility/noCallableReferencesWithEmptyLHS.kt");
|
||||
|
||||
+5
@@ -10317,6 +10317,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/javaLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("subclass.kt")
|
||||
public void testSubclass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt");
|
||||
|
||||
+5
@@ -10279,6 +10279,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class BigArity extends AbstractLightAnalysisModeTest {
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void ignoreNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ enum class LanguageFeature(
|
||||
ProhibitSmartcastsOnLocalDelegatedProperty(KOTLIN_1_3, kind = BUG_FIX),
|
||||
ProhibitOperatorMod(KOTLIN_1_3, kind = BUG_FIX),
|
||||
ProhibitAssigningSingleElementsToVarargsInNamedForm(KOTLIN_1_3, kind = BUG_FIX),
|
||||
FunctionTypesWithBigArity(KOTLIN_1_3, sinceApiVersion = ApiVersion.KOTLIN_1_3),
|
||||
|
||||
StrictJavaNullabilityAssertions(sinceVersion = null, defaultState = State.DISABLED),
|
||||
ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED),
|
||||
|
||||
+4
@@ -73,6 +73,10 @@ class FunctionClassDescriptor(
|
||||
parameters = result.toList()
|
||||
}
|
||||
|
||||
@get:JvmName("hasBigArity")
|
||||
val hasBigArity: Boolean
|
||||
get() = arity >= FunctionInvokeDescriptor.BIG_ARITY
|
||||
|
||||
override fun getContainingDeclaration() = containingDeclaration
|
||||
|
||||
override fun getStaticScope() = MemberScope.Empty
|
||||
|
||||
+5
@@ -8967,6 +8967,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("subclass.kt")
|
||||
public void testSubclass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt");
|
||||
|
||||
+5
@@ -9962,6 +9962,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/invokeLambda.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noBigFunctionTypes.kt")
|
||||
public void testNoBigFunctionTypes() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/noBigFunctionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("subclass.kt")
|
||||
public void testSubclass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/functions/bigArity/subclass.kt");
|
||||
|
||||
Reference in New Issue
Block a user