Check nullability in initial constraints

except constraints for receiver type (it can be accessed via safe call)
This commit is contained in:
Svetlana Isakova
2015-10-17 17:40:52 +03:00
parent bb9f7094e0
commit cb34498278
6 changed files with 18 additions and 13 deletions
@@ -6,7 +6,7 @@ interface A<T>
fun <T> infer(<!UNUSED_PARAMETER!>a<!>: A<T>) : T {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!> fun <T> infer(<!UNUSED_PARAMETER!>a<!>: A<T>) : T {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun test(nothing: Nothing?) { fun test(nothing: Nothing?) {
val <!UNUSED_VARIABLE!>i<!> = <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>infer<!>(<!TYPE_MISMATCH!>nothing<!>) val <!UNUSED_VARIABLE!>i<!> = <!TYPE_INFERENCE_INCORPORATION_ERROR!>infer<!>(<!TYPE_MISMATCH!>nothing<!>)
} }
fun sum(<!UNUSED_PARAMETER!>a<!> : IntArray) : Int { fun sum(<!UNUSED_PARAMETER!>a<!> : IntArray) : Int {
@@ -5,5 +5,5 @@ package d
fun <T> asList(<!UNUSED_PARAMETER!>t<!>: T) : List<T>? {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!> fun <T> asList(<!UNUSED_PARAMETER!>t<!>: T) : List<T>? {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
fun main(args : Array<String>) { fun main(args : Array<String>) {
val <!UNUSED_VARIABLE!>list<!> : List<String> = <!TYPE_MISMATCH!>asList("")<!> val <!UNUSED_VARIABLE!>list<!> : List<String> = <!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>asList("")<!>
} }
@@ -11,14 +11,14 @@ abstract class Buggy {
} }
val anotherThree : Int val anotherThree : Int
get() = <!TYPE_MISMATCH!>coll.find{ it > 3 }<!> // does not work here get() = coll.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>find{ it > 3 }<!> // does not work here
val yetAnotherThree : Int val yetAnotherThree : Int
get() = <!TYPE_MISMATCH!>coll.find({ v:Int -> v > 3 })<!> // neither here get() = coll.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>find({ v:Int -> v > 3 })<!> // neither here
val extendedGetter : Int val extendedGetter : Int
get() { get() {
return <!TYPE_MISMATCH!>coll.find{ it > 3 }<!> // not even here! return coll.<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>find{ it > 3 }<!> // not even here!
} }
} }
@@ -7,7 +7,7 @@ fun <T> bar(a: T, b: Map<T, String>) = b.get(a)
fun test(a: Int) { fun test(a: Int) {
foo(a, null) foo(a, null)
bar(a, <!NULL_FOR_NONNULL_TYPE!>null<!>) <!TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(a, <!NULL_FOR_NONNULL_TYPE!>null<!>)
} }
fun test1(a: Int) { fun test1(a: Int) {
foo(a, throw Exception()) foo(a, throw Exception())
@@ -21,7 +21,7 @@ fun <T> List<T>.contains1(e: @kotlin.internal.NoInfer T): Boolean = true
fun test(i: Int?, a: Any, l: List<Int>) { fun test(i: Int?, a: Any, l: List<Int>) {
l.<!TYPE_INFERENCE_INCORPORATION_ERROR!>contains1<!>(<!TYPE_MISMATCH!>a<!>) l.<!TYPE_INFERENCE_INCORPORATION_ERROR!>contains1<!>(<!TYPE_MISMATCH!>a<!>)
l.<!TYPE_INFERENCE_INCORPORATION_ERROR!>contains1<!>(<!TYPE_MISMATCH!>""<!>) l.<!TYPE_INFERENCE_INCORPORATION_ERROR!>contains1<!>(<!TYPE_MISMATCH!>""<!>)
l.contains1(<!TYPE_MISMATCH!>i<!>) l.<!TYPE_INFERENCE_INCORPORATION_ERROR!>contains1<!>(<!TYPE_MISMATCH!>i<!>)
} }
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.getNestedArguments import org.jetbrains.kotlin.types.typeUtil.getNestedArguments
import org.jetbrains.kotlin.types.typeUtil.isDefaultBound import org.jetbrains.kotlin.types.typeUtil.isDefaultBound
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import java.util.* import java.util.*
public class ConstraintSystemImpl : ConstraintSystem { public class ConstraintSystemImpl : ConstraintSystem {
@@ -474,15 +475,19 @@ public class ConstraintSystemImpl : ConstraintSystem {
} }
private fun satisfyInitialConstraints(): Boolean { private fun satisfyInitialConstraints(): Boolean {
fun JetType.substituteAndMakeNullable(): JetType? { fun JetType.substitute(): JetType? {
val substitutor = getSubstitutor(substituteOriginal = false) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) } val substitutor = getSubstitutor(substituteOriginal = false) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
val result = substitutor.substitute(this, Variance.INVARIANT) ?: return null return substitutor.substitute(this, Variance.INVARIANT) ?: return null
return TypeUtils.makeNullable(result)
} }
return initialConstraints.all { return initialConstraints.all {
val resultSubType = it.subtype.substituteAndMakeNullable() ?: return false constraint ->
val resultSuperType = it.superType.substituteAndMakeNullable() ?: return false val resultSubType = constraint.subtype.substitute()?.let {
when (it.kind) { // the call might be done via safe access, so we check for notNullable receiver type;
// 'unsafe call' error is reported otherwise later
if (constraint.position.kind != ConstraintPositionKind.RECEIVER_POSITION) it else it.makeNotNullable()
} ?: return false
val resultSuperType = constraint.superType.substitute() ?: return false
when (constraint.kind) {
SUB_TYPE -> JetTypeChecker.DEFAULT.isSubtypeOf(resultSubType, resultSuperType) SUB_TYPE -> JetTypeChecker.DEFAULT.isSubtypeOf(resultSubType, resultSuperType)
EQUAL -> JetTypeChecker.DEFAULT.equalTypes(resultSubType, resultSuperType) EQUAL -> JetTypeChecker.DEFAULT.equalTypes(resultSubType, resultSuperType)
} }