Write LHS resolution result into a call position

This commit is contained in:
Victor Petukhov
2021-09-20 16:07:26 +03:00
parent 2f4d02d011
commit 8b85b4630b
6 changed files with 68 additions and 8 deletions
@@ -62,7 +62,7 @@ fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection(
val resolvedCall = callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false
resolvedCall to { f: CallableDescriptor -> (f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type }
}
is CallPosition.Unknown -> return false
is CallPosition.Unknown, is CallPosition.CallableReferenceRhs -> return false
}
val receiverType = resolvedCall.smartCastDispatchReceiverType
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
sealed class CallPosition {
@@ -34,4 +35,6 @@ sealed class CallPosition {
) : CallPosition()
class PropertyAssignment(val leftPart: KtExpression?, val isLeft: Boolean) : CallPosition()
class CallableReferenceRhs(val lhs: DoubleColonLHS?) : CallPosition()
}
@@ -320,6 +320,13 @@ class KotlinResolutionCallbacksImpl(
trace.record(BindingContext.NEW_INFERENCE_IS_LAMBDA_FOR_OVERLOAD_RESOLUTION_INLINE, literal, isLambdaInline)
}
override fun getLhsResult(call: KotlinCall): LHSResult {
val callableReferenceExpression = call.extractCallableReferenceExpression()
?: throw IllegalStateException("Not a callable reference")
val (_, lhsResult) = psiCallResolver.getLhsResult(topLevelCallContext, callableReferenceExpression)
return lhsResult
}
private fun convertSignedConstantToUnsigned(expression: KtExpression): IntegerValueTypeConstant? {
val constant = trace[BindingContext.COMPILE_TIME_VALUE, expression]
if (constant !is IntegerValueTypeConstant || !constantCanBeConvertedToUnsigned(constant)) return null
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
@@ -771,6 +772,47 @@ class PSICallResolver(
return createSimplePSICallArgument(context, valueArgument, typeInfo) ?: createParseErrorElement()
}
fun getLhsResult(context: BasicCallResolutionContext, ktExpression: KtCallableReferenceExpression): Pair<DoubleColonLHS?, LHSResult> {
val expressionTypingContext = ExpressionTypingContext.newContext(context)
if (ktExpression.isEmptyLHS) return null to LHSResult.Empty
val doubleColonLhs = (context.callPosition as? CallPosition.CallableReferenceRhs)?.lhs
?: doubleColonExpressionResolver.resolveDoubleColonLHS(ktExpression, expressionTypingContext)
?: return null to LHSResult.Empty
val lhsResult = when (doubleColonLhs) {
is DoubleColonLHS.Expression -> {
if (doubleColonLhs.isObjectQualifier) {
val classifier = doubleColonLhs.type.constructor.declarationDescriptor
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
} else {
LHSResult.Error
}
} else {
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, doubleColonLhs.typeInfo)
kotlinCallArgument?.let { LHSResult.Expression(it as SimpleKotlinCallArgument) } ?: LHSResult.Error
}
}
is DoubleColonLHS.Type -> {
val qualifiedExpression = ktExpression.receiverExpression!!
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
val classifier = doubleColonLhs.type.constructor.declarationDescriptor
if (classifier !is ClassDescriptor) {
expressionTypingContext.trace.report(Errors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS.on(ktExpression))
LHSResult.Error
} else {
LHSResult.Type(qualifier, doubleColonLhs.type.unwrap())
}
}
}
return doubleColonLhs to lhsResult
}
fun createCallableReferenceKotlinCallArgument(
context: BasicCallResolutionContext,
ktExpression: KtCallableReferenceExpression,
@@ -720,7 +720,8 @@ class DoubleColonExpressionResolver(
receiver: Receiver?,
reference: KtSimpleNameExpression,
outerContext: ResolutionContext<*>,
resolutionMode: ResolveArgumentsMode
resolutionMode: ResolveArgumentsMode,
lhs: DoubleColonLHS?
): ResolutionResultsAndTraceCommitCallback? {
// we should preserve information about `call` because callable references are analyzed two times,
// otherwise there will be not completed calls in trace
@@ -737,7 +738,12 @@ class DoubleColonExpressionResolver(
outerContext.replaceTraceAndCache(temporaryTrace)
val resolutionResults = callResolver.resolveCallForMember(
reference, BasicCallResolutionContext.create(newContext, call, CheckArgumentTypesMode.CHECK_CALLABLE_TYPE)
reference,
BasicCallResolutionContext.create(
newContext.replaceCallPosition(CallPosition.CallableReferenceRhs(lhs)),
call,
CheckArgumentTypesMode.CHECK_CALLABLE_TYPE
)
)
return when {
@@ -763,7 +769,7 @@ class DoubleColonExpressionResolver(
if (lhsType == null) {
if (!expression.isEmptyLHS) return null
return tryResolveRHSWithReceiver("resolve callable reference with empty LHS", null, reference, c, mode)
return tryResolveRHSWithReceiver("resolve callable reference with empty LHS", null, reference, c, mode, lhs)
?.apply { commitTrace() }?.results
}
@@ -780,14 +786,14 @@ class DoubleColonExpressionResolver(
if (qualifier is ClassQualifier) {
yieldIfNotNull(
tryResolveRHSWithReceiver(
"resolve unbound callable reference in static scope", qualifier, reference, c, mode
"resolve unbound callable reference in static scope", qualifier, reference, c, mode, lhs
)
)
}
yieldIfNotNull(
tryResolveRHSWithReceiver(
"resolve unbound callable reference with receiver", TransientReceiver(lhsType), reference, c, mode
"resolve unbound callable reference with receiver", TransientReceiver(lhsType), reference, c, mode, lhs
)
)
}
@@ -795,7 +801,7 @@ class DoubleColonExpressionResolver(
val expressionReceiver = ExpressionReceiver.create(expression.receiverExpression!!, lhsType, c.trace.bindingContext)
yieldIfNotNull(
tryResolveRHSWithReceiver(
"resolve bound callable reference", expressionReceiver, reference, c, mode
"resolve bound callable reference", expressionReceiver, reference, c, mode, lhs
)
)
@@ -806,7 +812,7 @@ class DoubleColonExpressionResolver(
val qualifier = ClassQualifier(calleeExpression, classifier)
yieldIfNotNull(
tryResolveRHSWithReceiver(
"resolve object callable reference in static scope", qualifier, reference, c, mode
"resolve object callable reference in static scope", qualifier, reference, c, mode, lhs
)
)
}
@@ -87,6 +87,8 @@ interface KotlinResolutionCallbacks {
fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom)
fun getLhsResult(call: KotlinCall): LHSResult
fun convertSignedConstantToUnsigned(argument: KotlinCallArgument): IntegerValueTypeConstant?
fun recordInlinabilityOfLambda(atom: Set<Map.Entry<SimpleResolutionCandidate, ResolvedLambdaAtom>>)