[NI] Move ability to convert standalone SAM-argument under the feature

If new inference is enabled only for IDE analysis, then this feature
 will be disabled to reduce difference between new and old inference,
 but if new inference is enabled in the compiler, then this feature
 will be enabled too to preserve behavior of new inference for
 compilation

 #KT-32175 Fixed
 #KT-32143 Fixed
 #KT-32123 Fixed
 #KT-32230 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-06-25 20:01:36 +03:00
parent 4d82b02f83
commit c2cf4aa2b5
34 changed files with 151 additions and 34 deletions
@@ -323,6 +323,7 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
if (newInference) {
put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED)
put(LanguageFeature.SamConversionPerArgument, LanguageFeature.State.ENABLED)
}
if (legacySmartCastAfterTry) {
@@ -360,11 +361,20 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
private fun HashMap<LanguageFeature, LanguageFeature.State>.configureLanguageFeaturesFromInternalArgs(collector: MessageCollector) {
val featuresThatForcePreReleaseBinaries = mutableListOf<LanguageFeature>()
var standaloneSamConversionFeaturePassedExplicitly = false
for ((feature, state) in internalArguments.filterIsInstance<ManualLanguageFeatureSetting>()) {
put(feature, state)
if (state == LanguageFeature.State.ENABLED && feature.forcesPreReleaseBinariesIfEnabled()) {
featuresThatForcePreReleaseBinaries += feature
}
if (feature == LanguageFeature.SamConversionPerArgument) {
standaloneSamConversionFeaturePassedExplicitly = true
}
}
if (!standaloneSamConversionFeaturePassedExplicitly && this[LanguageFeature.NewInference] == LanguageFeature.State.ENABLED) {
put(LanguageFeature.SamConversionPerArgument, LanguageFeature.State.ENABLED)
}
if (featuresThatForcePreReleaseBinaries.isNotEmpty()) {
@@ -45,7 +45,8 @@ class JavaSyntheticScopes(
val scopesWithForceEnabledSamAdapters: Collection<SyntheticScope>
init {
val newInferenceEnabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
val samConversionPerArgumentIsEnabled =
languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)
val javaSyntheticPropertiesScope = JavaSyntheticPropertiesScope(storageManager, lookupTracker)
val scopesFromExtensions = SyntheticScopeProviderExtension
@@ -58,12 +59,12 @@ class JavaSyntheticScopes(
samConventionResolver,
deprecationResolver,
lookupTracker,
samViaSyntheticScopeDisabled = newInferenceEnabled
samViaSyntheticScopeDisabled = samConversionPerArgumentIsEnabled
)
scopes = listOf(javaSyntheticPropertiesScope, samAdapterFunctionsScope) + scopesFromExtensions
if (newInferenceEnabled) {
if (samConversionPerArgumentIsEnabled) {
val forceEnabledSamAdapterFunctionsScope = SamAdapterFunctionsScope(
storageManager,
samConventionResolver,
@@ -17,13 +17,11 @@
package org.jetbrains.kotlin.synthetic
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
@@ -63,13 +61,12 @@ fun syntheticVisibility(originalDescriptor: DeclarationDescriptorWithVisibility,
}
fun <D : CallableDescriptor> ResolvedCall<D>.isResolvedWithSamConversions(): Boolean {
return if (this is NewResolvedCallImpl<D>) {
// New inference
this.resolvedCallAtom.argumentsWithConversion.isNotEmpty()
} else {
// Old Inference
this.resultingDescriptor is SamAdapterDescriptor<*> ||
this.resultingDescriptor is SamConstructorDescriptor ||
this.resultingDescriptor is SamAdapterExtensionFunctionDescriptor
if (this is NewResolvedCallImpl<D> && resolvedCallAtom.argumentsWithConversion.isNotEmpty()) {
return true
}
// Feature SamConversionPerArgument is disabled
return this.resultingDescriptor is SamAdapterDescriptor<*> ||
this.resultingDescriptor is SamConstructorDescriptor ||
this.resultingDescriptor is SamAdapterExtensionFunctionDescriptor
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
@@ -295,6 +296,7 @@ private fun KotlinResolutionCandidate.getExpectedTypeWithSAMConversion(
argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor
): UnwrappedType? {
if (!callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument)) return null
if (!callComponents.samConversionTransformer.shouldRunSamConversionForFunction(resolvedCall.candidateDescriptor)) return null
val argumentIsFunctional = when (argument) {
@@ -0,0 +1,4 @@
$TESTDATA_DIR$/standaloneSamConversionsAreEnabledWithNewInference.kt
-d
$TEMP_DIR$
-Xnew-inference -XXLanguage:-SamConversionPerArgument
@@ -0,0 +1,8 @@
warning: flag is not supported by this version of the compiler: -Xnew-inference -XXLanguage:-SamConversionPerArgument
compiler/testData/cli/jvm/standaloneSamConversionsAreEnabledWithNewInference.kt:9:25: error: type mismatch: inferred type is () -> Unit but Runnable was expected
ForceSam.compare(r, {})
^
compiler/testData/cli/jvm/standaloneSamConversionsAreEnabledWithNewInference.kt:10:22: error: type mismatch: inferred type is () -> Unit but Runnable was expected
ForceSam.compare({}, r)
^
COMPILATION_ERROR
@@ -0,0 +1,4 @@
$TESTDATA_DIR$/standaloneSamConversionsAreEnabledWithNewInference.kt
-d
$TEMP_DIR$
-Xnew-inference
@@ -0,0 +1,11 @@
object ForceSam : java.util.Comparator<Runnable> {
override fun compare(o1: Runnable, o2: Runnable): Int = 0
}
fun test(r: Runnable) {
ForceSam.compare(r, r)
ForceSam.compare({}, {})
ForceSam.compare(r, {})
ForceSam.compare({}, r)
}
@@ -0,0 +1,4 @@
$TESTDATA_DIR$/standaloneSamConversionsAreEnabledWithNewInference.kt
-d
$TEMP_DIR$
-XXLanguage:+NewInference
@@ -0,0 +1,10 @@
warning: ATTENTION!
This build uses unsafe internal compiler arguments:
-XXLanguage:+NewInference
This mode is not recommended for production use,
as no stability/compatibility guarantees are given on
compiler or generated code. Use it at your own risk!
OK
@@ -0,0 +1,3 @@
$TESTDATA_DIR$/standaloneSamConversionsAreEnabledWithNewInference.kt
-d
$TEMP_DIR$
@@ -0,0 +1,7 @@
compiler/testData/cli/jvm/standaloneSamConversionsAreEnabledWithNewInference.kt:9:25: error: type mismatch: inferred type is () -> Unit but Runnable was expected
ForceSam.compare(r, {})
^
compiler/testData/cli/jvm/standaloneSamConversionsAreEnabledWithNewInference.kt:10:22: error: type mismatch: inferred type is () -> Unit but Runnable was expected
ForceSam.compare({}, r)
^
COMPILATION_ERROR
@@ -1,6 +1,5 @@
// !LANGUAGE: +NewInference
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FILE: example/Hello.java
+1 -1
View File
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference
// !LANGUAGE: +NewInference +SamConversionPerArgument
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
+1 -1
View File
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,4 +1,4 @@
// !WITH_NEW_INFERENCE
// !LANGUAGE: +SamConversionPerArgument +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: A.java
@@ -16,14 +16,14 @@ fun <T> bar(s: T) {}
fun <T> complex(t: T, f: (T) -> Unit) {}
fun test1() {
foo(1, <!NI;TYPE_MISMATCH!>A::invokeLater<!>) // KT-24507 SAM conversion accidentally applied to callable reference and incorrectly handled via BE
foo(1, <!TYPE_MISMATCH!>A::invokeLater<!>) // KT-24507 SAM conversion accidentally applied to callable reference and incorrectly handled via BE
foo(1, ::bar)
complex(1, ::bar)
}
fun <R> test2(x: R) {
foo(x, <!NI;TYPE_MISMATCH!>A::invokeLater<!>) // KT-24507 SAM conversion accidentally applied to callable reference and incorrectly handled via BE
foo(x, <!TYPE_MISMATCH!>A::invokeLater<!>) // KT-24507 SAM conversion accidentally applied to callable reference and incorrectly handled via BE
foo(x, ::bar)
complex(x, ::bar)
@@ -13,5 +13,5 @@ public class J {
package test
fun test() {
J("", <!NAMED_ARGUMENTS_NOT_ALLOWED!>r<!> = { }, <!NAMED_ARGUMENTS_NOT_ALLOWED!>z<!> = false)
J("", <!NAMED_ARGUMENTS_NOT_ALLOWED!>r<!> = <!NI;TYPE_MISMATCH!>{ }<!>, <!NAMED_ARGUMENTS_NOT_ALLOWED!>z<!> = false)
}
@@ -13,5 +13,5 @@ public class J {
package test
fun test() {
J.foo("", <!NAMED_ARGUMENTS_NOT_ALLOWED!>r<!> = { }, <!NAMED_ARGUMENTS_NOT_ALLOWED!>z<!> = false)
J.foo("", <!NAMED_ARGUMENTS_NOT_ALLOWED!>r<!> = <!NI;TYPE_MISMATCH!>{ }<!>, <!NAMED_ARGUMENTS_NOT_ALLOWED!>z<!> = false)
}
@@ -21,7 +21,7 @@ class B {
fun main() {
fun println() {}
// All parameters in SAM adapter of `foo` have functional types
B().foo(<!OI;TYPE_MISMATCH!>{ println() }<!>, B.bar())
B().foo(<!TYPE_MISMATCH!>{ println() }<!>, B.bar())
// So you should use SAM constructors when you want to use mix lambdas and Java objects
B().foo(Runnable { println() }, B.bar())
B().foo({ println() }, { it: Any? -> it == null } )
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference
// !LANGUAGE: +NewInference +SamConversionPerArgument
// !CHECK_TYPE
// FILE: J.java
public interface J<T> {
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument
// !CHECK_TYPE
// FILE: F.java
public interface F<S> {
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument
// !CHECK_TYPE
// FILE: Fn.java
public interface Fn<T, R> {
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions
// !LANGUAGE: +NewInference +SamConversionPerArgument
// FILE: J.java
public interface J {
public void foo1(Runnable r);
@@ -1,4 +1,4 @@
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions
// !LANGUAGE: +NewInference +SamConversionForKotlinFunctions +SamConversionPerArgument
// FILE: Runnable.java
public interface Runnable {
void run();
@@ -21,7 +21,7 @@ class B : A() {
}
if (d.x is B) {
<!OI;SMARTCAST_IMPOSSIBLE!>d.x<!>.<!NI;INVISIBLE_MEMBER!>foo<!> {}
<!SMARTCAST_IMPOSSIBLE!>d.x<!>.<!NI;INVISIBLE_MEMBER!>foo<!> {}
}
}
}
@@ -2,7 +2,7 @@
// FILE: KotlinFile.kt
fun foo(javaClass: JavaClass<Int>): Int {
val inner = javaClass.createInner<String>()
return <!TYPE_MISMATCH!>inner.doSomething(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>, "") <!OI;TYPE_MISMATCH!>{ }<!><!>
return <!TYPE_MISMATCH!>inner.<!NI;TYPE_MISMATCH!>doSomething(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>, "") <!TYPE_MISMATCH!>{ }<!><!><!>
}
// FILE: JavaClass.java
@@ -1,9 +1,9 @@
// !WITH_NEW_INFERENCE
// FILE: KotlinFile.kt
fun foo(javaClass: JavaClass) {
javaClass.doSomething(<!NAMED_ARGUMENTS_NOT_ALLOWED!>p<!> = 1) {
javaClass.doSomething(<!NAMED_ARGUMENTS_NOT_ALLOWED!>p<!> = 1) <!NI;TYPE_MISMATCH!>{
bar()
}
}<!>
}
fun bar(){}
@@ -1,7 +1,7 @@
// !WITH_NEW_INFERENCE
// FILE: KotlinFile.kt
fun foo(javaClass: JavaClass) {
javaClass.<!INVISIBLE_MEMBER!>doSomething<!> <!OI;TYPE_MISMATCH!>{ }<!>
javaClass.<!INVISIBLE_MEMBER!>doSomething<!> <!TYPE_MISMATCH!>{ }<!>
}
// FILE: JavaClass.java
@@ -576,6 +576,26 @@ public class CliTestGenerated extends AbstractCliTest {
runTest("compiler/testData/cli/jvm/singleJavaFileRoots.args");
}
@TestMetadata("standaloneSamConversionsAreDisabledExplicitlyWithNewInference.args")
public void testStandaloneSamConversionsAreDisabledExplicitlyWithNewInference() throws Exception {
runTest("compiler/testData/cli/jvm/standaloneSamConversionsAreDisabledExplicitlyWithNewInference.args");
}
@TestMetadata("standaloneSamConversionsAreEnabledWithNewInference.args")
public void testStandaloneSamConversionsAreEnabledWithNewInference() throws Exception {
runTest("compiler/testData/cli/jvm/standaloneSamConversionsAreEnabledWithNewInference.args");
}
@TestMetadata("standaloneSamConversionsAreEnabledWithNewInferenceInternalFlag.args")
public void testStandaloneSamConversionsAreEnabledWithNewInferenceInternalFlag() throws Exception {
runTest("compiler/testData/cli/jvm/standaloneSamConversionsAreEnabledWithNewInferenceInternalFlag.args");
}
@TestMetadata("standaloneSamConversionsBaseline_1_3.args")
public void testStandaloneSamConversionsBaseline_1_3() throws Exception {
runTest("compiler/testData/cli/jvm/standaloneSamConversionsBaseline_1_3.args");
}
@TestMetadata("suppressAllWarningsJvm.args")
public void testSuppressAllWarningsJvm() throws Exception {
runTest("compiler/testData/cli/jvm/suppressAllWarningsJvm.args");
@@ -125,6 +125,8 @@ enum class LanguageFeature(
SamConversionForKotlinFunctions(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),
SamConversionPerArgument(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),
// can be used only with NewInference feature
NewDataFlowForTryExpressions(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),
@@ -10,11 +10,13 @@ import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.codegen.SamCodegenUtil
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.forceEnableSamAdapters
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -131,10 +133,13 @@ class RedundantSamConstructorInspection : AbstractKotlinInspection() {
if (!resolutionResults.isSuccess) return false
val samAdapterOriginalDescriptor =
if (resolutionResults.resultingCall is NewResolvedCallImpl<*>)
if (parentCall.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) &&
resolutionResults.resultingCall is NewResolvedCallImpl<*>
) {
resolutionResults.resultingDescriptor
else
} else {
SamCodegenUtil.getOriginalIfSamAdapter(resolutionResults.resultingDescriptor) ?: return false
}
return samAdapterOriginalDescriptor.original == originalCall.resultingDescriptor.original
}
@@ -0,0 +1,24 @@
object ForceSam : java.util.Comparator<Runnable> {
override fun compare(o1: Runnable, o2: Runnable): Int = 0
}
fun test(r: Runnable) {
ForceSam.compare(r, r)
ForceSam.compare({}, {})
ForceSam.compare(r, <error descr="[TYPE_MISMATCH] Type mismatch: inferred type is () -> Unit but Runnable was expected">{}</error>)
ForceSam.compare(<error descr="[TYPE_MISMATCH] Type mismatch: inferred type is () -> Unit but Runnable was expected">{}</error>, r)
}
// Check that new inference is enabled
object Scope {
interface A
interface B<T>
class C<T>
fun <T, K> foo(<warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: C<T>) where K : A, K : B<T> {}
fun usage(c: C<Any>) {
foo(c) // should compile only in NI
}
}
@@ -930,5 +930,10 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
public void testOperatorCallDiagnosticsOnInOperator() throws Exception {
runTest("idea/testData/checker/diagnosticsMessage/operatorCallDiagnosticsOnInOperator.kt");
}
@TestMetadata("standaloneSamConversionIsDisabledInIDE.kt")
public void testStandaloneSamConversionIsDisabledInIDE() throws Exception {
runTest("idea/testData/checker/diagnosticsMessage/standaloneSamConversionIsDisabledInIDE.kt");
}
}
}