[NI] Remove lambda coersion to Unit in case of error return type(s)

Coersion to Unit from error type leads to misleading type mismatches:
"expected <expected lambda return type> found Unit", despite no user-provided Unit / empty lambda.
These diagnostics were collected, but not reported before, and that had been disguising the issue for a while.

KT-34729 Fixed
This commit is contained in:
Pavel Kirpichenkov
2020-01-20 19:25:35 +03:00
parent 3a98c84105
commit c5893913f3
39 changed files with 263 additions and 46 deletions
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getBinaryWithTypeParent
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.components.*
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.CoroutineInferenceSession
@@ -95,7 +92,7 @@ class KotlinResolutionCallbacksImpl(
expectedReturnType: UnwrappedType?,
annotations: Annotations,
stubsForPostponedVariables: Map<NewTypeVariable, StubType>
): Pair<List<KotlinCallArgument>, InferenceSession?> {
): ReturnArgumentsAnalysisResult {
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
val outerCallContext = psiCallArgument.outerCallContext
@@ -191,7 +188,9 @@ class KotlinResolutionCallbacksImpl(
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
var hasReturnWithoutExpression = false
var returnArgumentFound = false
val returnArguments = lambdaInfo.returnStatements.mapNotNullTo(ArrayList()) { (expression, contextInfo) ->
returnArgumentFound = true
val returnedExpression = expression.returnedExpression
if (returnedExpression != null) {
createCallArgument(
@@ -210,6 +209,7 @@ class KotlinResolutionCallbacksImpl(
if (expectedReturnType?.isUnit() == true || hasReturnWithoutExpression) return@let null // coercion to Unit
// todo lastExpression can be if without else
returnArgumentFound = true
val lastExpressionType = trace.getType(lastExpression)
val contextInfo = lambdaInfo.lastExpressionInfo
val lastExpressionTypeInfo = KotlinTypeInfo(lastExpressionType, contextInfo.dataFlowInfoAfter ?: functionTypeInfo.dataFlowInfo)
@@ -218,7 +218,7 @@ class KotlinResolutionCallbacksImpl(
returnArguments.addIfNotNull(lastExpressionArgument)
return Pair(returnArguments, coroutineSession)
return ReturnArgumentsAnalysisResult(ReturnArgumentsInfo(returnArguments, returnArgumentFound), coroutineSession)
}
private fun getLastDeparentesizedExpression(psiCallArgument: PSIKotlinCallArgument): KtExpression? {
@@ -153,7 +153,7 @@ class ResolvedAtomCompleter(
private val ResolvedLambdaAtom.isCoercedToUnit: Boolean
get() {
val returnTypes =
resultArguments.map {
resultArgumentsInfo.nonErrorArguments.map {
val type = it.safeAs<SimpleKotlinCallArgument>()?.receiver?.receiverValue?.type ?: return@map null
val unwrappedType = when (type) {
is WrappedType -> type.unwrap()
@@ -161,7 +161,7 @@ class ResolvedAtomCompleter(
}
resultSubstitutor.safeSubstitute(unwrappedType)
}
if (returnTypes.isEmpty()) return true
if (returnTypes.isEmpty() && !resultArgumentsInfo.returnArgumentsExist) return true
val substitutedTypes = returnTypes.filterNotNull()
// we have some unsubstituted types
if (substitutedTypes.isEmpty()) return false
@@ -184,7 +184,7 @@ class ResolvedAtomCompleter(
)
updateTraceForLambda(lambda, topLevelTrace, approximatedReturnType)
for (lambdaResult in lambda.resultArguments) {
for (lambdaResult in lambda.resultArgumentsInfo.nonErrorArguments) {
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
val newContext =
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)