[NI] Introduce flag to change constraint system for overload resolution

This commit doesn't change behaviour of any inference algorithm, it
 introduces opportunity to switch constraint system that is used for
 overload resolution and fix problematic cases by changing one enum
 entry.

 Due to fundamental changes, there are cases where a new inference
 algorithm reports overload resolution ambiguity errors (#KT-31670,
 #KT-31758), which is correct from its point of view. However, this is
 a breaking change and to really make it, we should be very confident
 and have enough motivation for it, therefore, we don't change behavior
 now in order to collect more examples (if there are any). And if we
 find a lot of erroneous examples, we'll be able to change the behavior
 quite simply
This commit is contained in:
Mikhail Zarechenskiy
2019-06-07 15:51:45 +03:00
parent e7064f5b77
commit b7849da19e
20 changed files with 377 additions and 2 deletions
@@ -17900,6 +17900,26 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.kt");
}
@TestMetadata("kt31670.kt")
public void testKt31670() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31670.kt");
}
@TestMetadata("kt31670_compat.kt")
public void testKt31670_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31670_compat.kt");
}
@TestMetadata("kt31758.kt")
public void testKt31758() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31758.kt");
}
@TestMetadata("kt31758_compat.kt")
public void testKt31758_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31758_compat.kt");
}
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/numberOfDefaults.kt");
@@ -17910,6 +17930,16 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/originalExamples.kt");
}
@TestMetadata("overloadResolutionOnNullableContravariantParameter.kt")
public void testOverloadResolutionOnNullableContravariantParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/overloadResolutionOnNullableContravariantParameter.kt");
}
@TestMetadata("overloadResolutionOnNullableContravariantParameter_compat.kt")
public void testOverloadResolutionOnNullableContravariantParameter_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/overloadResolutionOnNullableContravariantParameter_compat.kt");
}
@TestMetadata("varargWithMoreSpecificSignature.kt")
public void testVarargWithMoreSpecificSignature() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/varargWithMoreSpecificSignature.kt");
@@ -29,4 +29,7 @@ object AnalysisFlags {
@JvmStatic
val allowResultReturnType by AnalysisFlag.Delegates.Boolean
@JvmStatic
val constraintSystemForOverloadResolution by AnalysisFlag.Delegates.ConstraintSystemForOverloadResolution
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInfixCall
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isSuperOrDelegatingConstructorCall
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionStatelessCallbacks
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.isCoroutineCallWithAdditionalInference
@@ -88,6 +90,9 @@ class KotlinResolutionStatelessCallbacksImpl(
override fun createConstraintSystemForOverloadResolution(
constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns
): SimpleConstraintSystem {
return SimpleConstraintSystemImpl(constraintInjector, builtIns)
return if (languageVersionSettings.getFlag(AnalysisFlags.constraintSystemForOverloadResolution).forNewInference())
SimpleConstraintSystemImpl(constraintInjector, builtIns)
else
ConstraintSystemBuilderImpl.forSpecificity()
}
}
@@ -0,0 +1,16 @@
// !WITH_NEW_INFERENCE
// !CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION: CONSTRAINT_SYSTEM_FOR_NEW_INFERENCE
open class A<T>(val value: T)
class B<T>(value: T) : A<T>(value)
fun <T> A<T>.foo(block: (T?) -> Unit) {
block(value)
}
fun <T> B<T>.foo(block: (T) -> Unit) {
block(value)
}
fun main() {
B("string").<!NI;OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> { }
}
@@ -0,0 +1,21 @@
package
public fun main(): kotlin.Unit
public fun </*0*/ T> A<T>.foo(/*0*/ block: (T?) -> kotlin.Unit): kotlin.Unit
public fun </*0*/ T> B<T>.foo(/*0*/ block: (T) -> kotlin.Unit): kotlin.Unit
public open class A</*0*/ T> {
public constructor A</*0*/ T>(/*0*/ value: T)
public final val value: T
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
}
public final class B</*0*/ T> : A<T> {
public constructor B</*0*/ T>(/*0*/ value: T)
public final override /*1*/ /*fake_override*/ val value: T
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
}
@@ -0,0 +1,16 @@
// !WITH_NEW_INFERENCE
// !CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION: CONSTRAINT_SYSTEM_FOR_OLD_INFERENCE
open class A<T>(val value: T)
class B<T>(value: T) : A<T>(value)
fun <T> A<T>.foo(block: (T?) -> Unit) {
block(value)
}
fun <T> B<T>.foo(block: (T) -> Unit) {
block(value)
}
fun main() {
B("string").foo { }
}
@@ -0,0 +1,21 @@
package
public fun main(): kotlin.Unit
public fun </*0*/ T> A<T>.foo(/*0*/ block: (T?) -> kotlin.Unit): kotlin.Unit
public fun </*0*/ T> B<T>.foo(/*0*/ block: (T) -> kotlin.Unit): kotlin.Unit
public open class A</*0*/ T> {
public constructor A</*0*/ T>(/*0*/ value: T)
public final val value: T
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
}
public final class B</*0*/ T> : A<T> {
public constructor B</*0*/ T>(/*0*/ value: T)
public final override /*1*/ /*fake_override*/ val value: T
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
}
@@ -0,0 +1,26 @@
// !WITH_NEW_INFERENCE
// !CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION: CONSTRAINT_SYSTEM_FOR_NEW_INFERENCE
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: a.kt
package a
enum class A { A1 }
fun <T : Enum<T>> foo(arg: T.() -> Unit) = 1
// FILE: b.kt
package b
fun <T : Any> foo(arg: T.() -> Unit) = 2
// FILE: test.kt
import a.*
import b.*
fun test() {
<!NI;OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!><A> { }
}
@@ -0,0 +1,30 @@
package
public fun test(): kotlin.Unit
package a {
public fun </*0*/ T : kotlin.Enum<T>> foo(/*0*/ arg: T.() -> kotlin.Unit): kotlin.Int
public final enum class A : kotlin.Enum<a.A> {
enum entry A1
private constructor A()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: a.A): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<a.A!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): a.A
public final /*synthesized*/ fun values(): kotlin.Array<a.A>
}
}
package b {
public fun </*0*/ T : kotlin.Any> foo(/*0*/ arg: T.() -> kotlin.Unit): kotlin.Int
}
@@ -0,0 +1,26 @@
// !WITH_NEW_INFERENCE
// !CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION: CONSTRAINT_SYSTEM_FOR_OLD_INFERENCE
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: a.kt
package a
enum class A { A1 }
fun <T : Enum<T>> foo(arg: T.() -> Unit) = 1
// FILE: b.kt
package b
fun <T : Any> foo(arg: T.() -> Unit) = 2
// FILE: test.kt
import a.*
import b.*
fun test() {
foo<A> { }
}
@@ -0,0 +1,30 @@
package
public fun test(): kotlin.Unit
package a {
public fun </*0*/ T : kotlin.Enum<T>> foo(/*0*/ arg: T.() -> kotlin.Unit): kotlin.Int
public final enum class A : kotlin.Enum<a.A> {
enum entry A1
private constructor A()
public final override /*1*/ /*fake_override*/ val name: kotlin.String
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: a.A): kotlin.Int
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<a.A!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): a.A
public final /*synthesized*/ fun values(): kotlin.Array<a.A>
}
}
package b {
public fun </*0*/ T : kotlin.Any> foo(/*0*/ arg: T.() -> kotlin.Unit): kotlin.Int
}
@@ -0,0 +1,24 @@
// !WITH_NEW_INFERENCE
// !CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION: CONSTRAINT_SYSTEM_FOR_NEW_INFERENCE
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: a.kt
package a
fun <T> foo(block: (T?) -> Unit) {}
// FILE: b.kt
package b
fun <K> foo(block: (K) -> Unit) {}
// FILE: test.kt
import a.*
import b.*
fun main() {
<!OI;OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!><String> { }
}
@@ -0,0 +1,11 @@
package
public fun main(): kotlin.Unit
package a {
public fun </*0*/ T> foo(/*0*/ block: (T?) -> kotlin.Unit): kotlin.Unit
}
package b {
public fun </*0*/ K> foo(/*0*/ block: (K) -> kotlin.Unit): kotlin.Unit
}
@@ -0,0 +1,24 @@
// !WITH_NEW_INFERENCE
// !CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION: CONSTRAINT_SYSTEM_FOR_OLD_INFERENCE
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: a.kt
package a
fun <T> foo(block: (T?) -> Unit) {}
// FILE: b.kt
package b
fun <K> foo(block: (K) -> Unit) {}
// FILE: test.kt
import a.*
import b.*
fun main() {
<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!><String> { }
}
@@ -0,0 +1,11 @@
package
public fun main(): kotlin.Unit
package a {
public fun </*0*/ T> foo(/*0*/ block: (T?) -> kotlin.Unit): kotlin.Unit
}
package b {
public fun </*0*/ K> foo(/*0*/ block: (K) -> kotlin.Unit): kotlin.Unit
}
@@ -23,6 +23,7 @@ const val SKIP_METADATA_VERSION_CHECK = "SKIP_METADATA_VERSION_CHECK"
const val ALLOW_RESULT_RETURN_TYPE = "ALLOW_RESULT_RETURN_TYPE"
const val INHERIT_MULTIFILE_PARTS = "INHERIT_MULTIFILE_PARTS"
const val SANITIZE_PARENTHESES = "SANITIZE_PARENTHESES"
const val CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION = "CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION"
data class CompilerTestLanguageVersionSettings(
private val initialLanguageFeatures: Map<LanguageFeature, LanguageFeature.State>,
@@ -64,7 +65,10 @@ fun parseLanguageVersionSettings(directives: Map<String, String>): CompilerTestL
analysisFlag(AnalysisFlags.skipMetadataVersionCheck, if (SKIP_METADATA_VERSION_CHECK in directives) true else null),
analysisFlag(AnalysisFlags.allowResultReturnType, if (ALLOW_RESULT_RETURN_TYPE in directives) true else null),
analysisFlag(JvmAnalysisFlags.inheritMultifileParts, if (INHERIT_MULTIFILE_PARTS in directives) true else null),
analysisFlag(JvmAnalysisFlags.sanitizeParentheses, if (SANITIZE_PARENTHESES in directives) true else null)
analysisFlag(JvmAnalysisFlags.sanitizeParentheses, if (SANITIZE_PARENTHESES in directives) true else null),
analysisFlag(AnalysisFlags.constraintSystemForOverloadResolution, directives[CONSTRAINT_SYSTEM_FOR_OVERLOAD_RESOLUTION]?.let {
ConstraintSystemForOverloadResolutionMode.valueOf(it)
})
)
if (apiVersionString == null && languageFeaturesString == null && analysisFlags.isEmpty()) {
@@ -17912,6 +17912,26 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.kt");
}
@TestMetadata("kt31670.kt")
public void testKt31670() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31670.kt");
}
@TestMetadata("kt31670_compat.kt")
public void testKt31670_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31670_compat.kt");
}
@TestMetadata("kt31758.kt")
public void testKt31758() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31758.kt");
}
@TestMetadata("kt31758_compat.kt")
public void testKt31758_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31758_compat.kt");
}
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/numberOfDefaults.kt");
@@ -17922,6 +17942,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/originalExamples.kt");
}
@TestMetadata("overloadResolutionOnNullableContravariantParameter.kt")
public void testOverloadResolutionOnNullableContravariantParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/overloadResolutionOnNullableContravariantParameter.kt");
}
@TestMetadata("overloadResolutionOnNullableContravariantParameter_compat.kt")
public void testOverloadResolutionOnNullableContravariantParameter_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/overloadResolutionOnNullableContravariantParameter_compat.kt");
}
@TestMetadata("varargWithMoreSpecificSignature.kt")
public void testVarargWithMoreSpecificSignature() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/varargWithMoreSpecificSignature.kt");
@@ -17902,6 +17902,26 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt10640.kt");
}
@TestMetadata("kt31670.kt")
public void testKt31670() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31670.kt");
}
@TestMetadata("kt31670_compat.kt")
public void testKt31670_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31670_compat.kt");
}
@TestMetadata("kt31758.kt")
public void testKt31758() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31758.kt");
}
@TestMetadata("kt31758_compat.kt")
public void testKt31758_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/kt31758_compat.kt");
}
@TestMetadata("numberOfDefaults.kt")
public void testNumberOfDefaults() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/numberOfDefaults.kt");
@@ -17912,6 +17932,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/originalExamples.kt");
}
@TestMetadata("overloadResolutionOnNullableContravariantParameter.kt")
public void testOverloadResolutionOnNullableContravariantParameter() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/overloadResolutionOnNullableContravariantParameter.kt");
}
@TestMetadata("overloadResolutionOnNullableContravariantParameter_compat.kt")
public void testOverloadResolutionOnNullableContravariantParameter_compat() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/overloadResolutionOnNullableContravariantParameter_compat.kt");
}
@TestMetadata("varargWithMoreSpecificSignature.kt")
public void testVarargWithMoreSpecificSignature() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/overloadConflicts/varargWithMoreSpecificSignature.kt");
@@ -41,5 +41,10 @@ class AnalysisFlag<out T> internal constructor(
object ListOfStrings {
operator fun provideDelegate(instance: Any?, property: KProperty<*>) = Delegate(property.name, emptyList<String>())
}
object ConstraintSystemForOverloadResolution {
operator fun provideDelegate(instance: Any?, property: KProperty<*>) =
Delegate(property.name, ConstraintSystemForOverloadResolutionMode.CONSTRAINT_SYSTEM_FOR_NEW_INFERENCE)
}
}
}
@@ -0,0 +1,12 @@
/*
* 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.config
enum class ConstraintSystemForOverloadResolutionMode {
CONSTRAINT_SYSTEM_FOR_OLD_INFERENCE, CONSTRAINT_SYSTEM_FOR_NEW_INFERENCE;
fun forNewInference(): Boolean = this == CONSTRAINT_SYSTEM_FOR_NEW_INFERENCE
}