[NI] Postprocess lambda result expressions on call completion
Should update type to denotable, e.g., IntegerValueType(x) to proper numeric type. TODO extract common code into some ValueArgumentPostprocessor
This commit is contained in:
committed by
Stanislav Erokhin
parent
1d6ed4ef8e
commit
2bdeef7970
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.name.SpecialNames;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.StatementFilter;
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.TypeResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode;
|
||||
@@ -398,12 +399,22 @@ public class ArgumentTypeResolver {
|
||||
@NotNull ResolutionContext context,
|
||||
@NotNull KtExpression expression
|
||||
) {
|
||||
KotlinType type = context.trace.getType(expression);
|
||||
return updateResultArgumentTypeIfNotDenotable(context.trace, context.statementFilter, context.expectedType, expression);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KotlinType updateResultArgumentTypeIfNotDenotable(
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull StatementFilter statementFilter,
|
||||
@NotNull KotlinType expectedType,
|
||||
@NotNull KtExpression expression
|
||||
) {
|
||||
KotlinType type = trace.getType(expression);
|
||||
if (type != null && !type.getConstructor().isDenotable()) {
|
||||
if (type.getConstructor() instanceof IntegerValueTypeConstructor) {
|
||||
IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor();
|
||||
KotlinType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, context.expectedType);
|
||||
constantExpressionEvaluator.updateNumberType(primitiveType, expression, context.statementFilter, context.trace);
|
||||
KotlinType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, expectedType);
|
||||
constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace);
|
||||
return primitiveType;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-7
@@ -27,16 +27,13 @@ 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.ArgumentTypeResolver
|
||||
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.*
|
||||
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.*
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
|
||||
@@ -44,10 +41,11 @@ class LambdaAnalyzerImpl(
|
||||
val expressionTypingServices: ExpressionTypingServices,
|
||||
val trace: BindingTrace,
|
||||
val typeApproximator: TypeApproximator,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
val argumentTypeResolver: ArgumentTypeResolver
|
||||
): LambdaAnalyzer {
|
||||
|
||||
override fun analyzeAndGetRelatedCalls(
|
||||
override fun analyzeAndGetLambdaResultArguments(
|
||||
topLevelCall: KotlinCall,
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
receiverType: UnwrappedType?,
|
||||
@@ -102,8 +100,21 @@ class LambdaAnalyzerImpl(
|
||||
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)
|
||||
|
||||
for (lambdaResult in lambdaArgument.resultArguments) {
|
||||
val resultValueArgument = lambdaResult.psiCallArgument.valueArgument
|
||||
val deparenthesized = resultValueArgument.getArgumentExpression()?.let {
|
||||
KtPsiUtil.getLastElementDeparenthesized(it, expressionTypingServices.statementFilter)
|
||||
} ?: continue
|
||||
|
||||
val recordedType = trace.getType(deparenthesized)
|
||||
if (recordedType != null && !recordedType.constructor.isDenotable) {
|
||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter, returnType, deparenthesized)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,8 @@ class PSICallResolver(
|
||||
val constraintInjector: ConstraintInjector,
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val kotlinCallResolver: KotlinCallResolver,
|
||||
private val typeApproximator: TypeApproximator
|
||||
private val typeApproximator: TypeApproximator,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver
|
||||
) {
|
||||
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
|
||||
|
||||
@@ -89,7 +90,7 @@ class PSICallResolver(
|
||||
) : OverloadResolutionResults<D> {
|
||||
val kotlinCall = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, name, tracingStrategy)
|
||||
val scopeTower = ASTScopeTower(context)
|
||||
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator, kotlinToResolvedCallTransformer)
|
||||
val lambdaAnalyzer = createLambdaAnalyzer(context)
|
||||
|
||||
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
|
||||
val factoryProviderForInvoke = FactoryProviderForInvoke(context, callContext, kotlinCall)
|
||||
@@ -112,7 +113,7 @@ class PSICallResolver(
|
||||
|
||||
val kotlinCall = toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
|
||||
val scopeTower = ASTScopeTower(context)
|
||||
val lambdaAnalyzer = LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator, kotlinToResolvedCallTransformer)
|
||||
val lambdaAnalyzer = createLambdaAnalyzer(context)
|
||||
val callContext = createCallContext(scopeTower, lambdaAnalyzer)
|
||||
|
||||
val givenCandidates = resolutionCandidates.map {
|
||||
@@ -126,6 +127,9 @@ class PSICallResolver(
|
||||
|
||||
}
|
||||
|
||||
private fun createLambdaAnalyzer(context: BasicCallResolutionContext) =
|
||||
LambdaAnalyzerImpl(expressionTypingServices, context.trace, typeApproximator, kotlinToResolvedCallTransformer, argumentTypeResolver)
|
||||
|
||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||
val expectedType = context.expectedType.unwrap()
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ interface IsDescriptorFromSourcePredicate: (CallableDescriptor) -> Boolean
|
||||
interface CommonSupertypeCalculator: (Collection<UnwrappedType>) -> UnwrappedType
|
||||
|
||||
interface LambdaAnalyzer {
|
||||
fun analyzeAndGetRelatedCalls(
|
||||
fun analyzeAndGetLambdaResultArguments(
|
||||
topLevelCall: KotlinCall,
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
receiverType: UnwrappedType?,
|
||||
|
||||
+2
-2
@@ -245,10 +245,10 @@ class KotlinCallCompleter(
|
||||
val receiver = lambda.receiver?.let(::substitute)
|
||||
val parameters = lambda.parameters.map(::substitute)
|
||||
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
|
||||
val callsFromLambda = lambdaAnalyzer.analyzeAndGetRelatedCalls(topLevelCall, lambda.argument, receiver, parameters, expectedType)
|
||||
lambda.analyzed = true
|
||||
lambda.resultArguments = lambdaAnalyzer.analyzeAndGetLambdaResultArguments(topLevelCall, lambda.argument, receiver, parameters, expectedType)
|
||||
|
||||
for (innerCall in callsFromLambda) {
|
||||
for (innerCall in lambda.resultArguments) {
|
||||
// todo strange code -- why top-level kotlinCall? may be it isn't right outer call
|
||||
CheckArguments.checkArgument(topLevelCallContext, topLevelCall, c.getBuilder(), innerCall, lambda.returnType)
|
||||
}
|
||||
|
||||
+2
@@ -51,6 +51,8 @@ class ResolvedLambdaArgument(
|
||||
|
||||
override val inputType: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
|
||||
override val outputType: UnwrappedType get() = returnType
|
||||
|
||||
lateinit var resultArguments: List<KotlinCallArgument>
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user