Fix type inference issues for 'if' and 'when'.

Use 'expectedType' (when present) as an explicit type argument for a special construct call.
Unfortunately, this approach can't be used for elvis due to other elvis-related inference hacks.
Fixes KT-10807, KT-10811.
This also affects KT-6189: now we can infer proper type for 'if'.

If type inference for special call failed, and we found no type errors in sub-expressions,
report TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT error.
This (and the hack above) fixes KT-10809: code no longer compiles.
This commit is contained in:
Dmitry Petrov
2016-01-26 21:20:24 +03:00
parent e3e463ef70
commit 9db3440e72
28 changed files with 498 additions and 18 deletions
@@ -0,0 +1,20 @@
fun test1() {
if (true) {
when (true) {
true -> println()
}
} else {
System.out?.println() // kotlin.Unit?
}
}
fun test2() {
val mlist = arrayListOf("")
if (true) {
when (true) {
true -> println()
}
} else {
mlist.add("") // kotlin.Boolean
}
}
@@ -0,0 +1,4 @@
package
public fun test1(): kotlin.Unit
public fun test2(): kotlin.Unit
@@ -0,0 +1,17 @@
import java.util.*
import kotlin.comparisons.compareBy
import kotlin.comparisons.nullsLast
class Foo(val a: String, val b: Int)
fun getComp(): Comparator<Foo?> =
when {
else -> nullsLast(compareBy({ it.a }, { it.b }))
}
fun getCompInverted(): Comparator<Foo?> =
nullsLast(
when {
else -> compareBy({ it.a }, { it.b })
}
)
@@ -0,0 +1,13 @@
package
public fun getComp(): java.util.Comparator<Foo?>
public fun getCompInverted(): java.util.Comparator<Foo?>
public final class Foo {
public constructor Foo(/*0*/ a: kotlin.String, /*1*/ b: kotlin.Int)
public final val a: kotlin.String
public final val b: kotlin.Int
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,41 @@
import java.util.*
fun <T> nullable(x: T): T? = x
@Suppress("UNUSED_PARAMETER")
fun <T> select(x1: T, x2: T): T = x1
val test1 =
listOf(1, 2, 3).mapNotNullTo(ArrayList()) {
if (true) nullable(it) else null
}
val test2: MutableList<Int?> =
listOf(1, 2, 3).mapNotNullTo(ArrayList()) {
if (true) nullable(it) else null
}
val test3: MutableList<Int> =
listOf(1, 2, 3).mapNotNullTo(ArrayList()) {
if (true) nullable(it) else null
}
val test4: Collection<Int> =
listOf(1, 2, 3).flatMapTo(LinkedHashSet()) {
listOf(it)
}
val test5: Collection<Int> =
listOf(1, 2, 3).<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>flatMapTo(<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>LinkedHashSet<!>()) { // TODO
if (true) listOf(it) else listOf(it)
}<!>
val test6: Collection<Int> =
listOf(1, 2, 3).flatMapTo(LinkedHashSet<Int>()) {
if (true) listOf(it) else listOf(it)
}
val test7: Collection<Int> =
listOf(1, 2, 3).flatMapTo(LinkedHashSet()) {
select(listOf(it), listOf(it))
}
@@ -0,0 +1,11 @@
package
public val test1: java.util.ArrayList<kotlin.Int>
public val test2: kotlin.collections.MutableList<kotlin.Int?>
public val test3: kotlin.collections.MutableList<kotlin.Int>
public val test4: kotlin.collections.Collection<kotlin.Int>
public val test5: kotlin.collections.Collection<kotlin.Int>
public val test6: kotlin.collections.Collection<kotlin.Int>
public val test7: kotlin.collections.Collection<kotlin.Int>
public fun </*0*/ T> nullable(/*0*/ x: T): T?
@kotlin.Suppress(names = {"UNUSED_PARAMETER"}) public fun </*0*/ T> select(/*0*/ x1: T, /*1*/ x2: T): T