001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.psi.PsiElement;
021 import kotlin.Pair;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025 import org.jetbrains.kotlin.descriptors.*;
026 import org.jetbrains.kotlin.diagnostics.rendering.Renderers;
027 import org.jetbrains.kotlin.name.Name;
028 import org.jetbrains.kotlin.psi.*;
029 import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
030 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
031 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
032 import org.jetbrains.kotlin.resolve.calls.inference.TypeVariableKt;
033 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
034 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
035 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
036 import org.jetbrains.kotlin.resolve.scopes.ScopeUtils;
037 import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
038 import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
039 import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
040 import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
041 import org.jetbrains.kotlin.types.*;
042 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
043 import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
044 import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
045 import org.jetbrains.kotlin.types.expressions.FakeCallResolver;
046 import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
047
048 import java.util.Collections;
049 import java.util.List;
050
051 import static org.jetbrains.kotlin.diagnostics.Errors.*;
052 import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory;
053 import static org.jetbrains.kotlin.resolve.BindingContext.*;
054 import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER;
055 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
056 import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
057 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType;
058
059 public class DelegatedPropertyResolver {
060
061 public static final Name PROPERTY_DELEGATED_FUNCTION_NAME = Name.identifier("propertyDelegated");
062 public static final Name GETTER_NAME = Name.identifier("getValue");
063 public static final Name SETTER_NAME = Name.identifier("setValue");
064
065 public static final Name OLD_GETTER_NAME = Name.identifier("get");
066 public static final Name OLD_SETTER_NAME = Name.identifier("set");
067
068 @NotNull private final ExpressionTypingServices expressionTypingServices;
069 @NotNull private final FakeCallResolver fakeCallResolver;
070 @NotNull private final KotlinBuiltIns builtIns;
071 @NotNull private final SymbolUsageValidator symbolUsageValidator;
072
073 public DelegatedPropertyResolver(
074 @NotNull SymbolUsageValidator symbolUsageValidator,
075 @NotNull KotlinBuiltIns builtIns,
076 @NotNull FakeCallResolver fakeCallResolver,
077 @NotNull ExpressionTypingServices expressionTypingServices
078 ) {
079 this.symbolUsageValidator = symbolUsageValidator;
080 this.builtIns = builtIns;
081 this.fakeCallResolver = fakeCallResolver;
082 this.expressionTypingServices = expressionTypingServices;
083 }
084
085 @Nullable
086 public KotlinType getDelegatedPropertyGetMethodReturnType(
087 @NotNull PropertyDescriptor propertyDescriptor,
088 @NotNull KtExpression delegateExpression,
089 @NotNull KotlinType delegateType,
090 @NotNull BindingTrace trace,
091 @NotNull LexicalScope delegateFunctionsScope
092 ) {
093 resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, true);
094 ResolvedCall<FunctionDescriptor> resolvedCall =
095 trace.getBindingContext().get(DELEGATED_PROPERTY_RESOLVED_CALL, propertyDescriptor.getGetter());
096 return resolvedCall != null ? resolvedCall.getResultingDescriptor().getReturnType() : null;
097 }
098
099 public void resolveDelegatedPropertyGetMethod(
100 @NotNull PropertyDescriptor propertyDescriptor,
101 @NotNull KtExpression delegateExpression,
102 @NotNull KotlinType delegateType,
103 @NotNull BindingTrace trace,
104 @NotNull LexicalScope delegateFunctionsScope
105 ) {
106 KotlinType returnType = getDelegatedPropertyGetMethodReturnType(
107 propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope);
108 KotlinType propertyType = propertyDescriptor.getType();
109
110 /* Do not check return type of get() method of delegate for properties with DeferredType because property type is taken from it */
111 if (!(propertyType instanceof DeferredType) && returnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, propertyType)) {
112 Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, propertyDescriptor.getGetter());
113 assert call != null : "Call should exists for " + propertyDescriptor.getGetter();
114 trace.report(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH
115 .on(delegateExpression, renderCall(call, trace.getBindingContext()), propertyDescriptor.getType(), returnType));
116 }
117 }
118
119 public void resolveDelegatedPropertySetMethod(
120 @NotNull PropertyDescriptor propertyDescriptor,
121 @NotNull KtExpression delegateExpression,
122 @NotNull KotlinType delegateType,
123 @NotNull BindingTrace trace,
124 @NotNull LexicalScope delegateFunctionsScope
125 ) {
126 resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, false);
127 }
128
129 @NotNull
130 private static KtExpression createExpressionForProperty(@NotNull KtPsiFactory psiFactory) {
131 return psiFactory.createExpression("null as " + KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName().asString() + "<*>");
132 }
133
134 public void resolveDelegatedPropertyPDMethod(
135 @NotNull PropertyDescriptor propertyDescriptor,
136 @NotNull KtExpression delegateExpression,
137 @NotNull KotlinType delegateType,
138 @NotNull BindingTrace trace,
139 @NotNull LexicalScope delegateFunctionsScope
140 ) {
141 TemporaryBindingTrace traceToResolvePDMethod = TemporaryBindingTrace.create(trace, "Trace to resolve propertyDelegated method in delegated property");
142 ExpressionTypingContext context = ExpressionTypingContext.newContext(
143 traceToResolvePDMethod, delegateFunctionsScope,
144 DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
145
146 KtPsiFactory psiFactory = KtPsiFactory(delegateExpression);
147 List<KtExpression> arguments = Collections.singletonList(createExpressionForProperty(psiFactory));
148 ExpressionReceiver receiver = ExpressionReceiver.Companion.create(delegateExpression, delegateType, trace.getBindingContext());
149
150 Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
151 fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, PROPERTY_DELEGATED_FUNCTION_NAME, delegateExpression);
152
153 Call call = resolutionResult.getFirst();
154 OverloadResolutionResults<FunctionDescriptor> functionResults = resolutionResult.getSecond();
155
156 if (!functionResults.isSuccess()) {
157 String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext());
158 if (functionResults.isIncomplete() || functionResults.isSingleResult() ||
159 functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
160 trace.report(DELEGATE_PD_METHOD_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
161 } else if (functionResults.isAmbiguity()) {
162 trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY
163 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
164 }
165 return;
166 }
167
168 trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor, functionResults.getResultingCall());
169 }
170
171 /* Resolve getValue() or setValue() methods from delegate */
172 private void resolveDelegatedPropertyConventionMethod(
173 @NotNull PropertyDescriptor propertyDescriptor,
174 @NotNull KtExpression delegateExpression,
175 @NotNull KotlinType delegateType,
176 @NotNull BindingTrace trace,
177 @NotNull LexicalScope delegateFunctionsScope,
178 boolean isGet
179 ) {
180 PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
181 assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
182
183 if (trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor) != null) return;
184
185 OverloadResolutionResults<FunctionDescriptor> functionResults = getDelegatedPropertyConventionMethod(
186 propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, isGet, true);
187 Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor);
188 assert call != null : "'getDelegatedPropertyConventionMethod' didn't record a call";
189
190 if (!functionResults.isSuccess()) {
191 String expectedFunction = renderCall(call, trace.getBindingContext());
192 if (functionResults.isSingleResult() || functionResults.isIncomplete() ||
193 functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) {
194 trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE
195 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
196 }
197 else if (functionResults.isAmbiguity()) {
198 trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY
199 .on(delegateExpression, expectedFunction, functionResults.getResultingCalls()));
200 }
201 else {
202 trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType));
203 }
204 return;
205 }
206
207 FunctionDescriptor resultingDescriptor = functionResults.getResultingDescriptor();
208
209 ResolvedCall<FunctionDescriptor> resultingCall = functionResults.getResultingCall();
210 PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
211 if (declaration instanceof KtProperty) {
212 KtProperty property = (KtProperty) declaration;
213 KtPropertyDelegate delegate = property.getDelegate();
214 if (delegate != null) {
215 PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
216
217 if (!resultingDescriptor.isOperator()) {
218 OperatorValidator.Companion.report(byKeyword, resultingDescriptor, trace);
219 }
220
221 symbolUsageValidator.validateCall(resultingCall, resultingCall.getResultingDescriptor(), trace, byKeyword);
222 }
223 }
224 trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, resultingCall);
225 }
226
227 /* Resolve getValue() or setValue() methods from delegate */
228 public OverloadResolutionResults<FunctionDescriptor> getDelegatedPropertyConventionMethod(
229 @NotNull PropertyDescriptor propertyDescriptor,
230 @NotNull KtExpression delegateExpression,
231 @NotNull KotlinType delegateType,
232 @NotNull BindingTrace trace,
233 @NotNull LexicalScope delegateFunctionsScope,
234 boolean isGet,
235 boolean isComplete
236 ) {
237 PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
238 assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
239
240 KotlinType expectedType = isComplete && isGet && !(propertyDescriptor.getType() instanceof DeferredType)
241 ? propertyDescriptor.getType() : TypeUtils.NO_EXPECTED_TYPE;
242
243 ExpressionTypingContext context = ExpressionTypingContext.newContext(
244 trace, delegateFunctionsScope,
245 DataFlowInfo.EMPTY, expectedType);
246
247 boolean hasThis = propertyDescriptor.getExtensionReceiverParameter() != null || propertyDescriptor.getDispatchReceiverParameter() != null;
248
249 List<KtExpression> arguments = Lists.newArrayList();
250 KtPsiFactory psiFactory = KtPsiFactory(delegateExpression);
251 arguments.add(psiFactory.createExpression(hasThis ? "this" : "null"));
252 arguments.add(createExpressionForProperty(psiFactory));
253
254 if (!isGet) {
255 KtReferenceExpression fakeArgument = (KtReferenceExpression) createFakeExpressionOfType(delegateExpression.getProject(), trace,
256 "fakeArgument" + arguments.size(),
257 propertyDescriptor.getType());
258 arguments.add(fakeArgument);
259 List<ValueParameterDescriptor> valueParameters = accessor.getValueParameters();
260 trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0));
261 }
262
263 Name functionName = isGet ? GETTER_NAME : SETTER_NAME;
264 ExpressionReceiver receiver = ExpressionReceiver.Companion.create(delegateExpression, delegateType, trace.getBindingContext());
265
266 Pair<Call, OverloadResolutionResults<FunctionDescriptor>> resolutionResult =
267 fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, functionName, delegateExpression);
268
269 OverloadResolutionResults<FunctionDescriptor> resolutionResults = resolutionResult.getSecond();
270
271 // Resolve get/set is getValue/setValue was not found. Temporary, for code migration
272 if (!resolutionResults.isSuccess() && !resolutionResults.isAmbiguity()) {
273 Name oldFunctionName = isGet ? OLD_GETTER_NAME : OLD_SETTER_NAME;
274 Pair<Call, OverloadResolutionResults<FunctionDescriptor>> additionalResolutionResult =
275 fakeCallResolver.makeAndResolveFakeCallInContext(receiver, context, arguments, oldFunctionName, delegateExpression);
276 if (additionalResolutionResult.getSecond().isSuccess()) {
277 FunctionDescriptor resultingDescriptor = additionalResolutionResult.getSecond().getResultingDescriptor();
278
279 PsiElement declaration = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
280 if (declaration instanceof KtProperty) {
281 KtProperty property = (KtProperty) declaration;
282 KtPropertyDelegate delegate = property.getDelegate();
283 if (delegate != null) {
284 PsiElement byKeyword = delegate.getByKeywordNode().getPsi();
285
286 trace.report(DELEGATE_RESOLVED_TO_DEPRECATED_CONVENTION.on(
287 byKeyword, resultingDescriptor, delegateType, functionName.asString()));
288 }
289 }
290
291 trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, additionalResolutionResult.getFirst());
292 return additionalResolutionResult.getSecond();
293 }
294 }
295
296 trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, resolutionResult.getFirst());
297 return resolutionResults;
298 }
299
300 private static String renderCall(@NotNull Call call, @NotNull BindingContext context) {
301 KtExpression calleeExpression = call.getCalleeExpression();
302 assert calleeExpression != null : "CalleeExpression should exists for fake call of convention method";
303 StringBuilder builder = new StringBuilder(calleeExpression.getText());
304 builder.append("(");
305 List<KotlinType> argumentTypes = Lists.newArrayList();
306 for (ValueArgument argument : call.getValueArguments()) {
307 argumentTypes.add(context.getType(argument.getArgumentExpression()));
308
309 }
310 builder.append(Renderers.RENDER_COLLECTION_OF_TYPES.render(argumentTypes));
311 builder.append(")");
312 return builder.toString();
313 }
314
315 @NotNull
316 public KotlinType resolveDelegateExpression(
317 @NotNull KtExpression delegateExpression,
318 @NotNull KtProperty property,
319 @NotNull PropertyDescriptor propertyDescriptor,
320 @NotNull LexicalScope scopeForDelegate,
321 @NotNull BindingTrace trace,
322 @NotNull DataFlowInfo dataFlowInfo
323 ) {
324 TemporaryBindingTrace traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property");
325 KtExpression calleeExpression = CallUtilKt.getCalleeExpressionIfAny(delegateExpression);
326 ConstraintSystemCompleter completer = createConstraintSystemCompleter(
327 property, propertyDescriptor, delegateExpression, scopeForDelegate, trace);
328 if (calleeExpression != null) {
329 traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer);
330 }
331 KotlinType delegateType = expressionTypingServices.safeGetType(scopeForDelegate, delegateExpression, NO_EXPECTED_TYPE,
332 dataFlowInfo, traceToResolveDelegatedProperty);
333 traceToResolveDelegatedProperty.commit(new TraceEntryFilter() {
334 @Override
335 public boolean accept(@Nullable WritableSlice<?, ?> slice, Object key) {
336 return slice != CONSTRAINT_SYSTEM_COMPLETER;
337 }
338 }, true);
339 return delegateType;
340 }
341
342 @NotNull
343 private ConstraintSystemCompleter createConstraintSystemCompleter(
344 @NotNull KtProperty property,
345 @NotNull final PropertyDescriptor propertyDescriptor,
346 @NotNull final KtExpression delegateExpression,
347 @NotNull LexicalScope scopeForDelegate,
348 @NotNull final BindingTrace trace
349 ) {
350 final LexicalScope delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForDelegate, propertyDescriptor);
351 final KotlinType expectedType = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
352 return new ConstraintSystemCompleter() {
353 @Override
354 public void completeConstraintSystem(
355 @NotNull ConstraintSystem.Builder constraintSystem, @NotNull ResolvedCall<?> resolvedCall
356 ) {
357 KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
358 if (returnType == null) return;
359
360 TypeSubstitutor typeVariableSubstitutor =
361 constraintSystem.getTypeVariableSubstitutors().get(TypeVariableKt.toHandle(resolvedCall.getCall()));
362 assert typeVariableSubstitutor != null : "No substitutor in the system for call: " + resolvedCall.getCall();
363
364 TemporaryBindingTrace traceToResolveConventionMethods =
365 TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods");
366 OverloadResolutionResults<FunctionDescriptor>
367 getMethodResults = getDelegatedPropertyConventionMethod(
368 propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
369 true, false
370 );
371
372 if (conventionMethodFound(getMethodResults)) {
373 FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor();
374 KotlinType returnTypeOfGetMethod = descriptor.getReturnType();
375 if (returnTypeOfGetMethod != null && !TypeUtils.noExpectedType(expectedType)) {
376 KotlinType returnTypeInSystem = typeVariableSubstitutor.substitute(returnTypeOfGetMethod, Variance.INVARIANT);
377 if (returnTypeInSystem != null) {
378 constraintSystem.addSubtypeConstraint(returnTypeInSystem, expectedType, FROM_COMPLETER.position());
379 }
380 }
381 addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor);
382 }
383 if (!propertyDescriptor.isVar()) return;
384
385 // For the case: 'val v by d' (no declared type).
386 // When we add a constraint for 'set' method for delegated expression 'd' we use a type of the declared variable 'v'.
387 // 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).
388 if (propertyDescriptor.getReturnType() instanceof DeferredType) return;
389
390 OverloadResolutionResults<FunctionDescriptor>
391 setMethodResults = getDelegatedPropertyConventionMethod(
392 propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
393 false, false
394 );
395
396 if (conventionMethodFound(setMethodResults)) {
397 FunctionDescriptor descriptor = setMethodResults.getResultingDescriptor();
398 List<ValueParameterDescriptor> valueParameters = descriptor.getValueParameters();
399 if (valueParameters.size() == 3) {
400 ValueParameterDescriptor valueParameterForThis = valueParameters.get(2);
401
402 if (!noExpectedType(expectedType)) {
403 constraintSystem.addSubtypeConstraint(
404 expectedType,
405 typeVariableSubstitutor.substitute(valueParameterForThis.getType(), Variance.INVARIANT),
406 FROM_COMPLETER.position()
407 );
408 }
409 addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor);
410 }
411 }
412 }
413
414 private boolean conventionMethodFound(@NotNull OverloadResolutionResults<FunctionDescriptor> results) {
415 return results.isSuccess() ||
416 (results.isSingleResult() &&
417 results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
418 }
419
420 private void addConstraintForThisValue(
421 ConstraintSystem.Builder constraintSystem,
422 TypeSubstitutor typeVariableSubstitutor,
423 FunctionDescriptor resultingDescriptor
424 ) {
425 ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter();
426 ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter();
427 KotlinType typeOfThis =
428 extensionReceiver != null ? extensionReceiver.getType() :
429 dispatchReceiver != null ? dispatchReceiver.getType() :
430 builtIns.getNullableNothingType();
431
432 List<ValueParameterDescriptor> valueParameters = resultingDescriptor.getValueParameters();
433 if (valueParameters.isEmpty()) return;
434 ValueParameterDescriptor valueParameterForThis = valueParameters.get(0);
435
436 constraintSystem.addSubtypeConstraint(
437 typeOfThis,
438 typeVariableSubstitutor.substitute(valueParameterForThis.getType(), Variance.INVARIANT),
439 FROM_COMPLETER.position()
440 );
441 }
442 };
443 }
444 }