K2: Fix false-positive OVERLOAD_RESOLUTION_AMBIGUITY with PCLA Mostly, the idea of this change is reproducing K1 behavior with stub types ^KT-67875 Fixed ^KT-67947 Related
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt index 9ea75ac..4bd11b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/AbstractConeCallConflictResolver.kt
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.calls.results.* import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.requireOrDescribe +import org.jetbrains.kotlin.types.model.safeSubstitute import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment @@ -191,16 +192,16 @@ ): List<TypeWithConversion> { return buildList { val session = inferenceComponents.session - addIfNotNull(called.receiverParameter?.typeRef?.coneType?.fullyExpandedType(session)?.let { TypeWithConversion(it) }) + addIfNotNull(called.receiverParameter?.typeRef?.coneType?.prepareType(session, call)?.let { TypeWithConversion(it) }) val typeForCallableReference = call.resultingTypeForCallableReference if (typeForCallableReference != null) { // Return type isn't needed here v typeForCallableReference.typeArguments.dropLast(1) .mapTo(this) { - TypeWithConversion((it as ConeKotlinType).fullyExpandedType(session).removeTypeVariableTypes(session.typeContext)) + TypeWithConversion((it as ConeKotlinType).prepareType(session, call).removeTypeVariableTypes(session.typeContext)) } } else { - called.contextReceivers.mapTo(this) { TypeWithConversion(it.typeRef.coneType.fullyExpandedType(session)) } + called.contextReceivers.mapTo(this) { TypeWithConversion(it.typeRef.coneType.prepareType(session, call)) } call.argumentMapping?.mapTo(this) { (_, parameter) -> parameter.toTypeWithConversion(session, call) } @@ -222,7 +223,7 @@ } private fun FirValueParameter.toTypeWithConversion(session: FirSession, call: Candidate): TypeWithConversion { - val argumentType = argumentType().fullyExpandedType(session) + val argumentType = argumentType().prepareType(session, call) val functionTypeForSam = toFunctionTypeForSamOrNull(call) return if (functionTypeForSam == null) { TypeWithConversion(argumentType) @@ -231,6 +232,25 @@ } } + private fun ConeKotlinType.prepareType(session: FirSession, candidate: Candidate): ConeKotlinType { + val expanded = fullyExpandedType(session) + if (!candidate.system.usesOuterCs) return expanded + // For resolving overloads in PCLA of the following form: + // fun foo(vararg values: Tv) + // fun foo(x: A<Tv>) + // In K1, all Tv variables have been replaced with relevant stub types + // Thus, both of the overloads were considered as not less specific than other (stubTypesAreEqualToAnything=true) + // And after that the one with A<Tv> is chosen because it was discriminated via [ConeOverloadConflictResolver.exactMaxWith] + // as not containing varargs. + // Thus we reproduce K1 behavior with stub types (even though we don't like then much, but it's very local) + // + // But this behavior looks quite hacky because it seems that the second overload should win even without varargs + // on the first one. + // TODO: Get rid of hacky K1 behavior (KT-67947) + return candidate.system.buildNotFixedVariablesToStubTypesSubstitutor() + .safeSubstitute(session.typeContext, expanded) as ConeKotlinType + } + private fun FirValueParameter.toFunctionTypeForSamOrNull(call: Candidate): ConeKotlinType? { val functionTypesOfSamConversions = call.functionTypesOfSamConversions ?: return null return call.argumentMapping?.entries?.firstNotNullOfOrNull {
diff --git a/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.fir.kt b/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.fir.kt deleted file mode 100644 index b45ec67..0000000 --- a/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.fir.kt +++ /dev/null
@@ -1,27 +0,0 @@ -// WITH_STDLIB -// ISSUE: KT-67875 - -// FILE: MyClass.java -public class MyClass<T> {} - -// FILE: MyClassBuilder.java -public class MyClassBuilder<T> { - public MyClassBuilder<T> makeClass(T... values) {} - - public MyClassBuilder<T> makeClass(Iterable<? extends T> it) {} - - public MyClass<T> build() { return null; } -} - -// FILE: main.kt -inline fun <T: Any> myClassOf( - init: MyClassBuilder<T>.() -> Unit -): MyClass<T> = MyClassBuilder<T>().apply(init).build() - -object Foo { - val myClass = <!CANNOT_INFER_PARAMETER_TYPE, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>myClassOf<!> { - <!OVERLOAD_RESOLUTION_AMBIGUITY!>makeClass<!>(listOf("a", "b")) - } - - private val myClassType: MyClass<String> = myClass -} \ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.kt b/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.kt index ae85781..e74a886 100644 --- a/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.kt +++ b/compiler/testData/diagnostics/tests/builderInference/issues/kt67875.kt
@@ -1,3 +1,4 @@ +// FIR_IDENTICAL // WITH_STDLIB // ISSUE: KT-67875
diff --git a/compiler/testData/diagnostics/tests/builderInference/overloadResolutionWithTypeVariables.fir.kt b/compiler/testData/diagnostics/tests/builderInference/overloadResolutionWithTypeVariables.fir.kt index 3c3dbab..3f8e1f1 100644 --- a/compiler/testData/diagnostics/tests/builderInference/overloadResolutionWithTypeVariables.fir.kt +++ b/compiler/testData/diagnostics/tests/builderInference/overloadResolutionWithTypeVariables.fir.kt
@@ -27,12 +27,12 @@ fun <E> generate(f: Controller<E>.() -> Unit) {} fun bar(inv: Inv<String>, out: Out<String>, i: In<CharSequence>, cs: CharSequence) { - <!CANNOT_INFER_PARAMETER_TYPE, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>generate<!> { - <!OVERLOAD_RESOLUTION_AMBIGUITY!>foo1<!>(inv) + generate { + foo1(inv) } - <!CANNOT_INFER_PARAMETER_TYPE, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>generate<!> { - <!OVERLOAD_RESOLUTION_AMBIGUITY!>foo2<!>(out) + generate { + foo2(out) } <!CANNOT_INFER_PARAMETER_TYPE, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>generate<!> {