Fix inference when captured type is used as a lambda parameter type
Use lower approximation bound to obtain acceptable types for lambda parameters those types depend on captured type #KT-12238 Fixed #KT-10627 Fixed
This commit is contained in:
+8
-1
@@ -254,7 +254,14 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
|
||||
var expectedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||
|
||||
val currentSubstitutor = constraintSystem.build().currentSubstitutor
|
||||
val newSubstitution = object : DelegatedTypeSubstitution(currentSubstitutor.substitution) {
|
||||
override fun approximateContravariantCapturedTypes() = true
|
||||
}
|
||||
|
||||
var expectedType = newSubstitution.buildSubstitutor().substitute(effectiveExpectedType, Variance.IN_VARIANCE)
|
||||
|
||||
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
|
||||
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false)
|
||||
}
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// !CHECK_TYPE
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
class B<E>
|
||||
|
||||
fun <T> B<T>.foo(f: (T) -> Unit) {}
|
||||
fun <T> B<T>.bar(f: (T, T) -> Unit, g: (T, T) -> Unit) {}
|
||||
|
||||
fun number(x: Number) {}
|
||||
fun Number.foobar() {}
|
||||
|
||||
fun test(b: B<out Number>) {
|
||||
b.foo {
|
||||
it checkType { _<Number>() }
|
||||
it.toInt()
|
||||
}
|
||||
|
||||
b.foo { x ->
|
||||
x checkType { _<Number>() }
|
||||
x.toInt()
|
||||
}
|
||||
|
||||
b.bar({ x, y ->
|
||||
x checkType { _<Number>() }
|
||||
y checkType { _<Number>() }
|
||||
x.toInt()
|
||||
y.toInt()
|
||||
}) { u, w ->
|
||||
u checkType { _<Number>() }
|
||||
w checkType { _<Number>() }
|
||||
|
||||
u.toInt()
|
||||
w.toInt()
|
||||
}
|
||||
|
||||
b.foo(::number)
|
||||
b.foo(Number::foobar)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public fun number(/*0*/ x: kotlin.Number): kotlin.Unit
|
||||
public fun test(/*0*/ b: B<out kotlin.Number>): kotlin.Unit
|
||||
public fun </*0*/ T> B<T>.bar(/*0*/ f: (T, T) -> kotlin.Unit, /*1*/ g: (T, T) -> kotlin.Unit): kotlin.Unit
|
||||
public fun </*0*/ T> B<T>.foo(/*0*/ f: (T) -> kotlin.Unit): kotlin.Unit
|
||||
public fun kotlin.Number.foobar(): kotlin.Unit
|
||||
|
||||
public final class B</*0*/ E> {
|
||||
public constructor B</*0*/ E>()
|
||||
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,22 @@
|
||||
// !CHECK_TYPE
|
||||
// FILE: A.java
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class A<T> {
|
||||
void test(Consumer<? super T> consumer) {}
|
||||
}
|
||||
|
||||
// FILE: 1.kt
|
||||
import java.util.function.Consumer
|
||||
|
||||
fun test(a: A<out Number>) {
|
||||
a.test (Consumer {
|
||||
it checkType { _<Number>() }
|
||||
it.toInt()
|
||||
})
|
||||
|
||||
a.test {
|
||||
it checkType { _<Number>() }
|
||||
it.toInt()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package
|
||||
|
||||
public fun test(/*0*/ a: A<out kotlin.Number>): kotlin.Unit
|
||||
|
||||
public open class A</*0*/ T : kotlin.Any!> {
|
||||
public constructor A</*0*/ T : kotlin.Any!>()
|
||||
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/*package*/ open fun test(/*0*/ consumer: java.util.function.Consumer<in T!>!): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+6
@@ -35,6 +35,12 @@ public class DiagnosticsWithJava8TestGenerated extends AbstractDiagnosticsWithFu
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJava8"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("samWithConsumer.kt")
|
||||
public void testSamWithConsumer() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/samWithConsumer.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithJava8/annotations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -15414,6 +15414,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedTypesInLambdaParameter.kt")
|
||||
public void testCapturedTypesInLambdaParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/capturedTypesInLambdaParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("constructorVsCompanion.kt")
|
||||
public void testConstructorVsCompanion() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/constructorVsCompanion.kt");
|
||||
|
||||
Reference in New Issue
Block a user