From 07269661b4a75a8ddf714592de7761218077ff08 Mon Sep 17 00:00:00 2001 From: Victor Petukhov Date: Wed, 4 Dec 2019 20:29:03 +0300 Subject: [PATCH] NI: Allow to resolve to functions with SAM conversion and passing array without spread as vararg (with warning) ^KT-35224 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 15 ++++++ .../kotlin/synthetic/JavaSyntheticScopes.kt | 11 ++-- .../synthetic/SamAdapterFunctionsScope.kt | 49 +++++++++++------ .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../DiagnosticReporterByTrackingStrategy.kt | 4 ++ .../calls/components/KotlinCallCompleter.kt | 19 +++++++ .../calls/components/ResolutionParts.kt | 6 ++- .../calls/model/KotlinCallDiagnostics.kt | 8 ++- .../resolve/calls/tower/ImplicitScopeTower.kt | 1 + .../box/sam/arrayAsVarargAfterSamArgument.kt | 53 ++++++++++++++++++ ...rgumentWithoutSamConversionsPerArgument.kt | 41 ++++++++++++++ .../generic/dependOnArgumentType.kt | 2 +- .../arrayAsVarargAfterSamArgument.kt | 54 +++++++++++++++++++ ...arrayAsVarargAfterSamArgumentProhibited.kt | 54 +++++++++++++++++++ ...rgumentWithoutSamConversionsPerArgument.kt | 54 +++++++++++++++++++ .../samConversionInGenericConstructorCall.kt | 2 +- ...amConversionInGenericConstructorCall_NI.kt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 15 ++++++ .../DiagnosticsUsingJavacTestGenerated.java | 15 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 ++++ .../LightAnalysisModeTestGenerated.java | 10 ++++ .../ir/FirBlackBoxCodegenTestGenerated.java | 10 ++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 ++++ .../kotlin/config/LanguageVersionSettings.kt | 1 + .../RedundantSamConstructorInspection.kt | 8 +-- ...dSpreadOperatorForArrayAsVarargAfterSam.kt | 36 +++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 1 + .../withError.test | 21 ++++++++ .../withWarning.test | 27 ++++++++++ .../withoutWarning.test | 18 +++++++ .../QuickFixMultiFileTestGenerated.java | 28 ++++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 13 +++++ 33 files changed, 573 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt create mode 100644 compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt create mode 100644 compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt create mode 100644 compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt create mode 100644 compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/AddSpreadOperatorForArrayAsVarargAfterSam.kt create mode 100644 idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withError.test create mode 100644 idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withWarning.test create mode 100644 idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withoutWarning.test diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 3781ab6db50..ea1fc8948c2 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -18603,6 +18603,21 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/samConversions"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentProhibited.kt") + public void testArrayAsVarargAfterSamArgumentProhibited() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("checkSamConversionsAreDisabledByDefault.kt") public void testCheckSamConversionsAreDisabledByDefault() throws Exception { runTest("compiler/testData/diagnostics/tests/samConversions/checkSamConversionsAreDisabledByDefault.kt"); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt index 914dea47fd4..96b595b2cd8 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/JavaSyntheticScopes.kt @@ -46,7 +46,8 @@ class JavaSyntheticScopes( init { val samConversionPerArgumentIsEnabled = - languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) + languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) && + languageVersionSettings.supportsFeature(LanguageFeature.ProhibitVarargAsArrayAfterSamArgument) val javaSyntheticPropertiesScope = JavaSyntheticPropertiesScope(storageManager, lookupTracker) val scopesFromExtensions = SyntheticScopeProviderExtension @@ -59,7 +60,10 @@ class JavaSyntheticScopes( samConventionResolver, deprecationResolver, lookupTracker, - samViaSyntheticScopeDisabled = samConversionPerArgumentIsEnabled + samViaSyntheticScopeDisabled = samConversionPerArgumentIsEnabled, + shouldGenerateCandidateForVarargAfterSam = !languageVersionSettings.supportsFeature( + LanguageFeature.ProhibitVarargAsArrayAfterSamArgument + ) ) scopes = listOf(javaSyntheticPropertiesScope, samAdapterFunctionsScope) + scopesFromExtensions @@ -70,7 +74,8 @@ class JavaSyntheticScopes( samConventionResolver, deprecationResolver, lookupTracker, - samViaSyntheticScopeDisabled = false + samViaSyntheticScopeDisabled = false, + shouldGenerateCandidateForVarargAfterSam = false ) scopesWithForceEnabledSamAdapters = diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt index fcdb97f46b8..04065a1dd50 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt @@ -17,8 +17,6 @@ package org.jetbrains.kotlin.synthetic import com.intellij.util.SmartList -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl @@ -37,6 +35,7 @@ import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -58,8 +57,10 @@ class SamAdapterFunctionsScope( private val samResolver: SamConversionResolver, private val deprecationResolver: DeprecationResolver, private val lookupTracker: LookupTracker, - private val samViaSyntheticScopeDisabled: Boolean + private val samViaSyntheticScopeDisabled: Boolean, + private val shouldGenerateCandidateForVarargAfterSam: Boolean ) : SyntheticScope.Default() { + private val shouldGenerateAdditionalSamCandidate = !samViaSyntheticScopeDisabled || shouldGenerateCandidateForVarargAfterSam private val extensionForFunction = storageManager.createMemoizedFunctionWithNullableValues { function -> @@ -96,12 +97,18 @@ class SamAdapterFunctionsScope( return SamAdapterExtensionFunctionDescriptorImpl.create(function, samResolver) } - override fun getSyntheticMemberFunctions(receiverTypes: Collection, name: Name, location: LookupLocation): Collection { - if (samViaSyntheticScopeDisabled) return emptyList() + override fun getSyntheticMemberFunctions( + receiverTypes: Collection, + name: Name, + location: LookupLocation + ): Collection { + if (!shouldGenerateAdditionalSamCandidate) return emptyList() var result: SmartList? = null for (type in receiverTypes) { for (function in type.memberScope.getContributedFunctions(name, location)) { + if (samViaSyntheticScopeDisabled && !function.shouldGenerateCandidateForVarargAfterSamAndHasVararg) continue + val extension = extensionForFunction(function.original)?.substituteForReceiverType(type) if (extension != null) { recordSamLookupsForParameters(function, location) @@ -125,6 +132,9 @@ class SamAdapterFunctionsScope( } } + private val FunctionDescriptor.shouldGenerateCandidateForVarargAfterSamAndHasVararg + get() = shouldGenerateCandidateForVarargAfterSam && valueParameters.lastOrNull()?.isVararg == true + private fun FunctionDescriptor.substituteForReceiverType(receiverType: KotlinType): FunctionDescriptor? { val containingClass = containingDeclaration as? ClassDescriptor ?: return null val correspondingSupertype = findCorrespondingSupertype(receiverType, containingClass.defaultType) ?: return null @@ -138,19 +148,22 @@ class SamAdapterFunctionsScope( } override fun getSyntheticMemberFunctions(receiverTypes: Collection): Collection { - if (samViaSyntheticScopeDisabled) return emptyList() + if (!shouldGenerateAdditionalSamCandidate) return emptyList() return receiverTypes.flatMapTo(LinkedHashSet()) { type -> type.memberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) - .filterIsInstance() - .mapNotNull { - extensionForFunction(it.original)?.substituteForReceiverType(type) - } + .filterIsInstance() + .run { + if (samViaSyntheticScopeDisabled) filter { it.shouldGenerateCandidateForVarargAfterSamAndHasVararg } else this + } + .mapNotNull { + extensionForFunction(it.original)?.substituteForReceiverType(type) + } } } override fun getSyntheticStaticFunctions(scope: ResolutionScope, name: Name, location: LookupLocation): Collection { - if (samViaSyntheticScopeDisabled) return emptyList() + if (!shouldGenerateAdditionalSamCandidate) return emptyList() return getSamFunctions(scope.getContributedFunctions(name, location), location) } @@ -159,7 +172,7 @@ class SamAdapterFunctionsScope( val classifier = scope.getContributedClassifier(name, location) ?: return emptyList() recordSamLookupsToClassifier(classifier, location) - if (samViaSyntheticScopeDisabled) return listOfNotNull(getSamConstructor(classifier)) + if (!shouldGenerateAdditionalSamCandidate) return listOfNotNull(getSamConstructor(classifier)) return getAllSamConstructors(classifier) } @@ -173,7 +186,7 @@ class SamAdapterFunctionsScope( } override fun getSyntheticStaticFunctions(scope: ResolutionScope): Collection { - if (samViaSyntheticScopeDisabled) return emptyList() + if (!shouldGenerateAdditionalSamCandidate) return emptyList() return getSamFunctions(scope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS), location = null) } @@ -181,13 +194,13 @@ class SamAdapterFunctionsScope( override fun getSyntheticConstructors(scope: ResolutionScope): Collection { val classifiers = scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS).filterIsInstance() - if (samViaSyntheticScopeDisabled) return classifiers.mapNotNull { getSamConstructor(it) } + if (!shouldGenerateAdditionalSamCandidate) return classifiers.mapNotNull { getSamConstructor(it) } return classifiers.flatMap { getAllSamConstructors(it) } } override fun getSyntheticConstructor(constructor: ConstructorDescriptor): ConstructorDescriptor? { - if (samViaSyntheticScopeDisabled) return null + if (samViaSyntheticScopeDisabled && !constructor.shouldGenerateCandidateForVarargAfterSamAndHasVararg) return null return when (constructor) { is JavaClassConstructorDescriptor -> createJavaSamAdapterConstructor(constructor) @@ -211,10 +224,14 @@ class SamAdapterFunctionsScope( functions: Collection, location: LookupLocation? ): List> { + if (!shouldGenerateAdditionalSamCandidate) return emptyList() + return functions.mapNotNull { function -> if (function !is JavaMethodDescriptor) return@mapNotNull null if (function.dispatchReceiverParameter != null) return@mapNotNull null // consider only statics if (!SingleAbstractMethodUtils.isSamAdapterNecessary(function)) return@mapNotNull null + if (samViaSyntheticScopeDisabled && !function.shouldGenerateCandidateForVarargAfterSamAndHasVararg) + return@mapNotNull null location?.let { recordSamLookupsForParameters(function, it) } @@ -227,7 +244,7 @@ class SamAdapterFunctionsScope( } private fun getSamAdaptersFromConstructors(classifier: ClassifierDescriptor): List { - if (classifier !is JavaClassDescriptor) return emptyList() + if (!shouldGenerateAdditionalSamCandidate || classifier !is JavaClassDescriptor) return emptyList() return arrayListOf().apply { for (constructor in classifier.constructors) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 09a569dfbef..828dd0bfb2f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -765,6 +765,7 @@ public interface Errors { DiagnosticFactory1 TYPE_INFERENCE_ONLY_INPUT_TYPES = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); + DiagnosticFactory0 TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT = DiagnosticFactory0.create(ERROR, SPECIAL_CONSTRUCT_TOKEN); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index ba57167a7de..127e05f56b8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -859,6 +859,7 @@ public class DefaultErrorMessages { "(argument types, receiver type or expected type). Try to specify it explicitly.", NAME); MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER); MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, "Type inference failed. Expected type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE); + MAP.put(TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG, "Please use spread operator to pass an array as vararg. It will be an error in 1.5."); MAP.put(TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT, "Type inference for control flow expression failed. Please specify its type explicitly."); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index bbbb0b02fd6..99b20bd515c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -175,6 +175,10 @@ class DiagnosticReporterByTrackingStrategy( } } + + ResolvedToSamWithVarargDiagnostic::class.java -> { + trace.report(TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG.on(callArgument.psiCallArgument.valueArgument.asElement())) + } } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index 8e870cce568..74062286399 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter @@ -45,6 +47,7 @@ class KotlinCallCompleter( candidate.addExpectedTypeConstraint(returnType, expectedType) candidate.addExpectedTypeFromCastConstraint(returnType, resolutionCallbacks) + candidate.checkSamWithVararg(diagnosticHolder) return if (resolutionCallbacks.inferenceSession.shouldRunCompletion(candidate)) candidate.runCompletion( @@ -56,6 +59,22 @@ class KotlinCallCompleter( candidate.asCallResolutionResult(ConstraintSystemCompletionMode.PARTIAL, diagnosticHolder) } + private fun KotlinResolutionCandidate.checkSamWithVararg(diagnosticHolder: KotlinDiagnosticsHolder.SimpleHolder) { + val samConversionPerArgumentWithWarningsForVarargAfterSam = + callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) && + !callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitVarargAsArrayAfterSamArgument) + + if (samConversionPerArgumentWithWarningsForVarargAfterSam && resolvedCall.candidateDescriptor is SyntheticMemberDescriptor<*>) { + val declarationDescriptor = resolvedCall.candidateDescriptor.baseDescriptorForSynthetic as? FunctionDescriptor ?: return + + if (declarationDescriptor.valueParameters.lastOrNull()?.isVararg == true) { + diagnosticHolder.addDiagnostic( + ResolvedToSamWithVarargDiagnostic(resolvedCall.atom.argumentsInParenthesis.lastOrNull() ?: return) + ) + } + } + } + fun createAllCandidatesResult( candidates: Collection, expectedType: UnwrappedType?, diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index 1686264a451..af6e013d21b 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -294,7 +294,11 @@ private fun KotlinResolutionCandidate.getExpectedTypeWithSAMConversion( argument: KotlinCallArgument, candidateParameter: ParameterDescriptor ): UnwrappedType? { - if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null + val generatingAdditionalSamCandidateIsEnabled = + !callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) && + !callComponents.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitVarargAsArrayAfterSamArgument) + + if (generatingAdditionalSamCandidateIsEnabled) return null if (!callComponents.samConversionTransformer.shouldRunSamConversionForFunction(resolvedCall.candidateDescriptor)) return null val argumentIsFunctional = when (argument) { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt index 0d02905b2cf..e404dc3c0fc 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallDiagnostics.kt @@ -202,4 +202,10 @@ class OnlyInputTypesDiagnostic(val typeVariable: NewTypeVariable) : KotlinCallDi override fun report(reporter: DiagnosticReporter) { reporter.onCall(this) } -} \ No newline at end of file +} + +class ResolvedToSamWithVarargDiagnostic(val argument: KotlinCallArgument) : KotlinCallDiagnostic(RESOLVED_TO_SAM_WITH_VARARG) { + override fun report(reporter: DiagnosticReporter) { + reporter.onCallArgument(argument, this) + } +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt index 34d7e4b891d..41ffee506a2 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ImplicitScopeTower.kt @@ -83,6 +83,7 @@ enum class ResolutionCandidateApplicability { INAPPLICABLE_ARGUMENTS_MAPPING_ERROR, // arguments not mapped to parameters (i.e. different size of arguments and parameters) INAPPLICABLE_WRONG_RECEIVER, // receiver not matched HIDDEN, // removed from resolve + RESOLVED_TO_SAM_WITH_VARARG, // migration warning up to 1.5 (when resolve to function with SAM conversion and array without spread as vararg) } abstract class ResolutionDiagnostic(candidateApplicability: ResolutionCandidateApplicability) : diff --git a/compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt b/compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt new file mode 100644 index 00000000000..cc7f065a333 --- /dev/null +++ b/compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt @@ -0,0 +1,53 @@ +// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument +// IGNORE_BACKEND_FIR: JVM_IR +// IGNORE_BACKEND: JVM_IR +// TARGET_BACKEND: JVM + +// FILE: Test.java +public class Test { + public static String foo1(Runnable r, String... strs) { + return null; + } + public String foo2(Runnable r1, Runnable r2, String... strs) { + return null; + } + public Test(Runnable r, String... strs) {} + public Test(Runnable r1, Runnable r2, String... strs) {} +} + +// FILE: main.kt +fun box(): String { + val x1 = {} + val x2: Runnable = Runnable { } + val x3 = arrayOf() + + Test.foo1({}, arrayOf()) + Test.foo1({}, *arrayOf()) + Test.foo1({}, x3) + Test.foo1({}, *arrayOf("")) + + Test.foo1(x1, arrayOf()) + Test.foo1(x1, *arrayOf()) + Test.foo1(x2, *arrayOf()) + + Test.foo1(x1, x3) + Test.foo1(x1, *x3) + Test.foo1(x2, *arrayOf("")) + + val i1 = Test({}, arrayOf()) + val i2 = Test({}, *arrayOf()) + val i3 = Test({}, x3) + val i4 = Test({}, arrayOf("")) + val i5 = Test({}, {}, *arrayOf("")) + val i6 = Test({}, {}, arrayOf()) + + i1.foo2({}, {}, arrayOf()) + i2.foo2({}, {}, *arrayOf()) + i3.foo2(x2, {}, *arrayOf()) + + i4.foo2({}, {}, arrayOf("")) + i5.foo2({}, {}, *x3) + i6.foo2(x2, {}, *arrayOf("")) + + return "OK" +} diff --git a/compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt b/compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt new file mode 100644 index 00000000000..a64da0de458 --- /dev/null +++ b/compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt @@ -0,0 +1,41 @@ +// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM + +// FILE: Test.java +public class Test { + public static String foo1(Runnable r, String... strs) { + return null; + } + public String foo2(Runnable r1, Runnable r2, String... strs) { + return null; + } + public Test(Runnable r, String... strs) {} + public Test(Runnable r1, Runnable r2, String... strs) {} +} + +// FILE: main.kt +fun box(): String { + val x1 = {} + val x2: Runnable = Runnable { } + val x3 = arrayOf() + + Test.foo1({}, arrayOf()) + Test.foo1({}, arrayOf("")) + + Test.foo1(x1, arrayOf()) + Test.foo1(x2, *arrayOf()) + + Test.foo1(x1, x3) + Test.foo1(x2, *arrayOf("")) + + val i1 = Test({}, arrayOf()) + val i3 = Test({}, x3) + val i4 = Test({}, arrayOf("")) + val i6 = Test({}, {}, arrayOf()) + + i1.foo2({}, {}, arrayOf()) + i1.foo2({}, {}, arrayOf("")) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/callableReference/generic/dependOnArgumentType.kt b/compiler/testData/diagnostics/tests/callableReference/generic/dependOnArgumentType.kt index b7e690523a1..f93d0f47013 100644 --- a/compiler/testData/diagnostics/tests/callableReference/generic/dependOnArgumentType.kt +++ b/compiler/testData/diagnostics/tests/callableReference/generic/dependOnArgumentType.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +SamConversionPerArgument +NewInference +// !LANGUAGE: +SamConversionPerArgument +NewInference +ProhibitVarargAsArrayAfterSamArgument // !DIAGNOSTICS: -UNUSED_PARAMETER // FILE: A.java diff --git a/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt b/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt new file mode 100644 index 00000000000..b7a2879aead --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument +// IGNORE_BACKEND: JS +// SKIP_TXT + +// FILE: Test.java +public class Test { + public static String foo1(Runnable r, String... strs) { + return null; + } + public String foo2(Runnable r1, Runnable r2, String... strs) { + return null; + } + public Test(Runnable r, String... strs) {} + public Test(Runnable r, Runnable r, String... strs) {} +} + +// FILE: main.kt +fun main(x2: Runnable) { + val x1 = {} + val x3 = arrayOf() + + Test.foo1({}, arrayOf()) + Test.foo1({}, *arrayOf()) + Test.foo1({}, x3) + Test.foo1({}, *arrayOf("")) + + Test.foo1(x1, arrayOf()) + Test.foo1(x1, *arrayOf()) + Test.foo1(x2, arrayOf()) + Test.foo1(x2, *arrayOf()) + + Test.foo1(x1, x3) + Test.foo1(x1, *x3) + Test.foo1(x2, arrayOf("")) + Test.foo1(x2, *arrayOf("")) + + val i1 = Test({}, arrayOf()) + val i2 = Test({}, *arrayOf()) + val i3 = Test({}, x3) + val i4 = Test({}, arrayOf("")) + val i5 = Test({}, {}, *arrayOf("")) + val i6 = Test({}, {}, arrayOf()) + + i1.foo2({}, {}, arrayOf()) + i1.foo2({}, {}, *arrayOf()) + i1.foo2({}, x2, arrayOf()) + i1.foo2(x2, {}, *arrayOf()) + + i1.foo2({}, {}, arrayOf("")) + i1.foo2({}, {}, *x3) + i1.foo2({}, x2, x3) + i1.foo2(x2, {}, *arrayOf("")) +} diff --git a/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt b/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt new file mode 100644 index 00000000000..17c8186f00b --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument +ProhibitVarargAsArrayAfterSamArgument +// IGNORE_BACKEND: JS +// SKIP_TXT + +// FILE: Test.java +public class Test { + public static String foo1(Runnable r, String... strs) { + return null; + } + public String foo2(Runnable r, Runnable r, String... strs) { + return null; + } + public Test(Runnable r, String... strs) {} + public Test(Runnable r, Runnable r, String... strs) {} +} + +// FILE: main.kt +fun main(x2: Runnable) { + val x1 = {} + val x3 = arrayOf() + + Test.foo1({}, arrayOf()) + Test.foo1({}, *arrayOf()) + Test.foo1({}, *x3) + Test.foo1({}, arrayOf("")) + + Test.foo1(x1, arrayOf()) + Test.foo1(x1, *arrayOf()) + Test.foo1(x2, arrayOf()) + Test.foo1(x2, *arrayOf()) + + Test.foo1(x1, x3) + Test.foo1(x1, *x3) + Test.foo1(x2, arrayOf("")) + Test.foo1(x2, *arrayOf("")) + + val i1 = Test({}, arrayOf()) + val i2 = Test({}, *arrayOf()) + val i3 = Test({}, x3) + val i4 = Test({}, arrayOf("")) + val i5 = Test({}, {}, *arrayOf("")) + val i6 = Test({}, {}, arrayOf()) + + i2.foo2({}, {}, arrayOf()) + i2.foo2({}, {}, *arrayOf()) + i2.foo2({}, x2, arrayOf()) + i2.foo2(x2, {}, *arrayOf()) + + i2.foo2({}, {}, arrayOf("")) + i2.foo2({}, {}, *x3) + i2.foo2({}, x2, x3) + i2.foo2(x2, {}, *arrayOf("")) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt b/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt new file mode 100644 index 00000000000..0ead6fbf625 --- /dev/null +++ b/compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt @@ -0,0 +1,54 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +// IGNORE_BACKEND: JS, JS_IR +// SKIP_TXT + +// FILE: Test.java +public class Test { + public static String foo1(Runnable r, String... strs) { + return null; + } + public String foo2(Runnable r, Runnable r, String... strs) { + return null; + } + public Test(Runnable r, String... strs) {} + public Test(Runnable r, Runnable r, String... strs) {} +} + +// FILE: main.kt +fun main(x2: Runnable) { + val x1 = {} + val x3 = arrayOf() + + Test.foo1({}, arrayOf()) + Test.foo1({}, *arrayOf()) + Test.foo1({}, *x3) + Test.foo1({}, arrayOf("")) + + Test.foo1(x1, arrayOf()) + Test.foo1(x1, *arrayOf()) + Test.foo1(x2, arrayOf()) + Test.foo1(x2, *arrayOf()) + + Test.foo1(x1, x3) + Test.foo1(x1, *x3) + Test.foo1(x2, arrayOf("")) + Test.foo1(x2, *arrayOf("")) + + val i1 = Test({}, arrayOf()) + val i2 = Test({}, *arrayOf()) + val i3 = Test({}, x3) + val i4 = Test({}, arrayOf("")) + val i5 = Test({}, {}, *arrayOf("")) + val i6 = Test({}, {}, arrayOf()) + + i1.foo2({}, {}, arrayOf()) + i1.foo2({}, {}, *arrayOf()) + i1.foo2({}, x2, arrayOf()) + i1.foo2(x2, {}, *arrayOf()) + + i1.foo2({}, {}, arrayOf("")) + i1.foo2({}, {}, *x3) + i1.foo2({}, x2, x3) + i1.foo2(x2, {}, *arrayOf("")) +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall.kt b/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall.kt index 8c962812920..33489add763 100644 --- a/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall.kt +++ b/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +NewInference +SamConversionPerArgument +// !LANGUAGE: +NewInference +SamConversionPerArgument +ProhibitVarargAsArrayAfterSamArgument // FILE: samConversionInGenericConstructorCall.kt fun test1(f: (String) -> String) = C(f) diff --git a/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall_NI.kt b/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall_NI.kt index 8709be42577..e5b27a833d0 100644 --- a/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall_NI.kt +++ b/compiler/testData/ir/irText/expressions/sam/samConversionInGenericConstructorCall_NI.kt @@ -1,4 +1,4 @@ -// !LANGUAGE: +NewInference +SamConversionPerArgument +SamConversionForKotlinFunctions +// !LANGUAGE: +NewInference +SamConversionPerArgument +SamConversionForKotlinFunctions +ProhibitVarargAsArrayAfterSamArgument // FILE: samConversionInGenericConstructorCall_NI.kt fun test3( f1: (String) -> String, diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 7dfed2ce74e..8e8905a24c8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18615,6 +18615,21 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/samConversions"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentProhibited.kt") + public void testArrayAsVarargAfterSamArgumentProhibited() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("checkSamConversionsAreDisabledByDefault.kt") public void testCheckSamConversionsAreDisabledByDefault() throws Exception { runTest("compiler/testData/diagnostics/tests/samConversions/checkSamConversionsAreDisabledByDefault.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 390f3296b8c..6a20b1e4197 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -18605,6 +18605,21 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/samConversions"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentProhibited.kt") + public void testArrayAsVarargAfterSamArgumentProhibited() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentProhibited.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/diagnostics/tests/samConversions/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("checkSamConversionsAreDisabledByDefault.kt") public void testCheckSamConversionsAreDisabledByDefault() throws Exception { runTest("compiler/testData/diagnostics/tests/samConversions/checkSamConversionsAreDisabledByDefault.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index abcc2406a83..49fd9c8ee0d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -25784,6 +25784,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("castFromAny.kt") public void testCastFromAny() throws Exception { runTest("compiler/testData/codegen/box/sam/castFromAny.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 9cd9c94e97b..52a626c3670 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -24601,6 +24601,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("castFromAny.kt") public void testCastFromAny() throws Exception { runTest("compiler/testData/codegen/box/sam/castFromAny.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 84c9475d7a5..71a7c43d851 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -24283,6 +24283,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("castFromAny.kt") public void testCastFromAny() throws Exception { runTest("compiler/testData/codegen/box/sam/castFromAny.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9b58404dfd8..e7b81759139 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -24283,6 +24283,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("arrayAsVarargAfterSamArgument.kt") + public void testArrayAsVarargAfterSamArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgument.kt"); + } + + @TestMetadata("arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt") + public void testArrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument() throws Exception { + runTest("compiler/testData/codegen/box/sam/arrayAsVarargAfterSamArgumentWithoutSamConversionsPerArgument.kt"); + } + @TestMetadata("castFromAny.kt") public void testCastFromAny() throws Exception { runTest("compiler/testData/codegen/box/sam/castFromAny.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 14094eadce5..d3d1753d058 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -116,6 +116,7 @@ enum class LanguageFeature( ProhibitNonReifiedArraysAsReifiedTypeArguments(KOTLIN_1_4, kind = BUG_FIX), ProhibitProtectedCallFromInline(KOTLIN_1_4, kind = BUG_FIX), ProperFinally(KOTLIN_1_4, kind = BUG_FIX), + ProhibitVarargAsArrayAfterSamArgument(KOTLIN_1_4, kind = BUG_FIX), ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX), // Temporarily disabled, see KT-27084/KT-22379 diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt index 5e6f1614a21..42c442d5180 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantSamConstructorInspection.kt @@ -132,10 +132,12 @@ class RedundantSamConstructorInspection : AbstractKotlinInspection() { if (!resolutionResults.isSuccess) return false + val generatingAdditionalSamCandidateIsDisabled = + parentCall.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) || + parentCall.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitVarargAsArrayAfterSamArgument) + val samAdapterOriginalDescriptor = - if (parentCall.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) && - resolutionResults.resultingCall is NewResolvedCallImpl<*> - ) { + if (generatingAdditionalSamCandidateIsDisabled && resolutionResults.resultingCall is NewResolvedCallImpl<*>) { resolutionResults.resultingDescriptor } else { SamCodegenUtil.getOriginalIfSamAdapter(resolutionResults.resultingDescriptor) ?: return false diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddSpreadOperatorForArrayAsVarargAfterSam.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddSpreadOperatorForArrayAsVarargAfterSam.kt new file mode 100644 index 00000000000..0d9f8061e1e --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddSpreadOperatorForArrayAsVarargAfterSam.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiFactory + +object AddSpreadOperatorForArrayAsVarargAfterSamFixFactory : KotlinSingleIntentionActionFactory() { + public override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val diagnosticWithParameters = Errors.TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG.cast(diagnostic) + val argument = diagnosticWithParameters.psiElement + + return AddSpreadOperatorForArrayAsVarargAfterSamFix(argument) + } +} + +class AddSpreadOperatorForArrayAsVarargAfterSamFix(element: PsiElement) : KotlinQuickFixAction(element) { + override fun getFamilyName() = "Add a spread operator before an array passing as vararg" + + override fun getText() = familyName + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val element = element ?: return + + element.addBefore(KtPsiFactory(file).createStar(), element.firstChild) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 432b15b9c60..76f6a28fc3a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -160,6 +160,7 @@ class QuickFixRegistrar : QuickFixContributor { UNRESOLVED_REFERENCE.registerFactory(ImportFix) UNRESOLVED_REFERENCE.registerFactory(ImportConstructorReferenceFix) DEPRECATED_ACCESS_BY_SHORT_NAME.registerFactory(AddExplicitImportForDeprecatedVisibilityFix.Factory) + TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG.registerFactory(AddSpreadOperatorForArrayAsVarargAfterSamFixFactory) TOO_MANY_ARGUMENTS.registerFactory(ImportForMismatchingArgumentsFix) NO_VALUE_FOR_PARAMETER.registerFactory(ImportForMismatchingArgumentsFix) diff --git a/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withError.test b/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withError.test new file mode 100644 index 00000000000..722db8ebbc3 --- /dev/null +++ b/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withError.test @@ -0,0 +1,21 @@ +// FILE: test.before.kt +// "Add a spread operator before an array passing as vararg" "false" +// ACTION: Add 'toString()' call +// ACTION: Create member function 'Test.foo' +// ACTION: Introduce import alias +// ACTION: Introduce local variable +// ACTION: Put arguments on separate lines +// ERROR: Type mismatch: inferred type is Array but String! was expected +// COMPILER_ARGUMENTS: -XXLanguage:+NewInference -XXLanguage:+SamConversionForKotlinFunctions -XXLanguage:+SamConversionPerArgument -XXLanguage:+ProhibitVarargAsArrayAfterSamArgument +// WITH_RUNTIME + +fun main() { + Test.foo({}, arrayOf()) +} + +// FILE: Test.java +public class Test { + public static String foo(Runnable r, String... strs) { + return null; + } +} diff --git a/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withWarning.test b/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withWarning.test new file mode 100644 index 00000000000..bddc1ecd7e1 --- /dev/null +++ b/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withWarning.test @@ -0,0 +1,27 @@ +// FILE: test.before.kt +// "Add a spread operator before an array passing as vararg" "true" +// WARNING: Please use spread operator to pass an array as vararg. It will be an error in 1.5. +// COMPILER_ARGUMENTS: -XXLanguage:+NewInference -XXLanguage:+SamConversionForKotlinFunctions -XXLanguage:+SamConversionPerArgument +// WITH_RUNTIME + +fun main() { + Test.foo({}, arrayOf()) +} + +// FILE: Test.java +public class Test { + public static String foo(Runnable r, String... strs) { + return null; + } +} + +// FILE: test.after.kt +// "Add a spread operator before an array passing as vararg" "true" +// WARNING: Please use spread operator to pass an array as vararg. It will be an error in 1.5. +// COMPILER_ARGUMENTS: -XXLanguage:+NewInference -XXLanguage:+SamConversionForKotlinFunctions -XXLanguage:+SamConversionPerArgument +// WITH_RUNTIME + +fun main() { + Test.foo({}, *arrayOf()) +} + diff --git a/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withoutWarning.test b/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withoutWarning.test new file mode 100644 index 00000000000..abdb8bf5d9d --- /dev/null +++ b/idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withoutWarning.test @@ -0,0 +1,18 @@ +// FILE: test.before.kt +// "Add a spread operator before an array passing as vararg" "false" +// ACTION: Add explicit type arguments +// ACTION: Introduce import alias +// ACTION: Introduce local variable +// ACTION: Put arguments on separate lines +// WITH_RUNTIME + +fun main() { + Test.foo({}, arrayOf()) +} + +// FILE: Test.java +public class Test { + public static String foo(Runnable r, String... strs) { + return null; + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index df80db167bc..fc6d3c050d9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -324,6 +324,34 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddSpreadOperatorForArrayAsVarargAfterSam extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + public void testAllFilesPresentInAddSpreadOperatorForArrayAsVarargAfterSam() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), true); + } + + @TestMetadata("withError.test") + public void testWithError() throws Exception { + runTest("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withError.test"); + } + + @TestMetadata("withWarning.test") + public void testWithWarning() throws Exception { + runTest("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withWarning.test"); + } + + @TestMetadata("withoutWarning.test") + public void testWithoutWarning() throws Exception { + runTest("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam/withoutWarning.test"); + } + } + @TestMetadata("idea/testData/quickfix/addStarProjections") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 8590cd557b6..1a0d0d3d82b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1174,6 +1174,19 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddSpreadOperatorForArrayAsVarargAfterSam extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAddSpreadOperatorForArrayAsVarargAfterSam() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/addSpreadOperatorForArrayAsVarargAfterSam"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + } + @TestMetadata("idea/testData/quickfix/addStarProjections") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)