[NI] Add hacks for property delegation resolution.

This commit is contained in:
Stanislav Erokhin
2017-05-24 18:40:41 +03:00
committed by Mikhail Zarechenskiy
parent af138e7403
commit b9e9243e9d
4 changed files with 82 additions and 8 deletions
@@ -27,8 +27,12 @@ import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.calls.USE_NEW_INFERENCE
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER
@@ -47,6 +51,7 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType
import org.jetbrains.kotlin.types.expressions.FakeCallResolver
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
import org.jetbrains.kotlin.util.OperatorNameConventions
//TODO: check for 'operator' modifier!
@@ -310,8 +315,16 @@ class DelegatedPropertyResolver(
initializerScope: LexicalScope,
dataFlowInfo: DataFlowInfo
): OverloadResolutionResults<FunctionDescriptor> {
val expectedType = TypeUtils.NO_EXPECTED_TYPE
val context = ExpressionTypingContext.newContext(trace, initializerScope, dataFlowInfo, expectedType)
val context = ExpressionTypingContext.newContext(trace, initializerScope, dataFlowInfo, NO_EXPECTED_TYPE)
return getProvideDelegateMethod(propertyDescriptor, delegateExpression, delegateExpressionType, context)
}
private fun getProvideDelegateMethod(
propertyDescriptor: VariableDescriptorWithAccessors,
delegateExpression: KtExpression,
delegateExpressionType: KotlinType,
context: ExpressionTypingContext
): OverloadResolutionResults<FunctionDescriptor> {
val propertyHasReceiver = propertyDescriptor.dispatchReceiverParameter != null
val arguments = KtPsiFactory(delegateExpression, markGenerated = false).run {
listOf(
@@ -320,11 +333,11 @@ class DelegatedPropertyResolver(
)
}
val functionName = OperatorNameConventions.PROVIDE_DELEGATE
val receiver = ExpressionReceiver.create(delegateExpression, delegateExpressionType, trace.bindingContext)
val receiver = ExpressionReceiver.create(delegateExpression, delegateExpressionType, context.trace.bindingContext)
val (provideDelegateCall, provideDelegateResults) =
fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression)
trace.record(BindingContext.PROVIDE_DELEGATE_CALL, propertyDescriptor, provideDelegateCall)
context.trace.record(BindingContext.PROVIDE_DELEGATE_CALL, propertyDescriptor, provideDelegateCall)
return provideDelegateResults
}
@@ -362,7 +375,8 @@ class DelegatedPropertyResolver(
traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, it, completer)
}
val delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE, dataFlowInfo, traceToResolveDelegatedProperty)
val expectedTypeByNewInference = completer.resolveViaNewInference(delegateExpression, variableDescriptor, scopeForDelegate, trace, dataFlowInfo)
val delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, expectedTypeByNewInference ?: NO_EXPECTED_TYPE, dataFlowInfo, traceToResolveDelegatedProperty)
traceToResolveDelegatedProperty.commit({ slice, _ -> slice !== CONSTRAINT_SYSTEM_COMPLETER }, true)
@@ -479,5 +493,45 @@ class DelegatedPropertyResolver(
FROM_COMPLETER.position()
)
}
fun resolveViaNewInference(
delegateExpression: KtExpression,
variableDescriptor: VariableDescriptorWithAccessors,
scopeForDelegate: LexicalScope,
trace: BindingTrace,
dataFlowInfo: DataFlowInfo
): KotlinType? {
if (!USE_NEW_INFERENCE) return null
val traceToResolveConventionMethods = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods")
val delegateType = expressionTypingServices.getTypeInfo(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE, dataFlowInfo,
traceToResolveConventionMethods, false, delegateExpression, ContextDependency.DEPENDENT)
val contextForProvideDelegate = ExpressionTypingContext.newContext(traceToResolveConventionMethods, scopeForDelegate, delegateType.dataFlowInfo,
NO_EXPECTED_TYPE, ContextDependency.DEPENDENT, StatementFilter.NONE)
val provideDelegateResults = getProvideDelegateMethod(
variableDescriptor, delegateExpression, delegateType.type ?: return null, contextForProvideDelegate
)
var typeInfoForGetValueReceiver = delegateType
if (conventionMethodFound(provideDelegateResults)) {
val provideDelegateDescriptor = provideDelegateResults.resultingDescriptor
if (provideDelegateDescriptor.isOperator) {
typeInfoForGetValueReceiver = KotlinTypeInfo(provideDelegateDescriptor.returnType,
provideDelegateResults.resultingCall.dataFlowInfoForArguments.resultInfo)
}
}
getGetSetValueMethod(
variableDescriptor, delegateExpression, typeInfoForGetValueReceiver.type ?: return null,
traceToResolveConventionMethods, scopeForDelegate, typeInfoForGetValueReceiver.dataFlowInfo,
isGet = true, isComplete = true
)
val call = delegateExpression.getCall(traceToResolveConventionMethods.bindingContext)
return call.getResolvedCall(traceToResolveConventionMethods.bindingContext)?.resultingDescriptor?.returnType
}
}
}
@@ -426,7 +426,7 @@ class StubOnlyResolvedCall<D : CallableDescriptor>(val candidate: SimpleKotlinRe
override fun getStatus() = ResolutionStatus.UNKNOWN_STATUS
override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D
override fun getResultingDescriptor(): D = candidateDescriptor
override fun getResultingDescriptor(): D = candidate.descriptorWithFreshTypes as D
override fun getExtensionReceiver() = candidate.extensionReceiver?.receiver?.receiverValue
override fun getDispatchReceiver() = candidate.dispatchReceiverArgument?.receiver?.receiverValue
override fun getExplicitReceiverKind() = candidate.explicitReceiverKind
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.TypeResolver
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.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.components.ArgumentsToParametersMapper
@@ -50,6 +51,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -378,7 +380,22 @@ class PSICallResolver(
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
is ReceiverValue -> {
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
var subCallArgument: ReceiverKotlinCallArgument? = null
if (oldReceiver is ExpressionReceiver) {
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
val onlyResolvedCall = ktExpression?.getCall(context.trace.bindingContext)?.let {
context.trace.get(BindingContext.ONLY_RESOLVED_CALL, it)
}
if (onlyResolvedCall != null) {
subCallArgument = SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument(oldReceiver.expression),
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall)
}
}
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
}
else -> error("Incorrect receiver: $oldReceiver")
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
@@ -41,9 +42,11 @@ class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debu
sealed class NewTypeVariable(builtIns: KotlinBuiltIns, name: String) {
val freshTypeConstructor: TypeConstructor = TypeVariableTypeConstructor(builtIns, name)
// member scope is used if we have receiver with type TypeVariable(T)
// todo add to member scope methods from supertypes for type variable
val defaultType: SimpleType = KotlinTypeFactory.simpleType(
Annotations.EMPTY, freshTypeConstructor, arguments = emptyList(),
nullable = false, memberScope = ErrorUtils.createErrorScope("Type variable", true))
nullable = false, memberScope = builtIns.any.unsubstitutedMemberScope)
override fun toString() = freshTypeConstructor.toString()
}