FIR: discriminate candidates with suspend conversion
This commit is contained in:
committed by
Mikhail Glukhikh
parent
6de8ba40c1
commit
5fdd06676f
@@ -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."
|
// 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 refer to LanguageVersionSettings.SuspendConversion
|
||||||
// TODO: should prefer another candidate without suspend conversion when ambiguous
|
|
||||||
if (expectedType?.isSuspendFunctionType(session) == true &&
|
if (expectedType?.isSuspendFunctionType(session) == true &&
|
||||||
argumentTypeForApplicabilityCheck.isBuiltinFunctionalType(session) &&
|
argumentTypeForApplicabilityCheck.isBuiltinFunctionalType(session) &&
|
||||||
!argumentTypeForApplicabilityCheck.isSuspendFunctionType(session)
|
!argumentTypeForApplicabilityCheck.isSuspendFunctionType(session)
|
||||||
@@ -253,6 +252,7 @@ fun Candidate.resolvePlainArgumentType(
|
|||||||
isKFunctionType = argumentTypeForApplicabilityCheck.isKFunctionType(session)
|
isKFunctionType = argumentTypeForApplicabilityCheck.isKFunctionType(session)
|
||||||
)
|
)
|
||||||
substitutor.substituteOrSelf(argumentTypeForApplicabilityCheck)
|
substitutor.substituteOrSelf(argumentTypeForApplicabilityCheck)
|
||||||
|
usesSuspendConversion = true
|
||||||
}
|
}
|
||||||
|
|
||||||
checkApplicabilityForArgumentType(
|
checkApplicabilityForArgumentType(
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ class Candidate(
|
|||||||
var resultingTypeForCallableReference: ConeKotlinType? = null
|
var resultingTypeForCallableReference: ConeKotlinType? = null
|
||||||
var outerConstraintBuilderEffect: (ConstraintSystemOperation.() -> Unit)? = null
|
var outerConstraintBuilderEffect: (ConstraintSystemOperation.() -> Unit)? = null
|
||||||
var usesSAM: Boolean = false
|
var usesSAM: Boolean = false
|
||||||
|
var usesSuspendConversion: Boolean = false
|
||||||
|
|
||||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||||
lateinit var typeArgumentMapping: TypeArgumentMapping
|
lateinit var typeArgumentMapping: TypeArgumentMapping
|
||||||
|
|||||||
+25
-4
@@ -42,7 +42,7 @@ class ConeOverloadConflictResolver(
|
|||||||
candidates
|
candidates
|
||||||
|
|
||||||
return chooseMaximallySpecificCandidates(
|
return chooseMaximallySpecificCandidates(
|
||||||
fixedCandidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true
|
fixedCandidates, discriminateGenerics, discriminateAbstracts, discriminateSAMs = true, discriminateSuspendConversions = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,8 @@ class ConeOverloadConflictResolver(
|
|||||||
candidates: Set<Candidate>,
|
candidates: Set<Candidate>,
|
||||||
discriminateGenerics: Boolean,
|
discriminateGenerics: Boolean,
|
||||||
discriminateAbstracts: Boolean,
|
discriminateAbstracts: Boolean,
|
||||||
discriminateSAMs: Boolean
|
discriminateSAMs: Boolean,
|
||||||
|
discriminateSuspendConversions: Boolean,
|
||||||
): Set<Candidate> {
|
): Set<Candidate> {
|
||||||
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
|
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
|
||||||
|
|
||||||
@@ -78,7 +79,23 @@ class ConeOverloadConflictResolver(
|
|||||||
0, candidates.size -> {
|
0, candidates.size -> {
|
||||||
}
|
}
|
||||||
else -> return chooseMaximallySpecificCandidates(
|
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 -> {
|
0, candidates.size -> {
|
||||||
}
|
}
|
||||||
else -> return chooseMaximallySpecificCandidates(
|
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)
|
is FirVariable<*> -> createKPropertyType(fir, resultingReceiverType, returnTypeRef)
|
||||||
else -> ConeKotlinErrorType(ConeSimpleDiagnostic("Unknown callable kind: ${fir::class}", DiagnosticKind.UnknownCallableKind))
|
else -> ConeKotlinErrorType(ConeSimpleDiagnostic("Unknown callable kind: ${fir::class}", DiagnosticKind.UnknownCallableKind))
|
||||||
}.let(candidate.substitutor::substituteOrSelf)
|
}.let(candidate.substitutor::substituteOrSelf)
|
||||||
|
candidate.usesSuspendConversion = requireSuspendConversion
|
||||||
candidate.resultingTypeForCallableReference = resultingType
|
candidate.resultingTypeForCallableReference = resultingType
|
||||||
candidate.outerConstraintBuilderEffect = fun ConstraintSystemOperation.() {
|
candidate.outerConstraintBuilderEffect = fun ConstraintSystemOperation.() {
|
||||||
addOtherSystem(candidate.system.asReadOnlyStorage())
|
addOtherSystem(candidate.system.asReadOnlyStorage())
|
||||||
|
|||||||
Vendored
+1
-1
@@ -14,6 +14,6 @@ fun test1() {
|
|||||||
|
|
||||||
// candidate without suspend conversions is more specific
|
// candidate without suspend conversions is more specific
|
||||||
fun test2(f: () -> Int, g: suspend () -> Int) {
|
fun test2(f: () -> Int, g: suspend () -> Int) {
|
||||||
<!AMBIGUITY!>foo<!>(f)
|
foo(f)
|
||||||
foo(g)
|
foo(g)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -15,5 +15,5 @@ fun test4(): suspend () -> Unit = useSuspendFn {}
|
|||||||
fun test5() = useSuspendFn {}
|
fun test5() = useSuspendFn {}
|
||||||
|
|
||||||
fun test5(sfn: suspend () -> Unit) = ambiguous(sfn)
|
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<!> {}
|
fun test7(): () -> Unit = <!AMBIGUITY!>ambiguous<!> {}
|
||||||
Reference in New Issue
Block a user