Add compatibility resolve when variable has "bad" intersection type

#KT-39468 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2020-07-02 16:10:57 +03:00
parent 92a51b9794
commit d51bb2c053
13 changed files with 238 additions and 0 deletions
@@ -10059,6 +10059,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/commonSuperTypeOfErrorTypes.kt");
}
@TestMetadata("compatibilityResolveWhenVariableHasComplexIntersectionType.kt")
public void testCompatibilityResolveWhenVariableHasComplexIntersectionType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/compatibilityResolveWhenVariableHasComplexIntersectionType.kt");
}
@TestMetadata("completeInferenceIfManyFailed.kt")
public void testCompleteInferenceIfManyFailed() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt");
@@ -10209,6 +10214,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt");
}
@TestMetadata("intersectionTypesWithContravariantTypes.kt")
public void testIntersectionTypesWithContravariantTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypesWithContravariantTypes.kt");
}
@TestMetadata("intersectionWithEnum.kt")
public void testIntersectionWithEnum() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt");
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinResolutionStatelessCallbacksImpl(
@@ -87,6 +89,10 @@ class KotlinResolutionStatelessCallbacksImpl(
return org.jetbrains.kotlin.resolve.calls.inference.isApplicableCallForBuilderInference(descriptor, languageVersionSettings)
}
override fun isOldIntersectionIsEmpty(types: Collection<KotlinType>): Boolean {
return TypeIntersector.intersectTypes(types) == null
}
override fun createConstraintSystemForOverloadResolution(
constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns,
): SimpleConstraintSystem {
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.UnwrappedType
@@ -36,6 +37,8 @@ interface KotlinResolutionStatelessCallbacks {
fun isCoroutineCall(argument: KotlinCallArgument, parameter: ValueParameterDescriptor): Boolean
fun isApplicableCallForBuilderInference(descriptor: CallableDescriptor, languageVersionSettings: LanguageVersionSettings): Boolean
fun isOldIntersectionIsEmpty(types: Collection<KotlinType>): Boolean
fun createConstraintSystemForOverloadResolution(
constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns
): SimpleConstraintSystem
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal object CheckVisibility : ResolutionPart() {
@@ -250,6 +251,24 @@ internal object PostponedVariablesInitializerResolutionPart : ResolutionPart() {
}
}
internal object CompatibilityOfTypeVariableAsIntersectionTypePart : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
for ((_, variableWithConstraints) in csBuilder.currentStorage().notFixedTypeVariables) {
val constraints = variableWithConstraints.constraints.filter { csBuilder.isProperType(it.type) }
if (constraints.size <= 1) continue
if (constraints.any { it.kind.isLower() || it.kind.isEqual() }) continue
// See TypeBoundsImpl.computeValues(). It returns several values for such situation which means an error in OI
if (callComponents.statelessCallbacks.isOldIntersectionIsEmpty(constraints.map { it.type }.cast())) {
addDiagnostic(LowerPriorityToPreserveCompatibility)
return
}
}
}
}
internal object CheckExplicitReceiverKindConsistency : ResolutionPart() {
private fun KotlinResolutionCandidate.hasError(): Nothing =
error(
@@ -228,6 +228,7 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
CheckArgumentsInParenthesis,
CheckExternalArgument,
EagerResolveOfCallableReferences,
CompatibilityOfTypeVariableAsIntersectionTypePart,
PostponedVariablesInitializerResolutionPart
),
INVOKE(*FUNCTION.resolutionSequence.toTypedArray()),
@@ -0,0 +1,37 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
abstract class Foo<T>
abstract class Bar<T> : Foo<T>(), Comparable<Bar<T>>
object Scope {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, other: Foo<T>) {}
object Nested {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T) {}
fun test(b: Bar<Long>) {
<!DEBUG_INFO_CALL("fqName: Scope.Nested.greater; typeCall: function")!>greater(b, b)<!>
}
}
}
object OnlyOne {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T) {}
fun test(b: Bar<Long>) {
<!DEBUG_INFO_CALL("fqName: OnlyOne.greater; typeCall: function")!>greater(b, b)<!>
}
}
object GoodOldCandidate {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T) {}
object Nested {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, other: Foo<T>) {}
fun test(b: Bar<Long>) {
<!DEBUG_INFO_CALL("fqName: GoodOldCandidate.Nested.greater; typeCall: function")!>greater(b, b)<!>
}
}
}
@@ -0,0 +1,37 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
abstract class Foo<T>
abstract class Bar<T> : Foo<T>(), Comparable<Bar<T>>
object Scope {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, other: Foo<T>) {}
object Nested {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T) {}
fun test(b: Bar<Long>) {
<!DEBUG_INFO_CALL("fqName: Scope.greater; typeCall: function")!><!COMPATIBILITY_WARNING!>greater<!>(b, b)<!>
}
}
}
object OnlyOne {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T) {}
fun test(b: Bar<Long>) {
<!DEBUG_INFO_CALL("fqName: OnlyOne.greater; typeCall: function")!>greater(b, b)<!>
}
}
object GoodOldCandidate {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T) {}
object Nested {
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, other: Foo<T>) {}
fun test(b: Bar<Long>) {
<!DEBUG_INFO_CALL("fqName: GoodOldCandidate.Nested.greater; typeCall: function")!>greater(b, b)<!>
}
}
}
@@ -0,0 +1,59 @@
package
public abstract class Bar</*0*/ T> : Foo<T>, kotlin.Comparable<Bar<T>> {
public constructor Bar</*0*/ T>()
public abstract override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Bar<T>): kotlin.Int
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class Foo</*0*/ T> {
public constructor Foo</*0*/ 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 object GoodOldCandidate {
private constructor GoodOldCandidate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ t: T): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public object Nested {
private constructor Nested()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ other: Foo<T>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(/*0*/ b: Bar<kotlin.Long>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public object OnlyOne {
private constructor OnlyOne()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ t: T): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(/*0*/ b: Bar<kotlin.Long>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public object Scope {
private constructor Scope()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ other: Foo<T>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public object Nested {
private constructor Nested()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ t: T): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(/*0*/ b: Bar<kotlin.Long>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -0,0 +1,13 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
abstract class Foo<T>
abstract class Bar<T> : Foo<T>(), Comparable<Bar<T>>
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T): Int = 0
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, other: Foo<T>): String = ""
fun test(b: Bar<Long>) {
val result = <!AMBIGUITY!>greater<!>(b, b)
<!DEBUG_INFO_EXPRESSION_TYPE("ERROR CLASS: Ambiguity: greater, [/greater, /greater]")!>result<!>
}
@@ -0,0 +1,13 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
abstract class Foo<T>
abstract class Bar<T> : Foo<T>(), Comparable<Bar<T>>
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, t: T): Int = 0
fun <T : Comparable<T>, S : T> greater(x: Bar<in S>, other: Foo<T>): String = ""
fun test(b: Bar<Long>) {
val result = greater(b, b)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>result<!>
}
@@ -0,0 +1,20 @@
package
public fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ other: Foo<T>): kotlin.String
public fun </*0*/ T : kotlin.Comparable<T>, /*1*/ S : T> greater(/*0*/ x: Bar<in S>, /*1*/ t: T): kotlin.Int
public fun test(/*0*/ b: Bar<kotlin.Long>): kotlin.Unit
public abstract class Bar</*0*/ T> : Foo<T>, kotlin.Comparable<Bar<T>> {
public constructor Bar</*0*/ T>()
public abstract override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: Bar<T>): kotlin.Int
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public abstract class Foo</*0*/ T> {
public constructor Foo</*0*/ 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
}
@@ -10066,6 +10066,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/inference/commonSuperTypeOfErrorTypes.kt");
}
@TestMetadata("compatibilityResolveWhenVariableHasComplexIntersectionType.kt")
public void testCompatibilityResolveWhenVariableHasComplexIntersectionType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/compatibilityResolveWhenVariableHasComplexIntersectionType.kt");
}
@TestMetadata("completeInferenceIfManyFailed.kt")
public void testCompleteInferenceIfManyFailed() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt");
@@ -10216,6 +10221,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt");
}
@TestMetadata("intersectionTypesWithContravariantTypes.kt")
public void testIntersectionTypesWithContravariantTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypesWithContravariantTypes.kt");
}
@TestMetadata("intersectionWithEnum.kt")
public void testIntersectionWithEnum() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt");
@@ -10061,6 +10061,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/commonSuperTypeOfErrorTypes.kt");
}
@TestMetadata("compatibilityResolveWhenVariableHasComplexIntersectionType.kt")
public void testCompatibilityResolveWhenVariableHasComplexIntersectionType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/compatibilityResolveWhenVariableHasComplexIntersectionType.kt");
}
@TestMetadata("completeInferenceIfManyFailed.kt")
public void testCompleteInferenceIfManyFailed() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt");
@@ -10211,6 +10216,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt");
}
@TestMetadata("intersectionTypesWithContravariantTypes.kt")
public void testIntersectionTypesWithContravariantTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypesWithContravariantTypes.kt");
}
@TestMetadata("intersectionWithEnum.kt")
public void testIntersectionWithEnum() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt");