FIR: discriminate candidates with suspend conversion

This commit is contained in:
Jinseong Jeon
2020-09-09 12:54:50 -07:00
committed by Mikhail Glukhikh
parent 6de8ba40c1
commit 5fdd06676f
6 changed files with 30 additions and 8 deletions
@@ -240,7 +240,6 @@ fun Candidate.resolvePlainArgumentType(
// If the argument is of functional type and the expected type is a suspend function type, we need to do "suspend conversion."
// TODO: should refer to LanguageVersionSettings.SuspendConversion
// TODO: should prefer another candidate without suspend conversion when ambiguous
if (expectedType?.isSuspendFunctionType(session) == true &&
argumentTypeForApplicabilityCheck.isBuiltinFunctionalType(session) &&
!argumentTypeForApplicabilityCheck.isSuspendFunctionType(session)
@@ -253,6 +252,7 @@ fun Candidate.resolvePlainArgumentType(
isKFunctionType = argumentTypeForApplicabilityCheck.isKFunctionType(session)
)
substitutor.substituteOrSelf(argumentTypeForApplicabilityCheck)
usesSuspendConversion = true
}
checkApplicabilityForArgumentType(
@@ -97,6 +97,7 @@ class Candidate(
var resultingTypeForCallableReference: ConeKotlinType? = null
var outerConstraintBuilderEffect: (ConstraintSystemOperation.() -> Unit)? = null
var usesSAM: Boolean = false
var usesSuspendConversion: Boolean = false
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
lateinit var typeArgumentMapping: TypeArgumentMapping
@@ -42,7 +42,7 @@ class ConeOverloadConflictResolver(
candidates
return chooseMaximallySpecificCandidates(
fixedCandidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true
fixedCandidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true, discriminateSuspendConversions = true
)
}
@@ -63,7 +63,8 @@ class ConeOverloadConflictResolver(
candidates: Set<Candidate>,
discriminateGenerics: Boolean,
discriminateAbstracts: Boolean,
discriminateSAMs: Boolean
discriminateSAMs: Boolean,
discriminateSuspendConversions: Boolean,
): Set<Candidate> {
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
@@ -78,7 +79,23 @@ class ConeOverloadConflictResolver(
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(
filtered, discriminateGenerics, discriminateAbstracts, discriminateSAMs = false
filtered, discriminateGenerics, discriminateAbstracts, discriminateSAMs = false, discriminateSuspendConversions
)
}
}
if (discriminateSuspendConversions) {
val filtered = candidates.filterTo(mutableSetOf()) { !it.usesSuspendConversion }
when (filtered.size) {
1 -> return filtered
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(
filtered,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs = false,
discriminateSuspendConversions = false
)
}
}
@@ -90,7 +107,11 @@ class ConeOverloadConflictResolver(
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(
filtered, discriminateGenerics, discriminateAbstracts = false, discriminateSAMs = false
filtered,
discriminateGenerics,
discriminateAbstracts = false,
discriminateSAMs = false,
discriminateSuspendConversions = false
)
}
}
@@ -226,7 +226,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
is FirVariable<*> -> createKPropertyType(fir, resultingReceiverType, returnTypeRef)
else -> ConeKotlinErrorType(ConeSimpleDiagnostic("Unknown callable kind: ${fir::class}", DiagnosticKind.UnknownCallableKind))
}.let(candidate.substitutor::substituteOrSelf)
candidate.usesSuspendConversion = requireSuspendConversion
candidate.resultingTypeForCallableReference = resultingType
candidate.outerConstraintBuilderEffect = fun ConstraintSystemOperation.() {
addOtherSystem(candidate.system.asReadOnlyStorage())
@@ -14,6 +14,6 @@ fun test1() {
// candidate without suspend conversions is more specific
fun test2(f: () -> Int, g: suspend () -> Int) {
<!AMBIGUITY!>foo<!>(f)
foo(f)
foo(g)
}
@@ -15,5 +15,5 @@ fun test4(): suspend () -> Unit = useSuspendFn {}
fun test5() = useSuspendFn {}
fun test5(sfn: suspend () -> Unit) = ambiguous(sfn)
fun test6(fn: () -> Unit) = <!AMBIGUITY!>ambiguous<!>(fn)
fun test6(fn: () -> Unit) = ambiguous(fn)
fun test7(): () -> Unit = <!AMBIGUITY!>ambiguous<!> {}