From 558e8aaebb969cb79d366144e69d1f59077487ae Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 2 Dec 2016 12:58:22 +0300 Subject: [PATCH] DelegatedPropertyResolver: convert to Kotlin & cleanup. --- .../resolve/DelegatedPropertyResolver.kt | 620 ++++++++---------- 1 file changed, 277 insertions(+), 343 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt index f2260c2238f..85ab32d0f5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt @@ -14,461 +14,395 @@ * limitations under the License. */ -package org.jetbrains.kotlin.resolve; +package org.jetbrains.kotlin.resolve -import com.google.common.collect.Lists; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; -import com.intellij.util.Function; -import kotlin.Pair; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.renderer.DescriptorRenderer; -import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker; -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter; -import org.jetbrains.kotlin.resolve.calls.inference.TypeVariableKt; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; -import org.jetbrains.kotlin.resolve.scopes.LexicalScope; -import org.jetbrains.kotlin.resolve.scopes.ScopeUtils; -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.kotlin.types.*; -import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; -import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext; -import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices; -import org.jetbrains.kotlin.types.expressions.FakeCallResolver; -import org.jetbrains.kotlin.util.OperatorNameConventions; -import org.jetbrains.kotlin.util.slicedMap.WritableSlice; - -import java.util.Collections; -import java.util.List; - -import static org.jetbrains.kotlin.diagnostics.Errors.*; -import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory; -import static org.jetbrains.kotlin.resolve.BindingContext.*; -import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER; -import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; -import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType; -import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType; +import com.google.common.collect.Lists +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors +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.callUtil.getCalleeExpressionIfAny +import org.jetbrains.kotlin.resolve.calls.checkers.OperatorCallChecker +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 +import org.jetbrains.kotlin.resolve.calls.inference.toHandle +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.ScopeUtils +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE +import org.jetbrains.kotlin.types.TypeUtils.noExpectedType +import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +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.util.OperatorNameConventions //TODO: check for 'operator' modifier! -public class DelegatedPropertyResolver { - private final KotlinBuiltIns builtIns; - private final FakeCallResolver fakeCallResolver; - private final ExpressionTypingServices expressionTypingServices; +class DelegatedPropertyResolver( + private val builtIns: KotlinBuiltIns, + private val fakeCallResolver: FakeCallResolver, + private val expressionTypingServices: ExpressionTypingServices +) { - public DelegatedPropertyResolver( - @NotNull KotlinBuiltIns builtIns, - @NotNull FakeCallResolver fakeCallResolver, - @NotNull ExpressionTypingServices expressionTypingServices + fun resolvePropertyDelegate( + outerDataFlowInfo: DataFlowInfo, + property: KtProperty, + variableDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + propertyHeaderScope: LexicalScope, + trace: BindingTrace ) { - this.builtIns = builtIns; - this.fakeCallResolver = fakeCallResolver; - this.expressionTypingServices = expressionTypingServices; - } - - public void resolvePropertyDelegate( - @NotNull DataFlowInfo outerDataFlowInfo, - @NotNull KtProperty property, - @NotNull VariableDescriptorWithAccessors variableDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull LexicalScope propertyHeaderScope, - @NotNull BindingTrace trace - ) { - KtPropertyAccessor getter = property.getGetter(); - if (getter != null && getter.hasBody()) { - trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter)); + property.getter?.let { getter -> + if (getter.hasBody()) trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter)) + } + property.setter?.let { setter -> + if (setter.hasBody()) trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter)) } - KtPropertyAccessor setter = property.getSetter(); - if (setter != null && setter.hasBody()) { - trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter)); - } + val delegateFunctionsScope: LexicalScope + val initializerScope: LexicalScope - LexicalScope delegateFunctionsScope; - LexicalScope initializerScope; - - if (variableDescriptor instanceof PropertyDescriptor) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; - delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(propertyHeaderScope, propertyDescriptor); - initializerScope = ScopeUtils.makeScopeForPropertyInitializer(propertyHeaderScope, propertyDescriptor); + if (variableDescriptor is PropertyDescriptor) { + delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(propertyHeaderScope, variableDescriptor) + initializerScope = ScopeUtils.makeScopeForPropertyInitializer(propertyHeaderScope, variableDescriptor) } else { - delegateFunctionsScope = initializerScope = propertyHeaderScope; + initializerScope = propertyHeaderScope + delegateFunctionsScope = initializerScope } - KotlinType delegateType = resolveDelegateExpression( - delegateExpression, property, variableDescriptor, initializerScope, trace, outerDataFlowInfo - ); - - resolveDelegatedPropertyGetMethod( - variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo - ); - if (property.isVar()) { - resolveDelegatedPropertySetMethod( - variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo - ); + val delegateType = resolveDelegateExpression(delegateExpression, property, variableDescriptor, initializerScope, trace, outerDataFlowInfo) + resolveDelegatedPropertyGetMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo) + if (property.isVar) { + resolveDelegatedPropertySetMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo) } - resolveDelegatedPropertyPDMethod( - variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo - ); + resolveDelegatedPropertyPDMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, outerDataFlowInfo) } - @Nullable - public KotlinType getDelegatedPropertyGetMethodReturnType( - @NotNull VariableDescriptorWithAccessors variableDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull KotlinType delegateType, - @NotNull BindingTrace trace, - @NotNull LexicalScope delegateFunctionsScope, - @NotNull DataFlowInfo dataFlowInfo - ) { + fun getDelegatedPropertyGetMethodReturnType( + variableDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + delegateType: KotlinType, + trace: BindingTrace, + delegateFunctionsScope: LexicalScope, + dataFlowInfo: DataFlowInfo + ): KotlinType? { resolveDelegatedPropertyConventionMethod( variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo, true - ); - ResolvedCall resolvedCall = - trace.getBindingContext().get(DELEGATED_PROPERTY_RESOLVED_CALL, variableDescriptor.getGetter()); - return resolvedCall != null ? resolvedCall.getResultingDescriptor().getReturnType() : null; + ) + val resolvedCall = trace.bindingContext.get(DELEGATED_PROPERTY_RESOLVED_CALL, variableDescriptor.getter) + return if (resolvedCall != null) resolvedCall.resultingDescriptor.returnType else null } - private void resolveDelegatedPropertyGetMethod( - @NotNull VariableDescriptorWithAccessors variableDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull KotlinType delegateType, - @NotNull BindingTrace trace, - @NotNull LexicalScope delegateFunctionsScope, - @NotNull DataFlowInfo dataFlowInfo + private fun resolveDelegatedPropertyGetMethod( + variableDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + delegateType: KotlinType, + trace: BindingTrace, + delegateFunctionsScope: LexicalScope, + dataFlowInfo: DataFlowInfo ) { - KotlinType returnType = getDelegatedPropertyGetMethodReturnType( + val returnType = getDelegatedPropertyGetMethodReturnType( variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo - ); - KotlinType propertyType = variableDescriptor.getType(); + ) + val propertyType = variableDescriptor.type /* Do not check return type of get() method of delegate for properties with DeferredType because property type is taken from it */ - if (!(propertyType instanceof DeferredType) && returnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, propertyType)) { - Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, variableDescriptor.getGetter()); - assert call != null : "Call should exists for " + variableDescriptor.getGetter(); - trace.report(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH - .on(delegateExpression, renderCall(call, trace.getBindingContext()), variableDescriptor.getType(), returnType)); + if (propertyType !is DeferredType && returnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, propertyType)) { + val call = trace.bindingContext.get(DELEGATED_PROPERTY_CALL, variableDescriptor.getter) + ?: throw AssertionError("Call should exists for ${variableDescriptor.getter}") + trace.report(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH.on( + delegateExpression, renderCall(call, trace.bindingContext), variableDescriptor.type, returnType)) } } - private void resolveDelegatedPropertySetMethod( - @NotNull VariableDescriptorWithAccessors variableDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull KotlinType delegateType, - @NotNull BindingTrace trace, - @NotNull LexicalScope delegateFunctionsScope, - @NotNull DataFlowInfo dataFlowInfo + private fun resolveDelegatedPropertySetMethod( + variableDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + delegateType: KotlinType, + trace: BindingTrace, + delegateFunctionsScope: LexicalScope, + dataFlowInfo: DataFlowInfo ) { - resolveDelegatedPropertyConventionMethod( - variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo, false - ); + resolveDelegatedPropertyConventionMethod(variableDescriptor, delegateExpression, delegateType, trace, + delegateFunctionsScope, dataFlowInfo, false) } - @NotNull - private static KtExpression createExpressionForProperty(@NotNull KtPsiFactory psiFactory) { - return psiFactory.createExpression("null as " + KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString() + "<*>"); + private fun createExpressionForProperty(psiFactory: KtPsiFactory): KtExpression { + return psiFactory.createExpression("null as ${KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString()}<*>") } - private void resolveDelegatedPropertyPDMethod( - @NotNull VariableDescriptorWithAccessors variableDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull KotlinType delegateType, - @NotNull BindingTrace trace, - @NotNull LexicalScope delegateFunctionsScope, - @NotNull DataFlowInfo dataFlowInfo + private fun resolveDelegatedPropertyPDMethod( + variableDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + delegateType: KotlinType, + trace: BindingTrace, + delegateFunctionsScope: LexicalScope, + dataFlowInfo: DataFlowInfo ) { - TemporaryBindingTrace traceToResolvePDMethod = TemporaryBindingTrace.create(trace, "Trace to resolve propertyDelegated method in delegated property"); - ExpressionTypingContext context = ExpressionTypingContext.newContext( - traceToResolvePDMethod, delegateFunctionsScope, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE - ); + val traceToResolvePDMethod = TemporaryBindingTrace.create(trace, "Trace to resolve propertyDelegated method in delegated property") + val context = ExpressionTypingContext.newContext(traceToResolvePDMethod, delegateFunctionsScope, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE) - KtPsiFactory psiFactory = KtPsiFactory(delegateExpression); - List arguments = Collections.singletonList(createExpressionForProperty(psiFactory)); - ExpressionReceiver receiver = ExpressionReceiver.Companion.create(delegateExpression, delegateType, trace.getBindingContext()); + val psiFactory = KtPsiFactory(delegateExpression) + val arguments = listOf(createExpressionForProperty(psiFactory)) + val receiver = ExpressionReceiver.create(delegateExpression, delegateType, trace.bindingContext) - Pair> resolutionResult = - fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, OperatorNameConventions.PROPERTY_DELEGATED, delegateExpression); + val resolutionResult = fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, + OperatorNameConventions.PROPERTY_DELEGATED, delegateExpression) - Call call = resolutionResult.getFirst(); - OverloadResolutionResults functionResults = resolutionResult.getSecond(); + val call = resolutionResult.first + val functionResults = resolutionResult.second - if (!functionResults.isSuccess()) { - String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext()); - if (functionResults.isIncomplete() || functionResults.isSingleResult() || - functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { - trace.report(DELEGATE_PD_METHOD_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); - } else if (functionResults.isAmbiguity()) { - trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY - .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); + if (!functionResults.isSuccess) { + val expectedFunction = renderCall(call, traceToResolvePDMethod.bindingContext) + if (functionResults.isIncomplete || functionResults.isSingleResult || + functionResults.resultCode == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { + trace.report(DELEGATE_PD_METHOD_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.resultingCalls)) } - return; + else if (functionResults.isAmbiguity) { + trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY.on(delegateExpression, expectedFunction, functionResults.resultingCalls)) + } + return } - trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, variableDescriptor, functionResults.getResultingCall()); + trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, variableDescriptor, functionResults.resultingCall) } /* Resolve getValue() or setValue() methods from delegate */ - private void resolveDelegatedPropertyConventionMethod( - @NotNull VariableDescriptorWithAccessors propertyDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull KotlinType delegateType, - @NotNull BindingTrace trace, - @NotNull LexicalScope delegateFunctionsScope, - @NotNull DataFlowInfo dataFlowInfo, - boolean isGet + private fun resolveDelegatedPropertyConventionMethod( + propertyDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + delegateType: KotlinType, + trace: BindingTrace, + delegateFunctionsScope: LexicalScope, + dataFlowInfo: DataFlowInfo, + isGet: Boolean ) { - VariableAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); - assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText(); + val accessor = (if (isGet) propertyDescriptor.getter else propertyDescriptor.setter) + ?: throw AssertionError("Delegated property should have getter/setter $propertyDescriptor ${delegateExpression.text}") - if (trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor) != null) return; + if (trace.bindingContext.get(DELEGATED_PROPERTY_CALL, accessor) != null) return - OverloadResolutionResults functionResults = getDelegatedPropertyConventionMethod( - propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, dataFlowInfo, isGet, true - ); - Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor); - assert call != null : "'getDelegatedPropertyConventionMethod' didn't record a call"; + val functionResults = getDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, + delegateFunctionsScope, dataFlowInfo, isGet, true) + val call = trace.bindingContext.get(DELEGATED_PROPERTY_CALL, accessor) + ?: throw AssertionError("'getDelegatedPropertyConventionMethod' didn't record a call") - if (!functionResults.isSuccess()) { - String expectedFunction = renderCall(call, trace.getBindingContext()); - if (functionResults.isSingleResult() || functionResults.isIncomplete() || - functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { - trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE - .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); + if (!functionResults.isSuccess) { + val expectedFunction = renderCall(call, trace.bindingContext) + when { + functionResults.isSingleResult || + functionResults.isIncomplete || + functionResults.resultCode == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES -> + trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.resultingCalls)) + functionResults.isAmbiguity -> + trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY.on(delegateExpression, expectedFunction, functionResults.resultingCalls)) + else -> + trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType)) } - else if (functionResults.isAmbiguity()) { - trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY - .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); - } - else { - trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType)); - } - return; + return } - FunctionDescriptor resultingDescriptor = functionResults.getResultingDescriptor(); + val resultingDescriptor = functionResults.resultingDescriptor - ResolvedCall resultingCall = functionResults.getResultingCall(); - PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor); - if (declaration instanceof KtProperty) { - KtProperty property = (KtProperty) declaration; - KtPropertyDelegate delegate = property.getDelegate(); + val resultingCall = functionResults.resultingCall + val declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor) + if (declaration is KtProperty) { + val delegate = declaration.delegate if (delegate != null) { - PsiElement byKeyword = delegate.getByKeywordNode().getPsi(); - - if (!resultingDescriptor.isOperator()) { - OperatorCallChecker.Companion.report(byKeyword, resultingDescriptor, trace); + if (!resultingDescriptor.isOperator) { + val byKeyword = delegate.byKeywordNode.psi + OperatorCallChecker.report(byKeyword, resultingDescriptor, trace) } } } - trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall); + + trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall) } /* Resolve getValue() or setValue() methods from delegate */ - private OverloadResolutionResults getDelegatedPropertyConventionMethod( - @NotNull VariableDescriptorWithAccessors propertyDescriptor, - @NotNull KtExpression delegateExpression, - @NotNull KotlinType delegateType, - @NotNull BindingTrace trace, - @NotNull LexicalScope delegateFunctionsScope, - @NotNull DataFlowInfo dataFlowInfo, - boolean isGet, - boolean isComplete - ) { - VariableAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); - assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText(); + private fun getDelegatedPropertyConventionMethod( + propertyDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + delegateType: KotlinType, + trace: BindingTrace, + delegateFunctionsScope: LexicalScope, + dataFlowInfo: DataFlowInfo, + isGet: Boolean, + isComplete: Boolean + ): OverloadResolutionResults { + val accessor = (if (isGet) propertyDescriptor.getter else propertyDescriptor.setter) + ?: throw AssertionError("Delegated property should have getter/setter $propertyDescriptor ${delegateExpression.text}") - KotlinType expectedType = isComplete && isGet && !(propertyDescriptor.getType() instanceof DeferredType) - ? propertyDescriptor.getType() : TypeUtils.NO_EXPECTED_TYPE; + val expectedType = if (isComplete && isGet && propertyDescriptor.type !is DeferredType) + propertyDescriptor.type + else + TypeUtils.NO_EXPECTED_TYPE - ExpressionTypingContext context = ExpressionTypingContext.newContext(trace, delegateFunctionsScope, dataFlowInfo, expectedType); + val context = ExpressionTypingContext.newContext(trace, delegateFunctionsScope, dataFlowInfo, expectedType) - boolean hasThis = propertyDescriptor.getExtensionReceiverParameter() != null || propertyDescriptor.getDispatchReceiverParameter() != null; + val hasThis = propertyDescriptor.extensionReceiverParameter != null || propertyDescriptor.dispatchReceiverParameter != null - List arguments = Lists.newArrayList(); - KtPsiFactory psiFactory = KtPsiFactory(delegateExpression); - arguments.add(psiFactory.createExpression(hasThis ? "this" : "null")); - arguments.add(createExpressionForProperty(psiFactory)); + val arguments = Lists.newArrayList() + val psiFactory = KtPsiFactory(delegateExpression) + arguments.add(psiFactory.createExpression(if (hasThis) "this" else "null")) + arguments.add(createExpressionForProperty(psiFactory)) if (!isGet) { - KtReferenceExpression fakeArgument = (KtReferenceExpression) createFakeExpressionOfType(delegateExpression.getProject(), trace, - "fakeArgument" + arguments.size(), - propertyDescriptor.getType()); - arguments.add(fakeArgument); - List valueParameters = accessor.getValueParameters(); - trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0)); + val fakeArgument = createFakeExpressionOfType(delegateExpression.project, trace, + "fakeArgument${arguments.size}", + propertyDescriptor.type) as KtReferenceExpression + arguments.add(fakeArgument) + val valueParameters = accessor.valueParameters + trace.record(REFERENCE_TARGET, fakeArgument, valueParameters[0]) } - Name functionName = isGet ? OperatorNameConventions.GET_VALUE : OperatorNameConventions.SET_VALUE; - ExpressionReceiver receiver = ExpressionReceiver.Companion.create(delegateExpression, delegateType, trace.getBindingContext()); + val functionName = if (isGet) OperatorNameConventions.GET_VALUE else OperatorNameConventions.SET_VALUE + val receiver = ExpressionReceiver.create(delegateExpression, delegateType, trace.bindingContext) - Pair> resolutionResult = - fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression); + val resolutionResult = fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression) - trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, resolutionResult.getFirst()); - return resolutionResult.getSecond(); + trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, resolutionResult.first) + return resolutionResult.second } //TODO: diagnostics rendering does not belong here - private static String renderCall(@NotNull Call call, @NotNull BindingContext context) { - KtExpression calleeExpression = call.getCalleeExpression(); - assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method"; - StringBuilder builder = new StringBuilder(calleeExpression.getText()); - builder.append("("); - List argumentTypes = Lists.newArrayList(); - for (ValueArgument argument : call.getValueArguments()) { - argumentTypes.add(context.getType(argument.getArgumentExpression())); + private fun renderCall(call: Call, context: BindingContext): String { + val calleeExpression = call.calleeExpression + ?: throw AssertionError("CalleeExpression should exists for fake call of convention method") - } - String arguments = StringUtil.join(argumentTypes, new Function() { - @Override - public String fun(KotlinType type) { - return DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type); - } - }, ", "); - builder.append(arguments); - builder.append(")"); - return builder.toString(); + return call.valueArguments.joinToString( + prefix = "${calleeExpression.text}(", + postfix = ")", + separator = ", ", + transform = { argument -> + val type = context.getType(argument.getArgumentExpression()!!)!! + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type) + } + ) } - @NotNull - public KotlinType resolveDelegateExpression( - @NotNull KtExpression delegateExpression, - @NotNull KtProperty property, - @NotNull VariableDescriptorWithAccessors variableDescriptor, - @NotNull LexicalScope scopeForDelegate, - @NotNull BindingTrace trace, - @NotNull DataFlowInfo dataFlowInfo - ) { - TemporaryBindingTrace traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property"); - KtExpression calleeExpression = CallUtilKt.getCalleeExpressionIfAny(delegateExpression); - ConstraintSystemCompleter completer = createConstraintSystemCompleter( + fun resolveDelegateExpression( + delegateExpression: KtExpression, + property: KtProperty, + variableDescriptor: VariableDescriptorWithAccessors, + scopeForDelegate: LexicalScope, + trace: BindingTrace, + dataFlowInfo: DataFlowInfo + ): KotlinType { + val traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property") + val calleeExpression = delegateExpression.getCalleeExpressionIfAny() + val completer = createConstraintSystemCompleter( property, variableDescriptor, delegateExpression, scopeForDelegate, trace, dataFlowInfo - ); + ) if (calleeExpression != null) { - traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer); + traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer) } - KotlinType delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE, - dataFlowInfo, traceToResolveDelegatedProperty); - traceToResolveDelegatedProperty.commit(new TraceEntryFilter() { - @Override - public boolean accept(@Nullable WritableSlice slice, Object key) { - return slice != CONSTRAINT_SYSTEM_COMPLETER; - } - }, true); - return delegateType; + val delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE, + dataFlowInfo, traceToResolveDelegatedProperty) + traceToResolveDelegatedProperty.commit({ slice, key -> slice !== CONSTRAINT_SYSTEM_COMPLETER }, true) + return delegateType } - @NotNull - private ConstraintSystemCompleter createConstraintSystemCompleter( - @NotNull KtProperty property, - @NotNull final VariableDescriptorWithAccessors variableDescriptor, - @NotNull final KtExpression delegateExpression, - @NotNull LexicalScope scopeForDelegate, - @NotNull final BindingTrace trace, - @NotNull final DataFlowInfo dataFlowInfo - ) { - final LexicalScope delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForDelegate, variableDescriptor); - final KotlinType expectedType = property.getTypeReference() != null ? variableDescriptor.getType() : NO_EXPECTED_TYPE; - return new ConstraintSystemCompleter() { - @Override - public void completeConstraintSystem( - @NotNull ConstraintSystem.Builder constraintSystem, @NotNull ResolvedCall resolvedCall - ) { - KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType(); - if (returnType == null) return; + private fun createConstraintSystemCompleter( + property: KtProperty, + variableDescriptor: VariableDescriptorWithAccessors, + delegateExpression: KtExpression, + scopeForDelegate: LexicalScope, + trace: BindingTrace, + dataFlowInfo: DataFlowInfo + ): ConstraintSystemCompleter { + val delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForDelegate, variableDescriptor) + val expectedType = if (property.typeReference != null) variableDescriptor.type else NO_EXPECTED_TYPE - TypeSubstitutor typeVariableSubstitutor = - constraintSystem.getTypeVariableSubstitutors().get(TypeVariableKt.toHandle(resolvedCall.getCall())); - assert typeVariableSubstitutor != null : "No substitutor in the system for call: " + resolvedCall.getCall(); + return object : ConstraintSystemCompleter { + override fun completeConstraintSystem(constraintSystem: ConstraintSystem.Builder, resolvedCall: ResolvedCall<*>) { + val returnType = resolvedCall.candidateDescriptor.returnType ?: return - TemporaryBindingTrace traceToResolveConventionMethods = - TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods"); - OverloadResolutionResults - getMethodResults = getDelegatedPropertyConventionMethod( - variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope, - dataFlowInfo, true, false - ); + val typeVariableSubstitutor = constraintSystem.typeVariableSubstitutors[resolvedCall.call.toHandle()] + ?: throw AssertionError("No substitutor in the system for call: " + resolvedCall.call) + + val traceToResolveConventionMethods = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods") + val getMethodResults = getDelegatedPropertyConventionMethod( + variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope, + dataFlowInfo, true, false + ) if (conventionMethodFound(getMethodResults)) { - FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor(); - KotlinType returnTypeOfGetMethod = descriptor.getReturnType(); + val descriptor = getMethodResults.resultingDescriptor + val returnTypeOfGetMethod = descriptor.returnType if (returnTypeOfGetMethod != null && !TypeUtils.noExpectedType(expectedType)) { - KotlinType returnTypeInSystem = typeVariableSubstitutor.substitute(returnTypeOfGetMethod, Variance.INVARIANT); + val returnTypeInSystem = typeVariableSubstitutor.substitute(returnTypeOfGetMethod, Variance.INVARIANT) if (returnTypeInSystem != null) { - constraintSystem.addSubtypeConstraint(returnTypeInSystem, expectedType, FROM_COMPLETER.position()); + constraintSystem.addSubtypeConstraint(returnTypeInSystem, expectedType, FROM_COMPLETER.position()) } } - addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor); + addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor) } - if (!variableDescriptor.isVar()) return; + if (!variableDescriptor.isVar) return // For the case: 'val v by d' (no declared type). // When we add a constraint for 'set' method for delegated expression 'd' we use a type of the declared variable 'v'. // But if the type isn't known yet, the constraint shouldn't be added (we try to infer the type of 'v' here as well). - if (variableDescriptor.getReturnType() instanceof DeferredType) return; + if (variableDescriptor.returnType is DeferredType) return - OverloadResolutionResults - setMethodResults = getDelegatedPropertyConventionMethod( - variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope, - dataFlowInfo, false, false - ); + val setMethodResults = getDelegatedPropertyConventionMethod( + variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope, + dataFlowInfo, false, false + ) if (conventionMethodFound(setMethodResults)) { - FunctionDescriptor descriptor = setMethodResults.getResultingDescriptor(); - List valueParameters = descriptor.getValueParameters(); - if (valueParameters.size() == 3) { - ValueParameterDescriptor valueParameterForThis = valueParameters.get(2); + val descriptor = setMethodResults.resultingDescriptor + val valueParameters = descriptor.valueParameters + if (valueParameters.size == 3) { + val valueParameterForThis = valueParameters[2] if (!noExpectedType(expectedType)) { constraintSystem.addSubtypeConstraint( expectedType, - typeVariableSubstitutor.substitute(valueParameterForThis.getType(), Variance.INVARIANT), + typeVariableSubstitutor.substitute(valueParameterForThis.type, Variance.INVARIANT), FROM_COMPLETER.position() - ); + ) } - addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor); + addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor) } } } - private boolean conventionMethodFound(@NotNull OverloadResolutionResults results) { - return results.isSuccess() || - (results.isSingleResult() && - results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); - } + private fun conventionMethodFound(results: OverloadResolutionResults): Boolean = + results.isSuccess || + results.isSingleResult && results.resultCode == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH - private void addConstraintForThisValue( - ConstraintSystem.Builder constraintSystem, - TypeSubstitutor typeVariableSubstitutor, - FunctionDescriptor resultingDescriptor + private fun addConstraintForThisValue( + constraintSystem: ConstraintSystem.Builder, + typeVariableSubstitutor: TypeSubstitutor, + resultingDescriptor: FunctionDescriptor ) { - ReceiverParameterDescriptor extensionReceiver = variableDescriptor.getExtensionReceiverParameter(); - ReceiverParameterDescriptor dispatchReceiver = variableDescriptor.getDispatchReceiverParameter(); - KotlinType typeOfThis = - extensionReceiver != null ? extensionReceiver.getType() : - dispatchReceiver != null ? dispatchReceiver.getType() : - builtIns.getNullableNothingType(); + val extensionReceiver = variableDescriptor.extensionReceiverParameter + val dispatchReceiver = variableDescriptor.dispatchReceiverParameter + val typeOfThis = extensionReceiver?.type ?: dispatchReceiver?.type ?: builtIns.nullableNothingType - List valueParameters = resultingDescriptor.getValueParameters(); - if (valueParameters.isEmpty()) return; - ValueParameterDescriptor valueParameterForThis = valueParameters.get(0); + val valueParameters = resultingDescriptor.valueParameters + if (valueParameters.isEmpty()) return + val valueParameterForThis = valueParameters[0] constraintSystem.addSubtypeConstraint( typeOfThis, - typeVariableSubstitutor.substitute(valueParameterForThis.getType(), Variance.INVARIANT), + typeVariableSubstitutor.substitute(valueParameterForThis.type, Variance.INVARIANT), FROM_COMPLETER.position() - ); + ) } - }; + } } }