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:
Alexander Udalov
2018-06-27 19:41:13 +02:00
parent 56f509ba09
commit dcbb8045bd
25 changed files with 164 additions and 1 deletions
@@ -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)
}
}
@@ -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
)
)
}
}
}
@@ -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,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,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,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
@@ -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)
}
@@ -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
}
@@ -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");
@@ -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");
@@ -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");
@@ -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),
@@ -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
@@ -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");
@@ -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");