[FIR] Add discriminating generics into ConeOverloadConflictResolver

This commit is contained in:
Dmitriy Novozhilov
2019-11-06 13:42:55 +03:00
parent 86a8412b05
commit 665405c435
8 changed files with 59 additions and 51 deletions
@@ -93,7 +93,7 @@ class FirCallResolver(
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
bestCandidates.toSet()
} else {
conflictResolver.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false)
conflictResolver.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = true)
}
@@ -33,19 +33,19 @@ class ConeOverloadConflictResolver(
fun chooseMaximallySpecificCandidates(
candidates: Collection<Candidate>,
//checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean//,
//isDebuggerContext: Boolean
discriminateGenerics: Boolean
): Set<Candidate> {
candidates.setIfOneOrEmpty()?.let { return it }
val candidatesSet = candidates.toSet()
val maximallySpecific = findMaximallySpecificCall(candidatesSet, false/*, isDebuggerContext*/)
if (maximallySpecific != null) {
return setOf(maximallySpecific)
findMaximallySpecificCall(candidatesSet, false)?.let { return setOf(it) }
if (discriminateGenerics) {
findMaximallySpecificCall(candidatesSet, true)?.let { return setOf(it) }
}
return candidatesSet
}
private fun createFlatSignature(call: Candidate): FlatSignature<Candidate> {
@@ -224,6 +224,11 @@ class ConeOverloadConflictResolver(
return true
}
private fun <C> Collection<C>.setIfOneOrEmpty(): Set<C>? = when (size) {
0 -> emptySet()
1 -> setOf(single())
else -> null
}
}
object NoSubstitutor : TypeSubstitutorMarker
@@ -0,0 +1,17 @@
interface A
interface B : A
interface C
interface D : B, C
fun B.foo(): Int = 1
fun <T> T.foo(): String where T : A, T : C = ""
fun takeInt(x: Int) {}
fun test(d: D) {
val x = d.foo()
takeInt(x)
}
@@ -0,0 +1,21 @@
FILE: overloadByReceiver.kt
public abstract interface A : R|kotlin/Any| {
}
public abstract interface B : R|A| {
}
public abstract interface C : R|kotlin/Any| {
}
public abstract interface D : R|B|, R|C| {
}
public final fun R|B|.foo(): R|kotlin/Int| {
^foo Int(1)
}
public final fun <T : R|A|, R|C|> R|T|.foo(): R|kotlin/String| {
^foo String()
}
public final fun takeInt(x: R|kotlin/Int|): R|kotlin/Unit| {
}
public final fun test(d: R|D|): R|kotlin/Unit| {
lval x: R|kotlin/Int| = R|<local>/d|.R|/foo|()
R|/takeInt|(R|<local>/x|)
}
+1 -11
View File
@@ -21,14 +21,4 @@ class Base<T>(val x: T)
class Derived : Base<Int>(10)
val xx = Derived().x + 1
val t = throw AssertionError("")
interface A
interface B
interface C : A
class BC : B, C
fun C.analyze() {}
inline fun <reified T> T.analyze() where T : A, T : B {}
fun testAnalyze() {
BC().<!AMBIGUITY!>analyze<!>()
}
val t = throw AssertionError("")
@@ -57,22 +57,3 @@ FILE: problems.kt
public get(): R|kotlin/Int|
public final val t: R|kotlin/Nothing| = throw R|java/lang/AssertionError.AssertionError|(String())
public get(): R|kotlin/Nothing|
public abstract interface A : R|kotlin/Any| {
}
public abstract interface B : R|kotlin/Any| {
}
public abstract interface C : R|A| {
}
public final class BC : R|B|, R|C| {
public constructor(): R|BC| {
super<R|kotlin/Any|>()
}
}
public final fun R|C|.analyze(): R|kotlin/Unit| {
}
public final inline fun <reified T : R|A|, R|B|> R|T|.analyze(): R|kotlin/Unit| {
}
public final fun testAnalyze(): R|kotlin/Unit| {
R|/BC.BC|().<Ambiguity: analyze, [/analyze, /analyze]>#()
}
@@ -235,6 +235,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/resolve/arguments/lambda.kt");
}
@TestMetadata("overloadByReceiver.kt")
public void testOverloadByReceiver() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/arguments/overloadByReceiver.kt");
}
@TestMetadata("overloadWithDefault.kt")
public void testOverloadWithDefault() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/arguments/overloadWithDefault.kt");
@@ -2,17 +2,6 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// !USE_EXPERIMENTAL: kotlin.Experimental
import kotlin.experimental.ExperimentalTypeInference
interface ProducerScope<E> {
fun yield(e: E)
}
@UseExperimental(ExperimentalTypeInference::class)
fun <E> produce(@BuilderInference block: ProducerScope<E>.() -> Unit): ProducerScope<E> = TODO()
fun <K> filter(e: K, predicate: (K) -> Boolean) =
produce {
predicate(e)
yield(42)
}
fun test(x: List<Int>) {
x + x
}