[NI] Support callable reference resolution in NI.

Missing parts:
- report results about callable references into trace
This commit is contained in:
Stanislav Erokhin
2017-05-08 16:02:09 +03:00
committed by Mikhail Zarechenskiy
parent 02f4558683
commit 55dc2c11f7
19 changed files with 570 additions and 211 deletions
@@ -16,13 +16,13 @@
package org.jetbrains.kotlin.resolve.calls.tower
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
@@ -110,8 +110,8 @@ class CallableReferenceKotlinCallArgumentImpl(
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
val ktCallableReferenceExpression: KtCallableReferenceExpression,
override val argumentName: Name?,
override val lhsType: UnwrappedType?,
override val constraintStorage: ConstraintStorage
override val lhsResult: LHSResult,
override val rhsName: Name
) : CallableReferenceKotlinCallArgument, PSIKotlinCallArgument()
class SubKotlinCallArgumentImpl(
@@ -137,6 +137,16 @@ class ExpressionKotlinCallArgumentImpl(
override val isSafeCall: Boolean get() = false
}
class FakeValueArgumentForLeftCallableReference(val ktExpression: KtCallableReferenceExpression): ValueArgument {
override fun getArgumentExpression() = ktExpression.receiverExpression
override fun getArgumentName(): ValueArgumentName? = null
override fun isNamed(): Boolean = false
override fun asElement(): KtElement = getArgumentExpression() ?: ktExpression
override fun getSpreadElement(): LeafPsiElement? = null
override fun isExternal(): Boolean = false
}
internal fun createSimplePSICallArgument(
context: BasicCallResolutionContext,
valueArgument: ValueArgument,
@@ -16,8 +16,10 @@
package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
@@ -28,9 +30,10 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.ModifierCheckerCore
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.TypeResolver
import org.jetbrains.kotlin.resolve.calls.*
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver
@@ -40,7 +43,6 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
@@ -75,6 +77,7 @@ class PSICallResolver(
val resultTypeResolver: ResultTypeResolver,
val callableReferenceResolver: CallableReferenceResolver,
val constraintInjector: ConstraintInjector,
val reflectionTypes: ReflectionTypes,
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
private val kotlinCallResolver: KotlinCallResolver,
private val typeApproximator: TypeApproximator,
@@ -146,7 +149,7 @@ class PSICallResolver(
private fun createCallContext(scopeTower: ASTScopeTower, resolutionCallbacks: KotlinResolutionCallbacks) =
KotlinCallContext(scopeTower, resolutionCallbacks, argumentsToParametersMapper, typeArgumentsToParametersMapper, resultTypeResolver,
callableReferenceResolver, constraintInjector)
callableReferenceResolver, constraintInjector, reflectionTypes)
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
context: BasicCallResolutionContext,
@@ -456,17 +459,44 @@ class PSICallResolver(
if (ktExpression is KtCallableReferenceExpression) {
checkNoSpread(outerCallContext, valueArgument)
// todo analyze left expression and get constraint system
val (lhsResult, rightResults) = doubleColonExpressionResolver.resolveCallableReference(
ktExpression, ExpressionTypingContext.newContext(context), ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS)
val expressionTypingContext = ExpressionTypingContext.newContext(context)
val lhsResult = if (ktExpression.isEmptyLHS) null else doubleColonExpressionResolver.resolveDoubleColonLHS(ktExpression, expressionTypingContext)
val newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo
val name = ktExpression.callableReference.getReferencedNameAsName()
// todo ChosenCallableReferenceDescriptor
val lhsNewResult = when (lhsResult) {
null -> LHSResult.Empty
is DoubleColonLHS.Expression -> {
if (lhsResult.isObjectQualifier) {
val classifier = lhsResult.type.constructor.declarationDescriptor
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
}
else {
LHSResult.Empty // this is error case actually
}
}
else {
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
kotlinCallArgument?.let { LHSResult.Expression(it as SimpleKotlinCallArgument) } ?: LHSResult.Empty
}
}
is DoubleColonLHS.Type -> {
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, ktExpression.receiverExpression!!)
if (qualifier is ClassQualifier) {
LHSResult.Type(qualifier)
}
else {
LHSResult.Empty // this is error case actually
}
}
}
return CallableReferenceKotlinCallArgumentImpl(valueArgument, startDataFlowInfo, newDataFlowInfo,
ktExpression, argumentName, (lhsResult as? DoubleColonLHS.Type)?.type?.unwrap(),
ConstraintStorage.Empty)
ktExpression, argumentName, lhsNewResult, name)
}
// valueArgument.getArgumentExpression()!! instead of ktExpression is hack -- type info should be stored also for parenthesized expression
@@ -75,7 +75,7 @@ sealed class DoubleColonLHS(val type: KotlinType) {
* (Obj)::class // not an object qualifier (can only be treated as an expression, not as a type)
* { Obj }()::class // not an object qualifier
*/
class Expression(typeInfo: KotlinTypeInfo, val isObjectQualifier: Boolean) : DoubleColonLHS(typeInfo.type!!) {
class Expression(val typeInfo: KotlinTypeInfo, val isObjectQualifier: Boolean) : DoubleColonLHS(typeInfo.type!!) {
val dataFlowInfo: DataFlowInfo = typeInfo.dataFlowInfo
}
@@ -0,0 +1,305 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.DISPATCH_RECEIVER
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.EXTENSION_RECEIVER
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.upperIfFlexible
import org.jetbrains.kotlin.utils.SmartList
sealed class CallableReceiver {
class UnboundReference(val qualifier: QualifierReceiver) : CallableReceiver()
class BoundValueReference(val qualifier: QualifierReceiver) : CallableReceiver()
class ScopeReceiver(val receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver()
class ExplicitValueReceiver(val receiver: SimpleKotlinCallArgument) : CallableReceiver()
}
private val CallableReceiver.asReceiverValueForVisibilityChecks: ReceiverValue
get() = when(this) {
is CallableReceiver.ScopeReceiver -> receiver.receiverValue
is CallableReceiver.ExplicitValueReceiver -> receiver.receiver.receiverValue
is CallableReceiver.BoundValueReference -> qualifier.classValueReceiver ?: Visibilities.ALWAYS_SUITABLE_RECEIVER
is CallableReceiver.UnboundReference -> (qualifier.descriptor as? ClassDescriptor)?.defaultType?.let(::TransientReceiver)
?: Visibilities.ALWAYS_SUITABLE_RECEIVER
}
/**
* Suppose we have class A with staticM, memberM, memberExtM.
* For A::staticM both receivers will be null
* For A::memberM dispatchReceiver = UnboundReceiver, extensionReceiver = null
* For a::memberExtM dispatchReceiver = ExplicitValueReceiver, extensionReceiver = ExplicitValueReceiver
*
* For class B with companion object B::companionM dispatchReceiver = BoundValueReference
*/
class CallableReferenceCandidate(
val candidate: CallableDescriptor,
val dispatchReceiver: CallableReceiver?,
val extensionReceiver: CallableReceiver?,
val reflectionCandidateType: UnwrappedType,
val numDefaults: Int,
override val status: ResolutionCandidateStatus
) : Candidate {
override val isSuccessful get() = status.resultingApplicability.isSuccess
}
/**
* cases: class A {}, class B { companion object }, object C, enum class D { E }
* A::foo <-> Type
* a::foo <-> Expression
* B::foo <-> Type
* C::foo <-> Object
* D.E::foo <-> Expression
*/
fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory): ScopeTowerProcessor<CallableReferenceCandidate> {
val lhsResult = factory.argument.lhsResult
when (lhsResult) {
LHSResult.Empty, is LHSResult.Expression -> {
val explicitReceiver = (lhsResult as? LHSResult.Expression)?.lshCallArgument?.receiver
return factory.createCallableProcessor(explicitReceiver)
}
is LHSResult.Type -> {
val static = factory.createCallableProcessor(lhsResult.qualifier)
val unbound = factory.createCallableProcessor(lhsResult.unboundDetailedReceiver)
// note that if we use CompositeScopeTowerProcessor then static will win over unbound members
val staticOrUnbound = CompositeSimpleScopeTowerProcessor(static, unbound)
val asValue = lhsResult.qualifier.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound
return CompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue))
}
is LHSResult.Object -> {
// callable reference to nested class constructor
val static = factory.createCallableProcessor(lhsResult.qualifier)
val boundObjectReference = factory.createCallableProcessor(lhsResult.objectValueReceiver)
return CompositeSimpleScopeTowerProcessor(static, boundObjectReference)
}
}
}
class CallableReferencesCandidateFactory(
val argument: CallableReferenceKotlinCallArgument,
val outerCallContext: KotlinCallContext,
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
val expectedType: UnwrappedType?
) : CandidateFactory<CallableReferenceCandidate> {
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
createCallableReferenceProcessor(outerCallContext.scopeTower, argument.rhsName, this, explicitReceiver)
override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): CallableReferenceCandidate {
val dispatchCallableReceiver = towerCandidate.dispatchReceiver?.let { toCallableReceiver(it, explicitReceiverKind == DISPATCH_RECEIVER) }
val extensionCallableReceiver = extensionReceiver?.let { toCallableReceiver(it, explicitReceiverKind == EXTENSION_RECEIVER) }
val candidateDescriptor = towerCandidate.descriptor
val (reflectionCandidateType, defaults) = buildReflectionType(candidateDescriptor,
dispatchCallableReceiver,
extensionCallableReceiver,
expectedType)
if (candidateDescriptor !is CallableMemberDescriptor) {
val status = ResolutionCandidateStatus(listOf(NotCallableMemberReference(argument, candidateDescriptor)))
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
reflectionCandidateType, defaults, status)
}
val diagnostics = SmartList<KotlinCallDiagnostic>()
val invisibleMember = Visibilities.findInvisibleMember(dispatchCallableReceiver?.asReceiverValueForVisibilityChecks,
candidateDescriptor, outerCallContext.scopeTower.lexicalScope.ownerDescriptor)
if (invisibleMember != null) {
diagnostics.add(VisibilityError(invisibleMember))
}
// todo smartcast on receiver diagnostic and CheckInstantiationOfAbstractClass
compatibilityChecker {
if (it.hasContradiction || expectedType == null) return@compatibilityChecker
val toFreshSubstitutor = CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, it, kotlinCall = null)
val reflectionType = toFreshSubstitutor.safeSubstitute(reflectionCandidateType)
it.addSubtypeConstraint(reflectionType, expectedType, ArgumentConstraintPosition(argument))
if (it.hasContradiction) diagnostics.add(CallableReferenceNotCompatible(argument, candidateDescriptor, expectedType, reflectionType))
}
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
reflectionCandidateType, defaults, ResolutionCandidateStatus(diagnostics))
}
private fun getArgumentAndReturnTypeUseMappingByExpectedType(
descriptor: FunctionDescriptor,
expectedType: UnwrappedType?,
unboundReceiverCount: Int
): Triple<Array<KotlinType>, CoercionStrategy, Int>? {
if (expectedType == null) return null
val functionType =
if (expectedType.isFunctionType) {
expectedType
}
else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
expectedType.immediateSupertypes().first { it.isFunctionType }
}
else {
return null
}
val expectedArgumentCount = functionType.arguments.size - unboundReceiverCount - 1 // 1 -- return type
if (expectedArgumentCount < 0) return null
val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) }
val argumentMapping = outerCallContext.argumentsToParametersMapper.mapArguments(fakeArguments, externalArgument = null, descriptor = descriptor)
if (argumentMapping.diagnostics.any { !it.candidateApplicability.isSuccess }) return null
/**
* (A, B, C) -> Unit
* fun foo(a: A, b: B = B(), vararg c: C)
*/
var defaults = 0
val mappedArguments = arrayOfNulls<KotlinType?>(fakeArguments.size)
for ((valueParameter, resolvedArgument) in argumentMapping.parameterToCallArgumentMap) {
for (fakeArgument in resolvedArgument.arguments) {
val index = (fakeArgument as FakeKotlinCallArgumentForCallableReference).index
val substitutedParameter = descriptor.valueParameters.getOrNull(valueParameter.index) ?: continue
mappedArguments[index] = substitutedParameter.varargElementType ?: substitutedParameter.type
}
if (resolvedArgument == ResolvedCallArgument.DefaultArgument) defaults++
}
if (mappedArguments.any { it == null }) return null
val unitExpectedType = functionType.let(KotlinType::getReturnTypeFromFunctionType).takeIf { it.upperIfFlexible().isUnit() }
val coercion = if (unitExpectedType != null) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION
@Suppress("UNCHECKED_CAST")
return Triple(mappedArguments as Array<KotlinType>, coercion, defaults)
}
private fun buildReflectionType(
descriptor: CallableDescriptor,
dispatchReceiver: CallableReceiver?,
extensionReceiver: CallableReceiver?,
expectedType: UnwrappedType?
): Pair<UnwrappedType, /*defaults*/ Int> {
val argumentsAndReceivers = ArrayList<KotlinType>(descriptor.valueParameters.size + 2)
if (dispatchReceiver is CallableReceiver.UnboundReference) {
argumentsAndReceivers.add(descriptor.dispatchReceiverParameter?.type
?: error("Dispatch receiver should be not null for descriptor: $descriptor"))
}
if (extensionReceiver is CallableReceiver.UnboundReference) {
argumentsAndReceivers.add(descriptor.extensionReceiverParameter?.type
?: error("Extension receiver should be not null for descriptor: $descriptor"))
}
val descriptorReturnType = descriptor.returnType
?: ErrorUtils.createErrorType("Error return type for descriptor: $descriptor")
when (descriptor) {
is PropertyDescriptor -> {
val mutable = descriptor.isVar && run {
val setter = descriptor.setter
setter == null || Visibilities.isVisible(dispatchReceiver?.asReceiverValueForVisibilityChecks, setter,
outerCallContext.scopeTower.lexicalScope.ownerDescriptor)
}
return outerCallContext.reflectionTypes.getKPropertyType(Annotations.EMPTY, argumentsAndReceivers, descriptorReturnType, mutable) to 0
}
is FunctionDescriptor -> {
val returnType: KotlinType
val defaults: Int
val argumentsAndExpectedTypeCoercion = getArgumentAndReturnTypeUseMappingByExpectedType(descriptor, expectedType,
unboundReceiverCount = argumentsAndReceivers.size)
if (argumentsAndExpectedTypeCoercion == null) {
descriptor.valueParameters.mapTo(argumentsAndReceivers) { it.type }
returnType = descriptorReturnType
defaults = 0
}
else {
val (arguments, coercion) = argumentsAndExpectedTypeCoercion
defaults = argumentsAndExpectedTypeCoercion.third
argumentsAndReceivers.addAll(arguments)
returnType = if (coercion == CoercionStrategy.COERCION_TO_UNIT) descriptor.builtIns.unitType else descriptorReturnType
}
return outerCallContext.reflectionTypes.getKFunctionType(Annotations.EMPTY, null, argumentsAndReceivers, null,
returnType, descriptor.builtIns) to defaults
}
else -> error("Unsupported descriptor type: $descriptor")
}
}
private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver {
if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver)
val lhsResult = argument.lhsResult
return when (lhsResult) {
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument)
is LHSResult.Type -> {
if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) {
CallableReceiver.BoundValueReference(lhsResult.qualifier)
}
else {
CallableReceiver.UnboundReference(lhsResult.qualifier)
}
}
is LHSResult.Object -> CallableReceiver.BoundValueReference(lhsResult.qualifier)
else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult")
}
}
}
class CallableReferenceNotCompatible(
val argument: CallableReferenceKotlinCallArgument,
val candidate: CallableMemberDescriptor,
val expectedType: UnwrappedType,
val callableReverenceType: UnwrappedType
) : KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
}
class NotCallableMemberReference(
val argument: CallableReferenceKotlinCallArgument,
val candidate: CallableDescriptor
) : KotlinCallDiagnostic(ResolutionCandidateApplicability.INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
}
@@ -16,104 +16,64 @@
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallContext
import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
import org.jetbrains.kotlin.resolve.calls.results.OverloadingConflictResolver
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.upperIfFlexible
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
class CallableReferenceResolver(
val reflectionTypes: ReflectionTypes,
val argumentsToParametersMapper: ArgumentsToParametersMapper
) {
fun resolvePropertyReference(
descriptor: PropertyDescriptor,
propertyReference: ChosenCallableReferenceDescriptor,
outerCall: KotlinCall,
scopeOwnerDescriptor: DeclarationDescriptor
): ResolvedPropertyReference {
val mutable = descriptor.isVar && run {
val setter = descriptor.setter
setter == null || Visibilities.isVisible(propertyReference.candidate.dispatchReceiver?.receiverValue, setter, scopeOwnerDescriptor)
}
val reflectionType = reflectionTypes.getKPropertyType(Annotations.EMPTY, listOfNotNull(propertyReference.dispatchNotBoundReceiver,
propertyReference.extensionNotBoundReceiver), descriptor.type.unwrap(), mutable)
return ResolvedPropertyReference(outerCall, propertyReference, reflectionType)
}
private fun createFakeArgumentsAndMapArguments(
functionReference: ChosenCallableReferenceDescriptor,
argumentCount: Int?
): Pair<List<UnwrappedType>, ArgumentsToParametersMapper.ArgumentMapping?> {
if (argumentCount == null) {
return functionReference.candidate.descriptor.valueParameters.map { it.varargElementType?.unwrap() ?: it.type.unwrap() } to null
}
val fakeArguments = (0..(argumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(functionReference, it) }
val argumentsToParametersMapping = argumentsToParametersMapper.mapArguments(fakeArguments, null, functionReference.candidate.descriptor)
val parameters = Array<UnwrappedType?>(argumentCount) { null }
for ((parameter, resolvedArgument) in argumentsToParametersMapping.parameterToCallArgumentMap) {
for (argument in resolvedArgument.arguments) {
val index = (argument as FakeKotlinCallArgumentForCallableReference).index
parameters[index] = parameter.type.unwrap()
}
}
return parameters.map { it ?: ErrorUtils.createErrorType("Wrong parameters mapping") } to argumentsToParametersMapping
}
fun resolveFunctionReference(
functionReference: ChosenCallableReferenceDescriptor,
outerCall: KotlinCall,
expectedType: UnwrappedType
): ResolvedFunctionReference {
val functionType =
if (expectedType.isFunctionType) {
expectedType
}
else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
expectedType.immediateSupertypes().first { it.isFunctionType }
}
else {
null
}
val parameterTypes = ArrayList<UnwrappedType>(functionType?.arguments?.size ?: 2)
parameterTypes.addIfNotNull(functionReference.dispatchNotBoundReceiver)
parameterTypes.addIfNotNull(functionReference.extensionNotBoundReceiver)
// (A, B, C) -> Int if A -- receiver, then B & C -- parameters
// here parameterTypes contains only receivers, all parameters will be added later
val argumentCount = functionType?.arguments?.let { it.size - parameterTypes.size - 1 }?.takeIf { it >= 0 }
val (parameters, mapping) = createFakeArgumentsAndMapArguments(functionReference, argumentCount)
parameterTypes.addAll(parameters)
val unitExpectedType = functionType?.let(KotlinType::getReturnTypeFromFunctionType)?.takeIf { it.upperIfFlexible().isUnit() }
// coercion to unit
val returnType = unitExpectedType ?: functionReference.candidate.descriptor.returnType
?: ErrorUtils.createErrorType("Error return type")
val kFunctionType = reflectionTypes.getKFunctionType(Annotations.EMPTY, null, parameterTypes, null, returnType, expectedType.builtIns)
return ResolvedFunctionReference(outerCall, functionReference, kFunctionType, mapping)
class CallableReferenceOverloadConflictResolver(
builtIns: KotlinBuiltIns,
specificityComparator: TypeSpecificityComparator,
isDescriptorFromSourcePredicate: IsDescriptorFromSourcePredicate,
constraintInjector: ConstraintInjector,
typeResolver: ResultTypeResolver
) : OverloadingConflictResolver<CallableReferenceCandidate>(
builtIns,
specificityComparator,
{ it.candidate },
{ SimpleConstraintSystemImpl(constraintInjector, typeResolver) },
Companion::createFlatSignature,
{ null },
isDescriptorFromSourcePredicate
) {
companion object {
private fun createFlatSignature(candidate: CallableReferenceCandidate) =
FlatSignature.createFromReflectionType(candidate, candidate.candidate, candidate.numDefaults, candidate.reflectionCandidateType)
}
}
class PostponeCallableReferenceArgument(
val argument: CallableReferenceKotlinCallArgument,
val expectedType: UnwrappedType
)
class CallableReferenceResolver(
val towerResolver: TowerResolver,
val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver
) {
fun runRLSResolution(
outerCallContext: KotlinCallContext,
callableReference: CallableReferenceKotlinCallArgument,
expectedType: UnwrappedType?, // this type can have not fixed type variable inside
compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be roll backed
): Set<CallableReferenceCandidate> {
val factory = CallableReferencesCandidateFactory(callableReference, outerCallContext, compatibilityChecker, expectedType)
val processor = createCallableReferenceProcessor(factory)
val candidates = towerResolver.runResolve(outerCallContext.scopeTower, processor, useOrder = true)
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(candidates, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
discriminateGenerics = false,
isDebuggerContext = outerCallContext.scopeTower.isDebuggerContext)
}
}
@@ -19,7 +19,10 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.components.CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
@@ -32,12 +35,10 @@ import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
import org.jetbrains.kotlin.types.lowerIfFlexible
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.supertypes
import org.jetbrains.kotlin.types.upperIfFlexible
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
import java.lang.UnsupportedOperationException
internal object CheckArguments : ResolutionPart {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
@@ -47,7 +48,8 @@ internal object CheckArguments : ResolutionPart {
val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue
for (argument in resolvedCallArgument.arguments) {
val diagnostic = checkArgument(callContext, kotlinCall, csBuilder, argument, argument.getExpectedType(parameterDescriptor))
val diagnostic = checkArgument(callContext, kotlinCall, csBuilder, argument, argument.getExpectedType(parameterDescriptor),
postponeCallableReferenceArguments)
diagnostics.addIfNotNull(diagnostic)
if (diagnostic != null && !diagnostic.candidateApplicability.isSuccess) break
@@ -61,13 +63,23 @@ internal object CheckArguments : ResolutionPart {
kotlinCall: KotlinCall,
csBuilder: ConstraintSystemBuilder,
argument: KotlinCallArgument,
expectedType: UnwrappedType
expectedType: UnwrappedType,
postponeCallableReferenceArguments: MutableList<PostponeCallableReferenceArgument>? = null
): KotlinCallDiagnostic? {
return when (argument) {
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, isReceiver = false)
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, isReceiver = false)
is LambdaKotlinCallArgument -> processLambdaArgument(kotlinCall, csBuilder, argument, expectedType)
is CallableReferenceKotlinCallArgument -> processCallableReferenceArgument(callContext, kotlinCall, csBuilder, argument, expectedType)
is CallableReferenceKotlinCallArgument -> {
if (postponeCallableReferenceArguments == null) {
processCallableReferenceArgument(callContext, kotlinCall, csBuilder, argument, expectedType)
}
else {
// callable reference resolution will be run after choosing single descriptor
postponeCallableReferenceArguments.add(PostponeCallableReferenceArgument(argument, expectedType))
null
}
}
else -> error("Incorrect argument type: $argument, ${argument.javaClass.canonicalName}.")
}
}
@@ -158,43 +170,27 @@ internal object CheckArguments : ResolutionPart {
argument: CallableReferenceKotlinCallArgument,
expectedType: UnwrappedType
): KotlinCallDiagnostic? {
val position = ArgumentConstraintPosition(argument)
if (argument !is ChosenCallableReferenceDescriptor) {
val lhsType = argument.lhsType
if (lhsType != null) {
// todo: case with two receivers
val expectedReceiverType = expectedType.supertypes().firstOrNull { it.isFunctionType }?.arguments?.first()?.type?.unwrap()
if (expectedReceiverType != null) {
// (lhsType) -> .. <: (expectedReceiverType) -> ... => expectedReceiverType <: lhsType
csBuilder.addSubtypeConstraint(expectedReceiverType, lhsType, position)
}
}
return null
val subLHSCall = ((argument.lhsResult as? LHSResult.Expression)?.lshCallArgument as? SubKotlinCallArgument)
if (subLHSCall != null) {
csBuilder.addInnerCall(subLHSCall.resolvedCall)
}
val candidates = callContext.callableReferenceResolver.runRLSResolution(callContext, argument, expectedType) { checkCallableReference ->
csBuilder.runTransaction { checkCallableReference(this); false }
}
val chosenCandidate = when (candidates.size) {
0 -> return NoneCallableReferenceCandidates(argument)
1 -> candidates.single()
else -> return CallableReferenceCandidatesAmbiguity(argument, candidates)
}
val descriptor = argument.candidate.descriptor
when (descriptor) {
is FunctionDescriptor -> {
// todo store resolved
val resolvedFunctionReference = callContext.callableReferenceResolver.resolveFunctionReference(
argument, kotlinCall, expectedType)
csBuilder.addSubtypeConstraint(resolvedFunctionReference.reflectionType, expectedType, position)
return resolvedFunctionReference.argumentsMapping?.diagnostics?.let {
ErrorCallableMapping(resolvedFunctionReference)
}
}
is PropertyDescriptor -> {
val toFreshSubstitutor = createToFreshVariableSubstitutorAndAddInitialConstraints(chosenCandidate.candidate, csBuilder, kotlinCall = null)
val reflectionType = toFreshSubstitutor.safeSubstitute(chosenCandidate.reflectionCandidateType)
csBuilder.addSubtypeConstraint(reflectionType, expectedType, ArgumentConstraintPosition(argument))
val resolvedCallableReference = ResolvedCallableReferenceArgument(kotlinCall, argument, toFreshSubstitutor.freshVariables, chosenCandidate)
csBuilder.addCallableReferenceArgument(resolvedCallableReference)
// todo store resolved
val resolvedPropertyReference = callContext.callableReferenceResolver.resolvePropertyReference(descriptor,
argument, kotlinCall, callContext.scopeTower.lexicalScope.ownerDescriptor)
csBuilder.addSubtypeConstraint(resolvedPropertyReference.reflectionType, expectedType, position)
}
else -> throw UnsupportedOperationException("Callable reference resolved to an unsupported descriptor: $descriptor")
}
return null
}
}
@@ -77,6 +77,7 @@ class KotlinCallCompleter(
is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate
else -> candidate as SimpleKotlinResolutionCandidate
}
resolveCallableReferenceArguments(topLevelCall)
if (topLevelCall.prepareForCompletion(expectedType)) {
val c = candidate.lastCall.constraintSystem.asCallCompleterContext()
@@ -88,6 +89,14 @@ class KotlinCallCompleter(
return ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate)
}
private fun resolveCallableReferenceArguments(candidate: SimpleKotlinResolutionCandidate) {
for (callableReferenceArgument in candidate.postponeCallableReferenceArguments) {
CheckArguments.processCallableReferenceArgument(candidate.callContext, candidate.kotlinCall, candidate.csBuilder,
callableReferenceArgument.argument, callableReferenceArgument.expectedType)
}
candidate.postponeCallableReferenceArguments.clear()
}
private fun toCompletedBaseResolvedCall(
c: Context,
candidate: KotlinResolutionCandidate,
@@ -262,6 +262,13 @@ class MissingReceiver(val functionExpression: FunctionExpression) : KotlinCallDi
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionExpression, this)
}
class ErrorCallableMapping(val functionReference: ResolvedFunctionReference) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(functionReference.argument, this)
}
class NoneCallableReferenceCandidates(val argument: CallableReferenceKotlinCallArgument) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
}
class CallableReferenceCandidatesAmbiguity(
val argument: CallableReferenceKotlinCallArgument,
val candidates: Collection<CallableReferenceCandidate>
) : KotlinCallDiagnostic(IMPOSSIBLE_TO_GENERATE) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.types.UnwrappedType
@@ -36,6 +37,7 @@ interface ConstraintSystemOperation {
interface ConstraintSystemBuilder : ConstraintSystemOperation {
fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall)
fun addLambdaArgument(resolvedLambdaArgument: ResolvedLambdaArgument)
fun addCallableReferenceArgument(resolvedCallableReferenceArgument: ResolvedCallableReferenceArgument)
// if runOperations return true, then this operation will be applied, and function return true
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.model
import org.jetbrains.kotlin.resolve.calls.inference.substitute
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeSubstitutor
@@ -55,6 +56,7 @@ interface ConstraintStorage {
val errors: List<KotlinCallDiagnostic>
val fixedTypeVariables: Map<TypeConstructor, UnwrappedType>
val lambdaArguments: List<ResolvedLambdaArgument>
val callableReferenceArguments: List<ResolvedCallableReferenceArgument>
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
object Empty : ConstraintStorage {
@@ -65,6 +67,7 @@ interface ConstraintStorage {
override val errors: List<KotlinCallDiagnostic> get() = emptyList()
override val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> get() = emptyMap()
override val lambdaArguments: List<ResolvedLambdaArgument> get() = emptyList()
override val callableReferenceArguments: List<ResolvedCallableReferenceArgument> get() = emptyList()
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() = emptyList()
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.model
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
@@ -84,5 +85,6 @@ internal class MutableConstraintStorage : ConstraintStorage {
override val errors: MutableList<KotlinCallDiagnostic> = ArrayList()
override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType> = LinkedHashMap()
override val lambdaArguments: MutableList<ResolvedLambdaArgument> = ArrayList()
override val callableReferenceArguments: MutableList<ResolvedCallableReferenceArgument> = ArrayList()
override val innerCalls: MutableList<ResolvedKotlinCall.OnlyResolvedKotlinCall> = ArrayList()
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
import org.jetbrains.kotlin.resolve.calls.inference.*
import org.jetbrains.kotlin.resolve.calls.inference.components.*
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallableReferenceArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
@@ -140,6 +141,11 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
storage.lambdaArguments.add(resolvedLambdaArgument)
}
override fun addCallableReferenceArgument(resolvedCallableReferenceArgument: ResolvedCallableReferenceArgument) {
checkState(State.BUILDING, State.COMPLETION)
storage.callableReferenceArguments.add(resolvedCallableReferenceArgument)
}
private fun getVariablesForFixation(): Map<NewTypeVariable, UnwrappedType> {
val fixedVariables = LinkedHashMap<NewTypeVariable, UnwrappedType>()
@@ -185,6 +191,7 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
storage.errors.addAll(otherSystem.errors)
storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables)
storage.lambdaArguments.addAll(otherSystem.lambdaArguments)
storage.callableReferenceArguments.addAll(otherSystem.callableReferenceArguments)
storage.innerCalls.addAll(otherSystem.innerCalls)
}
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTyp
class FakeKotlinCallArgumentForCallableReference(
val callableReference: ChosenCallableReferenceDescriptor,
val index: Int
) : KotlinCallArgument {
override val isSpread: Boolean get() = false
@@ -16,12 +16,13 @@
package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.tower.CandidateWithBoundDispatchReceiver
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.types.UnwrappedType
@@ -71,20 +72,51 @@ interface FunctionExpression : LambdaKotlinCallArgument {
val returnType: UnwrappedType?
}
/**
* cases: class A {}, class B { companion object }, object C, enum class D { E }
* A::foo <-> Type
* a::foo <-> Expression
* B::foo <-> Type
* C::foo <-> Object
* D.E::foo <-> Expression
*/
sealed class LHSResult {
class Type(val qualifier: QualifierReceiver): LHSResult() {
val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo
init {
assert(qualifier.descriptor is ClassDescriptor) {
"Should be ClassDescriptor: ${qualifier.descriptor}"
}
val unboundReceiver = TransientReceiver((qualifier.descriptor as ClassDescriptor).defaultType)
unboundDetailedReceiver = ReceiverValueWithSmartCastInfo(unboundReceiver, emptySet(), isStable = true)
}
}
class Object(val qualifier: QualifierReceiver): LHSResult() {
val objectValueReceiver: ReceiverValueWithSmartCastInfo
init {
assert(DescriptorUtils.isObject(qualifier.descriptor)) {
"Should be object descriptor: ${qualifier.descriptor}"
}
objectValueReceiver = qualifier.classValueReceiverWithSmartCastInfo ?: error("class value should be not null for $qualifier")
}
}
class Expression(val lshCallArgument: SimpleKotlinCallArgument): LHSResult()
// todo this case is forbid for now
object Empty: LHSResult()
}
interface CallableReferenceKotlinCallArgument : KotlinCallArgument {
override val isSpread: Boolean
get() = false
// Foo::bar lhsType = Foo. For a::bar where a is expression, this type is null
val lhsType: UnwrappedType?
val lhsResult: LHSResult
val constraintStorage: ConstraintStorage
}
interface ChosenCallableReferenceDescriptor : CallableReferenceKotlinCallArgument {
val candidate: CandidateWithBoundDispatchReceiver
val extensionReceiver: ReceiverValueWithSmartCastInfo?
val rhsName: Name
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.components.CheckArguments
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
@@ -38,7 +39,8 @@ class KotlinCallContext(
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
val resultTypeResolver: ResultTypeResolver,
val callableReferenceResolver: CallableReferenceResolver,
val constraintInjector: ConstraintInjector
val constraintInjector: ConstraintInjector,
val reflectionTypes: ReflectionTypes
)
class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall: KotlinCall): CandidateFactory<SimpleKotlinResolutionCandidate> {
@@ -51,6 +53,17 @@ class SimpleCandidateFactory(val callContext: KotlinCallContext, val kotlinCall:
explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe
fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this
private fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver
ExplicitReceiverKind.BOTH_RECEIVERS -> dispatchReceiverForInvokeExtension
else -> null
}
private fun KotlinCall.getExplicitExtensionReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver
else -> null
}
override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind,
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.calls.components.PostponeCallableReferenceArgument
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.Candidate
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateStatus
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.utils.SmartList
import java.util.*
@@ -112,6 +114,7 @@ open class SimpleKotlinResolutionCandidate(
initialDiagnostics: Collection<KotlinCallDiagnostic>
) : AbstractSimpleKotlinResolutionCandidate(NewConstraintSystemImpl(callContext.constraintInjector, callContext.resultTypeResolver), initialDiagnostics) {
val csBuilder: ConstraintSystemBuilder get() = constraintSystem.getBuilder()
val postponeCallableReferenceArguments = SmartList<PostponeCallableReferenceArgument>()
lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
@@ -18,12 +18,9 @@ package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns
@@ -55,45 +52,12 @@ class ResolvedLambdaArgument(
lateinit var resultArguments: List<KotlinCallArgument>
}
class ResolvedPropertyReference(
val outerCall: KotlinCall,
val argument: ChosenCallableReferenceDescriptor,
val reflectionType: UnwrappedType
) {
val boundDispatchReceiver: ReceiverValue? get() = argument.candidate.dispatchReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
val boundExtensionReceiver: ReceiverValue? get() = argument.extensionReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
}
class ResolvedFunctionReference(
val outerCall: KotlinCall,
val argument: ChosenCallableReferenceDescriptor,
val reflectionType: UnwrappedType,
val argumentsMapping: ArgumentsToParametersMapper.ArgumentMapping?
) {
val boundDispatchReceiver: ReceiverValue? get() = argument.candidate.dispatchReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
val boundExtensionReceiver: ReceiverValue? get() = argument.extensionReceiver?.receiverValue?.takeIf { it !is MockReceiverForCallableReference }
}
fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver
ExplicitReceiverKind.BOTH_RECEIVERS -> dispatchReceiverForInvokeExtension
else -> null
}
fun KotlinCall.getExplicitExtensionReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver
else -> null
}
class MockReceiverForCallableReference(val lhsOrDeclaredType: UnwrappedType) : ReceiverValue {
override fun getType() = lhsOrDeclaredType
override fun replaceType(newType: KotlinType) = MockReceiverForCallableReference(newType.unwrap())
}
val ChosenCallableReferenceDescriptor.dispatchNotBoundReceiver : UnwrappedType?
get() = (candidate.dispatchReceiver?.receiverValue as? MockReceiverForCallableReference)?.lhsOrDeclaredType
val ChosenCallableReferenceDescriptor.extensionNotBoundReceiver : UnwrappedType?
get() = (extensionReceiver as? MockReceiverForCallableReference)?.lhsOrDeclaredType
class ResolvedCallableReferenceArgument(
override val outerCall: KotlinCall,
override val argument: CallableReferenceKotlinCallArgument,
override val myTypeVariables: Collection<NewTypeVariable>,
val callableResolutionCandidate: CallableReferenceCandidate
) : ArgumentWithPostponeResolution() {
override val inputType: Collection<UnwrappedType> get() = emptyList()
override val outputType: UnwrappedType? = null
}
@@ -51,6 +51,23 @@ class FlatSignature<out T> private constructor(
val isGeneric = typeParameters.isNotEmpty()
companion object {
fun <T> createFromReflectionType(
origin: T,
descriptor: CallableDescriptor,
numDefaults: Int,
reflectionType: UnwrappedType
): FlatSignature<T> {
return FlatSignature(origin,
descriptor.typeParameters,
reflectionType.arguments.map { it.type }, // should we drop return type?
hasExtensionReceiver = false,
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
numDefaults = numDefaults,
isHeader = descriptor is MemberDescriptor && descriptor.isHeader,
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
)
}
fun <T> create(
origin: T,
descriptor: CallableDescriptor,