From eb7e9196b550f3b7a0b0b4e9331e7ca04f59692d Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 21 Apr 2017 15:36:18 +0300 Subject: [PATCH] [NI] Fix some argument mapping problems 1. Value arguments for the resolved call are indexed with resulting descriptor value parameters (which can be substituted). 2. Simple argument can be a single vararg element if the corresponding value parameter is a vararg parameter. 3. Resulting descriptor should be approximated to super-type. This doesn't affect type inference, but the JVM BE expects types with proper classifiers. --- .../tower/KotlinToResolvedCallTransformer.kt | 37 +++++++++++-------- .../calls/components/KotlinCallCompleter.kt | 22 +++++++---- .../resolve/calls/inference/InferenceUtils.kt | 13 +++++++ 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt index 903ce49bffe..d1b9ed0b0eb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinToResolvedCallTransformer.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedT import org.jetbrains.kotlin.resolve.calls.callUtil.isFakeElement import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext +import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.model.* @@ -244,7 +245,7 @@ sealed class NewAbstractResolvedCall(): ResolvedCall abstract val kotlinCall: KotlinCall private var argumentToParameterMap: Map? = null - private val _valueArguments: Map by lazy(this::createValueArguments) + private val _valueArguments: Map by lazy { createValueArguments() } override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall @@ -298,7 +299,7 @@ sealed class NewAbstractResolvedCall(): ResolvedCall resultingDescriptor: CallableDescriptor, valueArguments: Map ): Map = - HashMap().also { result -> + LinkedHashMap().also { result -> for (parameter in resultingDescriptor.valueParameters) { val resolvedArgument = valueArguments[parameter] ?: continue for (arguments in resolvedArgument.arguments) { @@ -307,22 +308,28 @@ sealed class NewAbstractResolvedCall(): ResolvedCall } } - private fun createValueArguments(): Map { - val result = HashMap() - for (parameter in candidateDescriptor.valueParameters) { - val resolvedCallArgument = argumentMappingByOriginal[parameter.original] ?: continue - val valueArgument = when (resolvedCallArgument) { - ResolvedCallArgument.DefaultArgument -> DefaultValueArgument.DEFAULT - is ResolvedCallArgument.SimpleArgument -> ExpressionValueArgument(resolvedCallArgument.callArgument.psiCallArgument.valueArgument) - is ResolvedCallArgument.VarargArgument -> VarargValueArgument().apply { - resolvedCallArgument.arguments.map { it.psiCallArgument.valueArgument }.forEach(this::addArgument) + private fun createValueArguments(): Map = + LinkedHashMap().also { result -> + for ((originalParameter, resolvedCallArgument) in argumentMappingByOriginal) { + val resultingParameter = resultingDescriptor.valueParameters[originalParameter.index] + result[resultingParameter] = when (resolvedCallArgument) { + ResolvedCallArgument.DefaultArgument -> + DefaultValueArgument.DEFAULT + is ResolvedCallArgument.SimpleArgument -> { + val valueArgument = resolvedCallArgument.callArgument.psiCallArgument.valueArgument + if (resultingParameter.isVararg) + VarargValueArgument().apply { addArgument(valueArgument) } + else + ExpressionValueArgument(valueArgument) + } + is ResolvedCallArgument.VarargArgument -> + VarargValueArgument().apply { + resolvedCallArgument.arguments.map { it.psiCallArgument.valueArgument }.forEach { addArgument(it) } + } + } } } - result[parameter] = valueArgument - } - return result - } } class NewResolvedCallImpl( diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index a422233c9ad..2b5dbfb67c5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.resolve.calls.components import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector @@ -28,7 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing -import org.jetbrains.kotlin.resolve.calls.inference.substitute +import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus @@ -71,11 +73,9 @@ class KotlinCallCompleter( ): ResolvedKotlinCall { lambdaAnalyzer.bindStubResolvedCallForCandidate(candidate) val topLevelCall = - if (candidate is VariableAsFunctionKotlinResolutionCandidate) { - candidate.invokeCandidate - } - else { - candidate as SimpleKotlinResolutionCandidate + when (candidate) { + is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate + else -> candidate as SimpleKotlinResolutionCandidate } if (topLevelCall.prepareForCompletion(expectedType)) { @@ -111,7 +111,15 @@ class KotlinCallCompleter( } private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): CompletedKotlinCall.Simple { - val resultingDescriptor = if (descriptorWithFreshTypes.typeParameters.isNotEmpty()) descriptorWithFreshTypes.substitute(substitutor)!! else descriptorWithFreshTypes + val resultingDescriptor = when { + descriptorWithFreshTypes is FunctionDescriptor || + descriptorWithFreshTypes is PropertyDescriptor && descriptorWithFreshTypes.typeParameters.isNotEmpty() -> + // this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types, + // but it seems like temporary solution. + descriptorWithFreshTypes.substituteAndApproximateCapturedTypes(substitutor)!! + else -> + descriptorWithFreshTypes + } val typeArguments = descriptorWithFreshTypes.typeParameters.map { substitutor.safeSubstitute(it.defaultType) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt index 50af0bbfe02..911450ddf8d 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceUtils.kt @@ -44,3 +44,16 @@ fun CallableDescriptor.substitute(substitutor: NewTypeSubstitutor): CallableDesc return substitute(TypeSubstitutor.create(wrappedSubstitution)) } +fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTypeSubstitutor): CallableDescriptor? { + val wrappedSubstitution = object : TypeSubstitution() { + override fun get(key: KotlinType): TypeProjection? = null + + override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = + substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType -> + TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: + substitutedType + } + } + + return substitute(TypeSubstitutor.create(wrappedSubstitution)) +}