[FIR] Implement SAM candidates discrimination

This commit is contained in:
Mikhail Glukhikh
2020-01-28 18:26:30 +03:00
parent c37a2d3dc3
commit 3f95ac341c
9 changed files with 37 additions and 12 deletions
@@ -110,7 +110,9 @@ class FirCallResolver(
return resultFunctionCall
}
private data class ResolutionResult(val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection<Candidate>)
private data class ResolutionResult(
val info: CallInfo, val applicability: CandidateApplicability, val candidates: Collection<Candidate>
)
private fun collectCandidates(functionCall: FirFunctionCall): ResolutionResult {
val explicitReceiver = functionCall.explicitReceiver
@@ -289,7 +291,7 @@ class FirCallResolver(
symbol: FirClassSymbol<*>,
typeArguments: List<FirTypeProjection>
): FirDelegatedConstructorCall? {
val scope = symbol.fir.unsubstitutedScope(session, scopeSession) ?: return null
val scope = symbol.fir.unsubstitutedScope(session, scopeSession)
val className = symbol.classId.shortClassName
val callInfo = CallInfo(
CallKind.Function,
@@ -313,7 +315,9 @@ class FirCallResolver(
return callResolver.selectCandidateFromGivenCandidates(delegatedConstructorCall, className, candidates)
}
fun <T> selectCandidateFromGivenCandidates(call: T, name: Name, candidates: Collection<Candidate>): T where T : FirResolvable, T : FirCall {
private fun <T> selectCandidateFromGivenCandidates(
call: T, name: Name, candidates: Collection<Candidate>
): T where T : FirResolvable, T : FirCall {
val result = CandidateCollector(this, resolutionStageRunner)
candidates.forEach { result.consumeCandidate(TowerGroup.Start, it) }
val bestCandidates = result.bestCandidates()
@@ -306,7 +306,9 @@ private fun Candidate.getExpectedTypeWithSAMConversion(
// TODO: resolvedCall.registerArgumentWithSamConversion(argument, SamConversionDescription(convertedTypeByOriginal, convertedTypeByCandidate!!))
return samResolver.getFunctionTypeForPossibleSamType(candidateExpectedType) ?: return null
return samResolver.getFunctionTypeForPossibleSamType(candidateExpectedType).apply {
usesSAM = true
} ?: return null
}
internal fun FirExpression.getExpectedType(
@@ -104,6 +104,7 @@ class Candidate(
lateinit var freshVariables: List<ConeTypeVariable>
var resultingTypeForCallableReference: ConeKotlinType? = null
var outerConstraintBuilderEffect: (ConstraintSystemOperation.() -> Unit)? = null
var usesSAM: Boolean = false
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>()
@@ -28,6 +28,14 @@ class ConeOverloadConflictResolver(
override fun chooseMaximallySpecificCandidates(
candidates: Set<Candidate>,
discriminateGenerics: Boolean
): Set<Candidate> {
return chooseMaximallySpecificCandidates(candidates, discriminateGenerics, discriminateSAMs = true)
}
private fun chooseMaximallySpecificCandidates(
candidates: Set<Candidate>,
discriminateGenerics: Boolean,
discriminateSAMs: Boolean
): Set<Candidate> {
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
@@ -35,6 +43,16 @@ class ConeOverloadConflictResolver(
findMaximallySpecificCall(candidates, true)?.let { return setOf(it) }
}
if (discriminateSAMs) {
val filtered = candidates.filterTo(mutableSetOf()) { !it.usesSAM }
when (filtered.size) {
1 -> return filtered
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(filtered, discriminateGenerics, discriminateSAMs = false)
}
}
return candidates
}
@@ -1,5 +1,5 @@
fun test(list: MutableList<String>) {
list.<!AMBIGUITY!>removeAll<!> {
<!UNRESOLVED_REFERENCE!>it<!>.<!AMBIGUITY!>isEmpty<!>()
list.removeAll {
it.isEmpty()
}
}
@@ -1,7 +1,7 @@
FILE: inapplicableRemoveAll.kt
public final fun test(list: R|kotlin/collections/MutableList<kotlin/String>|): R|kotlin/Unit| {
R|<local>/list|.<Ambiguity: removeAll, [kotlin/collections/removeAll, kotlin/collections/removeAll, kotlin/collections/removeAll, kotlin/collections/removeAll]>#(<L> = removeAll@fun <anonymous>(): R|ERROR CLASS: Ambiguity: isEmpty, [kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/text/isEmpty]| {
<Unresolved name: it>#.<Ambiguity: isEmpty, [kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/collections/isEmpty, kotlin/text/isEmpty]>#()
R|<local>/list|.R|kotlin/collections/removeAll|<R|kotlin/String|>(<L> = removeAll@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Boolean| {
R|<local>/it|.R|kotlin/text/isEmpty|()
}
)
}
@@ -11,8 +11,8 @@ public interface Runnable {
// FILE: k.kt
fun fail() {
<!AMBIGUITY!>foo<!>({ }, { })
<!AMBIGUITY!>foo<!>(::bar, { })
foo({ }, { })
foo(::bar, { })
}
fun foo(f: Runnable, selector: () -> Unit) {}
@@ -7,4 +7,4 @@ object X2
fun <T1> foo(x: T1, f: (T1) -> T1) = X1
fun <T2> foo(xf: () -> T2, f: (T2) -> T2) = X2
val test: X2 = <!AMBIGUITY!>foo<!>({ 0 }, { it -> it + 1 })
val test: X2 = foo({ 0 }, { it -> it + 1 })
@@ -21,6 +21,6 @@ interface B {
interface C : B, Other
fun test(c: C) {
c.<!AMBIGUITY!>pluginManagement<!> {
c.pluginManagement {
}
}