[NI] Update lambda result types.

When completing calls, update return types for functional descriptors
for lambdas using type inference results.

Add toString to some Call subclasses (for debugging purposes).
This commit is contained in:
Dmitry Petrov
2017-04-25 11:57:55 +03:00
committed by Stanislav Erokhin
parent 2bf252afe6
commit 1d6ed4ef8e
9 changed files with 46 additions and 17 deletions
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
import java.util.*
import kotlin.collections.HashMap
@@ -21,20 +21,20 @@ import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.components.LambdaAnalyzer
import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
@@ -94,4 +94,16 @@ class LambdaAnalyzerImpl(
override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) {
kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace)
}
override fun completeLambdaReturnType(lambdaArgument: ResolvedLambdaArgument, returnType: KotlinType) {
val psiCallArgument = lambdaArgument.argument.psiCallArgument
val ktFunction = when (psiCallArgument) {
is LambdaKotlinCallArgumentImpl -> psiCallArgument.ktLambdaExpression.functionLiteral
is FunctionExpressionImpl -> psiCallArgument.ktFunction
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
}
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
throw AssertionError("No function descriptor for resolved lambda argument")
functionDescriptor.setReturnType(returnType)
}
}
@@ -130,7 +130,9 @@ class PSICallResolver(
val expectedType = context.expectedType.unwrap()
return if (context.contextDependency == ContextDependency.DEPENDENT) {
assert(expectedType == TypeUtils.NO_EXPECTED_TYPE)
assert(TypeUtils.noExpectedType(expectedType)) {
"Should have no expected type, got: $expectedType"
}
null
}
else {
@@ -366,6 +366,11 @@ public class CallMaker {
public CallType getCallType() {
return CallType.DEFAULT;
}
@Override
public String toString() {
return DebugTextUtilKt.getDebugText(callElement);
}
};
}
@@ -100,4 +100,9 @@ public class DelegatingCall implements Call {
public CallType getCallType() {
return delegate.getCallType();
}
@Override
public String toString() {
return "*" + delegate.toString();
}
}
@@ -220,8 +220,10 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
// This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions
context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType)
val typeOfBodyExpression = // Type-check the body
components.expressionTypingServices.getBlockReturnedType(functionLiteral.bodyExpression!!, COERCION_TO_UNIT, newContext).type
// Type-check the body
val blockReturnedType = components.expressionTypingServices.getBlockReturnedType(functionLiteral.bodyExpression!!, COERCION_TO_UNIT, newContext)
val typeOfBodyExpression = blockReturnedType.type
return computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression)
}
@@ -102,7 +102,7 @@ class KotlinCallResolver(
}
return maximallySpecificCandidates.map {
kotlinCallCompleter.transformWhenAmbiguity(it)
kotlinCallCompleter.transformWhenAmbiguity(it, callContext.lambdaAnalyzer)
}
}
}
@@ -17,10 +17,8 @@
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
interface IsDescriptorFromSourcePredicate: (CallableDescriptor) -> Boolean
@@ -39,4 +37,6 @@ interface LambdaAnalyzer {
// todo this is hack for some client which try to read ResolvedCall from trace before all calls completed
fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate)
fun completeLambdaReturnType(lambdaArgument: ResolvedLambdaArgument, returnType: KotlinType)
}
@@ -63,8 +63,8 @@ class KotlinCallCompleter(
fun getBuilder(): ConstraintSystemBuilder
}
fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate): ResolvedKotlinCall =
toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate)
fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate, lambdaAnalyzer: LambdaAnalyzer): ResolvedKotlinCall =
toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate, lambdaAnalyzer)
fun completeCallIfNecessary(
candidate: KotlinResolutionCandidate,
@@ -82,7 +82,7 @@ class KotlinCallCompleter(
val c = candidate.lastCall.constraintSystem.asCallCompleterContext()
topLevelCall.competeCall(c, lambdaAnalyzer)
return toCompletedBaseResolvedCall(c, candidate)
return toCompletedBaseResolvedCall(c, candidate, lambdaAnalyzer)
}
return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate)
@@ -90,13 +90,17 @@ class KotlinCallCompleter(
private fun toCompletedBaseResolvedCall(
c: Context,
candidate: KotlinResolutionCandidate
candidate: KotlinResolutionCandidate,
lambdaAnalyzer: LambdaAnalyzer
): ResolvedKotlinCall.CompletedResolvedKotlinCall {
val currentSubstitutor = c.buildResultingSubstitutor()
val completedCall = candidate.toCompletedCall(currentSubstitutor)
val competedCalls = c.innerCalls.map {
it.candidate.toCompletedCall(currentSubstitutor)
}
c.lambdaArguments.forEach {
lambdaAnalyzer.completeLambdaReturnType(it, currentSubstitutor.safeSubstitute(it.returnType))
}
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls)
}