NI: Try to solve constraint system with another flexibility from a type variable if couldn't solve

^KT-36254 Fixed
This commit is contained in:
Victor Petukhov
2020-02-06 15:45:20 +03:00
parent b5dd16784a
commit ae39d748e4
10 changed files with 141 additions and 9 deletions
@@ -16476,6 +16476,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt"); runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt");
} }
@TestMetadata("flexibilityThroughTypeVariable.kt")
public void testFlexibilityThroughTypeVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt");
}
@TestMetadata("flexibilityThroughTypeVariableOut.kt")
public void testFlexibilityThroughTypeVariableOut() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt");
}
@TestMetadata("genericsAndArrays.kt") @TestMetadata("genericsAndArrays.kt")
public void testGenericsAndArrays() throws Exception { public void testGenericsAndArrays() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt"); runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt");
@@ -173,7 +173,7 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
} }
} }
private fun TypeParameterDescriptor.shouldBeFlexible(): Boolean { fun TypeParameterDescriptor.shouldBeFlexible(): Boolean {
return upperBounds.any { return upperBounds.any {
it.isFlexible() || ((it.constructor.declarationDescriptor as? TypeParameterDescriptor)?.run { shouldBeFlexible() } ?: false) it.isFlexible() || ((it.constructor.declarationDescriptor as? TypeParameterDescriptor)?.run { shouldBeFlexible() } ?: false)
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.resolve.calls.inference.components package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.shouldBeFlexible
import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.types.model.*
@@ -27,7 +28,11 @@ class ConstraintIncorporator(
fun getConstraintsForVariable(typeVariable: TypeVariableMarker): Collection<Constraint> fun getConstraintsForVariable(typeVariable: TypeVariableMarker): Collection<Constraint>
fun addNewIncorporatedConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) fun addNewIncorporatedConstraint(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
shouldTryUseDifferentFlexibilityForUpperType: Boolean
)
fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext) fun addNewIncorporatedConstraint(typeVariable: TypeVariableMarker, type: KotlinTypeMarker, constraintContext: ConstraintContext)
} }
@@ -49,11 +54,14 @@ class ConstraintIncorporator(
typeVariable: TypeVariableMarker, typeVariable: TypeVariableMarker,
constraint: Constraint constraint: Constraint
) { ) {
val shouldBeTypeVariableFlexible =
typeVariable is TypeVariableFromCallableDescriptor && typeVariable.originalTypeParameter.shouldBeFlexible()
// \alpha <: constraint.type // \alpha <: constraint.type
if (constraint.kind != ConstraintKind.LOWER) { if (constraint.kind != ConstraintKind.LOWER) {
getConstraintsForVariable(typeVariable).forEach { getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.UPPER) { if (it.kind != ConstraintKind.UPPER) {
addNewIncorporatedConstraint(it.type, constraint.type) addNewIncorporatedConstraint(it.type, constraint.type, shouldBeTypeVariableFlexible)
} }
} }
} }
@@ -62,7 +70,7 @@ class ConstraintIncorporator(
if (constraint.kind != ConstraintKind.UPPER) { if (constraint.kind != ConstraintKind.UPPER) {
getConstraintsForVariable(typeVariable).forEach { getConstraintsForVariable(typeVariable).forEach {
if (it.kind != ConstraintKind.LOWER) { if (it.kind != ConstraintKind.LOWER) {
addNewIncorporatedConstraint(constraint.type, it.type) addNewIncorporatedConstraint(constraint.type, it.type, shouldBeTypeVariableFlexible)
} }
} }
} }
@@ -148,10 +148,33 @@ class ConstraintInjector(
} }
} }
fun runIsSubtypeOf(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) { fun runIsSubtypeOf(
if (!AbstractTypeChecker.isSubtypeOf(this@TypeCheckerContext as AbstractTypeCheckerContext, lowerType, upperType)) { lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
shouldTryUseDifferentFlexibilityForUpperType: Boolean = false
) {
fun isSubtypeOf(upperType: KotlinTypeMarker) =
AbstractTypeChecker.isSubtypeOf(
this@TypeCheckerContext as AbstractTypeCheckerContext,
lowerType,
upperType
)
if (!isSubtypeOf(upperType)) {
// todo improve error reporting -- add information about base types // todo improve error reporting -- add information about base types
c.addError(NewConstraintError(lowerType, upperType, position)) if (shouldTryUseDifferentFlexibilityForUpperType && upperType is SimpleType) {
/*
* Please don't reuse this logic.
* It's necessary to solve constraint systems when flexibility isn't propagated through a type variable.
* It's OK in the old inference because it uses already substituted types, that are with the correct flexibility.
*/
val flexibleUpperType = createFlexibleType(upperType, upperType.withNullability(true))
if (!isSubtypeOf(flexibleUpperType)) {
c.addError(NewConstraintError(lowerType, flexibleUpperType, position))
}
} else {
c.addError(NewConstraintError(lowerType, upperType, position))
}
} }
} }
@@ -181,10 +204,14 @@ class ConstraintInjector(
} }
// from ConstraintIncorporator.Context // from ConstraintIncorporator.Context
override fun addNewIncorporatedConstraint(lowerType: KotlinTypeMarker, upperType: KotlinTypeMarker) { override fun addNewIncorporatedConstraint(
lowerType: KotlinTypeMarker,
upperType: KotlinTypeMarker,
shouldTryUseDifferentFlexibilityForUpperType: Boolean
) {
if (lowerType === upperType) return if (lowerType === upperType) return
if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) { if (c.isAllowedType(lowerType) && c.isAllowedType(upperType)) {
runIsSubtypeOf(lowerType, upperType) runIsSubtypeOf(lowerType, upperType, shouldTryUseDifferentFlexibilityForUpperType)
} }
} }
@@ -0,0 +1,18 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
// Issue: KT-36254
// FILE: Convertor.java
public interface Convertor<Src, Dst> {
Dst convert(Src o);
}
// FILE: main.kt
fun takeConvertor(c: Convertor<String, String>) {}
fun main() {
takeConvertor(Convertor { null })
}
@@ -0,0 +1,11 @@
package
public fun main(): kotlin.Unit
public fun takeConvertor(/*0*/ c: Convertor<kotlin.String, kotlin.String>): kotlin.Unit
public interface Convertor</*0*/ Src : kotlin.Any!, /*1*/ Dst : kotlin.Any!> {
public abstract fun convert(/*0*/ o: Src!): Dst!
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,20 @@
// !LANGUAGE: +NewInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
// Issue: KT-36254
// FILE: Convertor.java
public interface Convertor<Src, Dst> {
Out<Dst> convert(Out<Src> o);
}
// FILE: main.kt
fun takeConvertor(c: Convertor<String, String>) {}
class Out<out T> {}
fun main(o: Out<Nothing?>) {
takeConvertor(Convertor { o })
}
@@ -0,0 +1,18 @@
package
public fun main(/*0*/ o: Out<kotlin.Nothing?>): kotlin.Unit
public fun takeConvertor(/*0*/ c: Convertor<kotlin.String, kotlin.String>): kotlin.Unit
public interface Convertor</*0*/ Src : kotlin.Any!, /*1*/ Dst : kotlin.Any!> {
public abstract fun convert(/*0*/ o: Out<Src!>!): Out<Dst!>!
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 Out</*0*/ out T> {
public constructor Out</*0*/ out 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
}
@@ -16483,6 +16483,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt"); runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt");
} }
@TestMetadata("flexibilityThroughTypeVariable.kt")
public void testFlexibilityThroughTypeVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt");
}
@TestMetadata("flexibilityThroughTypeVariableOut.kt")
public void testFlexibilityThroughTypeVariableOut() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt");
}
@TestMetadata("genericsAndArrays.kt") @TestMetadata("genericsAndArrays.kt")
public void testGenericsAndArrays() throws Exception { public void testGenericsAndArrays() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt"); runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt");
@@ -16478,6 +16478,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt"); runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/entrySet.kt");
} }
@TestMetadata("flexibilityThroughTypeVariable.kt")
public void testFlexibilityThroughTypeVariable() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariable.kt");
}
@TestMetadata("flexibilityThroughTypeVariableOut.kt")
public void testFlexibilityThroughTypeVariableOut() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/flexibilityThroughTypeVariableOut.kt");
}
@TestMetadata("genericsAndArrays.kt") @TestMetadata("genericsAndArrays.kt")
public void testGenericsAndArrays() throws Exception { public void testGenericsAndArrays() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt"); runTest("compiler/testData/diagnostics/tests/platformTypes/methodCall/genericsAndArrays.kt");