FIR: no constraint for coerced-to-Unit last expression of lambda
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
4ab0897d7d
commit
6239301f4e
+2
-2
@@ -59,7 +59,7 @@ FILE: RedundantReturnUnitTypeChecker.kt
|
||||
}
|
||||
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
^foo this@R|/B|.R|/B.run|<R|kotlin/Int|>(<L> = run@fun <anonymous>(): R|kotlin/Int| {
|
||||
^foo this@R|/B|.R|/B.run|<R|kotlin/Unit|>(<L> = run@fun <anonymous>(): R|kotlin/Unit| {
|
||||
this@R|/B|.R|/B.bar|()
|
||||
}
|
||||
)
|
||||
@@ -88,7 +88,7 @@ FILE: RedundantReturnUnitTypeChecker.kt
|
||||
}
|
||||
|
||||
public final fun goo(): R|kotlin/Unit| {
|
||||
^goo (this@R|/B|, Int(1)).R|/B.let|<R|kotlin/Int|, R|kotlin/Int|>(<L> = let@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Int| {
|
||||
^goo (this@R|/B|, Int(1)).R|/B.let|<R|kotlin/Int|, R|kotlin/Unit|>(<L> = let@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
this@R|/B|.R|/B.bar|()
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ digraph complexPostponedCfg_kt {
|
||||
}
|
||||
34 [label="Call arguments union" style="filled" fillcolor=yellow];
|
||||
35 [label="Postponed exit from lambda"];
|
||||
36 [label="Function call: R|kotlin/with|<R|FirFunctionCall|, R|kotlin/Boolean|>(...)"];
|
||||
36 [label="Function call: R|kotlin/with|<R|FirFunctionCall|, R|kotlin/Unit|>(...)"];
|
||||
37 [label="Exit block"];
|
||||
}
|
||||
38 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ FILE: complexPostponedCfg.kt
|
||||
lval firstCalls: R|kotlin/collections/List<FirFunctionCall>| = R|kotlin/with|<R|FirFunctionCall|, R|kotlin/collections/List<FirFunctionCall>|>((R|<local>/statements|.R|kotlin/collections/last|<R|FirBase|>() as R|FirFunctionCall|), <L> = setCall@fun R|FirFunctionCall|.<anonymous>(): R|kotlin/collections/List<FirFunctionCall>| <kind=EXACTLY_ONCE> {
|
||||
^ R|kotlin/collections/buildList|<R|FirFunctionCall|>(<L> = buildList@fun R|kotlin/collections/MutableList<FirFunctionCall>|.<anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(this@R|special/anonymous|)
|
||||
R|kotlin/with|<R|FirFunctionCall|, R|kotlin/Boolean|>((R|<local>/arguments|.R|kotlin/collections/last|<R|FirBase|>() as R|FirFunctionCall|), <L> = plusCall@fun R|FirFunctionCall|.<anonymous>(): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
|
||||
R|kotlin/with|<R|FirFunctionCall|, R|kotlin/Unit|>((R|<local>/arguments|.R|kotlin/collections/last|<R|FirBase|>() as R|FirFunctionCall|), <L> = plusCall@fun R|FirFunctionCall|.<anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(this@R|special/anonymous|)
|
||||
this@R|special/anonymous|.R|SubstitutionOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|((R|<local>/explicitReceiver| as R|FirFunctionCall|))
|
||||
}
|
||||
|
||||
+21
-11
@@ -130,7 +130,7 @@ class PostponedArgumentsAnalyzer(
|
||||
rawReturnType,
|
||||
stubsForPostponedVariables
|
||||
)
|
||||
applyResultsOfAnalyzedLambdaToCandidateSystem(c, lambda, candidate, results, ::substitute)
|
||||
applyResultsOfAnalyzedLambdaToCandidateSystem(c, lambda, candidate, results, expectedTypeForReturnArguments, ::substitute)
|
||||
return results
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ class PostponedArgumentsAnalyzer(
|
||||
lambda: ResolvedLambdaAtom,
|
||||
candidate: Candidate,
|
||||
results: ReturnArgumentsAnalysisResult,
|
||||
expectedReturnType: ConeKotlinType? = null,
|
||||
substitute: (ConeKotlinType) -> ConeKotlinType = c.createSubstituteFunctorForLambdaAnalysis()
|
||||
) {
|
||||
val (returnArguments, inferenceSession) = results
|
||||
@@ -164,21 +165,30 @@ class PostponedArgumentsAnalyzer(
|
||||
|
||||
val checkerSink: CheckerSink = CheckerSinkImpl(candidate)
|
||||
|
||||
val lastExpression = lambda.atom.body?.statements?.lastOrNull() as? FirExpression
|
||||
var hasExpressionInReturnArguments = false
|
||||
// No constraint for return expressions of lambda if it has Unit return type.
|
||||
val lambdaReturnType = lambda.returnType.let(substitute).takeUnless { it.isUnit }
|
||||
returnArguments.forEach {
|
||||
if (it !is FirExpression) return@forEach
|
||||
hasExpressionInReturnArguments = true
|
||||
candidate.resolveArgumentExpression(
|
||||
c.getBuilder(),
|
||||
it,
|
||||
lambdaReturnType,
|
||||
lambda.atom.returnTypeRef, // TODO: proper ref
|
||||
checkerSink,
|
||||
context = resolutionContext,
|
||||
isReceiver = false,
|
||||
isDispatch = false
|
||||
)
|
||||
// If it is the last expression, and the expected type is Unit, that expression will be coerced to Unit.
|
||||
// If the last expression is of Unit type, of course it's not coercion-to-Unit case.
|
||||
val lastExpressionCoercedToUnit =
|
||||
it == lastExpression && expectedReturnType?.isUnit == true && !it.typeRef.coneType.isUnit
|
||||
// No constraint for the last expression of lambda if it will be coerced to Unit.
|
||||
if (!lastExpressionCoercedToUnit) {
|
||||
candidate.resolveArgumentExpression(
|
||||
c.getBuilder(),
|
||||
it,
|
||||
lambdaReturnType,
|
||||
lambda.atom.returnTypeRef, // TODO: proper ref
|
||||
checkerSink,
|
||||
context = resolutionContext,
|
||||
isReceiver = false,
|
||||
isDispatch = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasExpressionInReturnArguments && lambdaReturnType != null) {
|
||||
|
||||
Reference in New Issue
Block a user