[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.
This commit is contained in:
Dmitry Petrov
2017-04-21 15:36:18 +03:00
committed by Stanislav Erokhin
parent 0c79949cf1
commit eb7e9196b5
3 changed files with 50 additions and 22 deletions
@@ -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.callUtil.isFakeElement
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext 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.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.context.CallPosition
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
@@ -244,7 +245,7 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
abstract val kotlinCall: KotlinCall abstract val kotlinCall: KotlinCall
private var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null private var argumentToParameterMap: Map<ValueArgument, ArgumentMatchImpl>? = null
private val _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument> by lazy(this::createValueArguments) private val _valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument> by lazy { createValueArguments() }
override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall override fun getCall(): Call = kotlinCall.psiKotlinCall.psiCall
@@ -298,7 +299,7 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
resultingDescriptor: CallableDescriptor, resultingDescriptor: CallableDescriptor,
valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments: Map<ValueParameterDescriptor, ResolvedValueArgument>
): Map<ValueArgument, ArgumentMatchImpl> = ): Map<ValueArgument, ArgumentMatchImpl> =
HashMap<ValueArgument, ArgumentMatchImpl>().also { result -> LinkedHashMap<ValueArgument, ArgumentMatchImpl>().also { result ->
for (parameter in resultingDescriptor.valueParameters) { for (parameter in resultingDescriptor.valueParameters) {
val resolvedArgument = valueArguments[parameter] ?: continue val resolvedArgument = valueArguments[parameter] ?: continue
for (arguments in resolvedArgument.arguments) { for (arguments in resolvedArgument.arguments) {
@@ -307,22 +308,28 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
} }
} }
private fun createValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> { private fun createValueArguments(): Map<ValueParameterDescriptor, ResolvedValueArgument> =
val result = HashMap<ValueParameterDescriptor, ResolvedValueArgument>() LinkedHashMap<ValueParameterDescriptor, ResolvedValueArgument>().also { result ->
for (parameter in candidateDescriptor.valueParameters) { for ((originalParameter, resolvedCallArgument) in argumentMappingByOriginal) {
val resolvedCallArgument = argumentMappingByOriginal[parameter.original] ?: continue val resultingParameter = resultingDescriptor.valueParameters[originalParameter.index]
val valueArgument = when (resolvedCallArgument) { result[resultingParameter] = when (resolvedCallArgument) {
ResolvedCallArgument.DefaultArgument -> DefaultValueArgument.DEFAULT ResolvedCallArgument.DefaultArgument ->
is ResolvedCallArgument.SimpleArgument -> ExpressionValueArgument(resolvedCallArgument.callArgument.psiCallArgument.valueArgument) DefaultValueArgument.DEFAULT
is ResolvedCallArgument.VarargArgument -> VarargValueArgument().apply { is ResolvedCallArgument.SimpleArgument -> {
resolvedCallArgument.arguments.map { it.psiCallArgument.valueArgument }.forEach(this::addArgument) 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<D : CallableDescriptor>( class NewResolvedCallImpl<D : CallableDescriptor>(
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.CallableDescriptor 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.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector 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.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing 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.model.*
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
@@ -71,11 +73,9 @@ class KotlinCallCompleter(
): ResolvedKotlinCall { ): ResolvedKotlinCall {
lambdaAnalyzer.bindStubResolvedCallForCandidate(candidate) lambdaAnalyzer.bindStubResolvedCallForCandidate(candidate)
val topLevelCall = val topLevelCall =
if (candidate is VariableAsFunctionKotlinResolutionCandidate) { when (candidate) {
candidate.invokeCandidate is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate
} else -> candidate as SimpleKotlinResolutionCandidate
else {
candidate as SimpleKotlinResolutionCandidate
} }
if (topLevelCall.prepareForCompletion(expectedType)) { if (topLevelCall.prepareForCompletion(expectedType)) {
@@ -111,7 +111,15 @@ class KotlinCallCompleter(
} }
private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor): CompletedKotlinCall.Simple { 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) } val typeArguments = descriptorWithFreshTypes.typeParameters.map { substitutor.safeSubstitute(it.defaultType) }
@@ -44,3 +44,16 @@ fun CallableDescriptor.substitute(substitutor: NewTypeSubstitutor): CallableDesc
return substitute(TypeSubstitutor.create(wrappedSubstitution)) 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))
}