Constraint system builder shouldn't drop nullability when comparing signatures for specificity.

This commit is contained in:
Dmitry Petrov
2016-03-03 16:18:04 +03:00
parent 8a2b80fe3f
commit 8660800af7
5 changed files with 38 additions and 15 deletions
@@ -37,7 +37,12 @@ import org.jetbrains.kotlin.types.typeUtil.defaultProjections
import org.jetbrains.kotlin.types.typeUtil.isDefaultBound
import java.util.*
class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystemBuilderImpl.Mode.INFERENCE) : ConstraintSystem.Builder {
enum class Mode {
INFERENCE,
SPECIFICITY
}
internal data class Constraint(
val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition
)
@@ -217,15 +222,13 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
generateTypeParameterBound(superType, subType, constraintKind.bound.reverse(), constraintContext)
return
}
// if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
// but constraint system should be solved anyway
val subTypeNotNullable = if (constraintContext.initial) TypeUtils.makeNotNullable(subType) else subType
val superTypeNotNullable = if (constraintContext.initial) TypeUtils.makeNotNullable(superType) else superType
val subType2 = simplifyType(subType, constraintContext.initial)
val superType2 = simplifyType(superType, constraintContext.initial)
val result = if (constraintKind == EQUAL) {
typeCheckingProcedure.equalTypes(subTypeNotNullable, superTypeNotNullable)
typeCheckingProcedure.equalTypes(subType2, superType2)
}
else {
typeCheckingProcedure.isSubtypeOf(subTypeNotNullable, superType)
typeCheckingProcedure.isSubtypeOf(subType2, superType)
}
if (!result) errors.add(newTypeInferenceOrParameterConstraintError(constraintPosition))
}
@@ -237,6 +240,15 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
simplifyConstraint(newSubType, superType)
}
private fun simplifyType(type: KotlinType, isInitialConstraint: Boolean): KotlinType =
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
type
else {
// if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
// but constraint system should be solved anyway
TypeUtils.makeNotNullable(type)
}
internal fun addBound(
typeVariable: TypeVariable,
constrainingType: KotlinType,
@@ -393,6 +405,10 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
override fun build(): ConstraintSystem {
return ConstraintSystemImpl(allTypeParameterBounds, usedInBounds, errors, initialConstraints, typeVariableSubstitutors)
}
companion object {
fun forSpecificity() = ConstraintSystemBuilderImpl(Mode.SPECIFICITY)
}
}
internal fun createTypeForFunctionPlaceholder(
@@ -37,7 +37,7 @@ fun <T> isSignatureNotLessSpecific(
if (specific.valueParameterTypes.size != general.valueParameterTypes.size) return false
val typeParameters = general.typeParameters
val constraintSystemBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl()
val constraintSystemBuilder: ConstraintSystem.Builder = ConstraintSystemBuilderImpl.forSpecificity()
val typeSubstitutor = constraintSystemBuilder.registerTypeVariables(callHandle, typeParameters)
var numConstraints = 0
@@ -5,4 +5,4 @@
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(<!UNUSED_PARAMETER!>x<!>: Array<Int>)<!> {}
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(vararg <!UNUSED_PARAMETER!>nn<!>: Number)<!> {}
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(<!UNUSED_PARAMETER!>nn<!>: Array<out Number>)<!> {}
<!CONFLICTING_JVM_DECLARATIONS!>fun foo(<!UNUSED_PARAMETER!>nn<!>: Array<out Number>)<!> {}
@@ -1,5 +1,10 @@
fun <T> List<T>?.foo() {}
fun <T1> List<T1>?.foo() {}
// NB Not a redeclaration
@JvmName("f1")
fun <T> List<T>.foo() {}
@JvmName("foo1")
fun <T2> List<T2>.foo() {}
fun <T1> bar(x: List<T1>) = x
@JvmName("bar1")
fun <T2> bar(x: List<T2>?) = x
@@ -1,4 +1,6 @@
package
@kotlin.jvm.JvmName(name = "f1") public fun </*0*/ T> kotlin.collections.List<T>.foo(): kotlin.Unit
public fun </*0*/ T> kotlin.collections.List<T>?.foo(): kotlin.Unit
public fun </*0*/ T1> bar(/*0*/ x: kotlin.collections.List<T1>): kotlin.collections.List<T1>
@kotlin.jvm.JvmName(name = "bar1") public fun </*0*/ T2> bar(/*0*/ x: kotlin.collections.List<T2>?): kotlin.collections.List<T2>?
public fun </*0*/ T1> kotlin.collections.List<T1>?.foo(): kotlin.Unit
@kotlin.jvm.JvmName(name = "foo1") public fun </*0*/ T2> kotlin.collections.List<T2>.foo(): kotlin.Unit