001 /*
002 * Copyright 2010-2013 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.jet.lang.resolve.calls.tasks;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.openapi.progress.ProgressIndicatorProvider;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.psi.JetExpression;
025 import org.jetbrains.jet.lang.psi.JetReferenceExpression;
026 import org.jetbrains.jet.lang.psi.JetSuperExpression;
027 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028 import org.jetbrains.jet.lang.resolve.LibrarySourceHacks;
029 import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
030 import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
031 import org.jetbrains.jet.lang.resolve.name.Name;
032 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033 import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
034 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
035 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
036 import org.jetbrains.jet.lang.types.ErrorUtils;
037 import org.jetbrains.jet.lang.types.NamespaceType;
038 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
039
040 import java.util.Collection;
041 import java.util.Collections;
042 import java.util.List;
043
044 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
045 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
046 import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
047
048 public class TaskPrioritizer {
049
050 public static <D extends CallableDescriptor> void splitLexicallyLocalDescriptors(
051 @NotNull Collection<ResolutionCandidate<D>> allDescriptors,
052 @NotNull DeclarationDescriptor containerOfTheCurrentLocality,
053 @NotNull Collection<ResolutionCandidate<D>> local,
054 @NotNull Collection<ResolutionCandidate<D>> nonlocal
055 ) {
056 for (ResolutionCandidate<D> resolvedCall : allDescriptors) {
057 if (DescriptorUtils.isLocal(containerOfTheCurrentLocality, resolvedCall.getDescriptor())) {
058 local.add(resolvedCall);
059 }
060 else {
061 nonlocal.add(resolvedCall);
062 }
063 }
064 }
065
066 @Nullable
067 public static JetSuperExpression getReceiverSuper(@NotNull ReceiverValue receiver) {
068 if (receiver instanceof ExpressionReceiver) {
069 ExpressionReceiver expressionReceiver = (ExpressionReceiver) receiver;
070 JetExpression expression = expressionReceiver.getExpression();
071 if (expression instanceof JetSuperExpression) {
072 return (JetSuperExpression) expression;
073 }
074 }
075 return null;
076 }
077
078 @NotNull
079 public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasks(
080 @NotNull BasicCallResolutionContext context,
081 @NotNull Name name,
082 @NotNull JetReferenceExpression functionReference,
083 @NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors
084 ) {
085 ReceiverValue explicitReceiver = context.call.getExplicitReceiver();
086 JetScope scope;
087 if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) {
088 // Receiver is a namespace
089 scope = explicitReceiver.getType().getMemberScope();
090 explicitReceiver = NO_RECEIVER;
091 }
092 else {
093 scope = context.scope;
094 }
095
096 ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(functionReference, context, new MyPriorityProvider<D>(context), null);
097 TaskPrioritizerContext<D, F> c = new TaskPrioritizerContext<D, F>(name, result, context, scope, callableDescriptorCollectors);
098 doComputeTasks(explicitReceiver, c);
099 return result.getTasks();
100 }
101
102 private static <D extends CallableDescriptor, F extends D> void doComputeTasks(
103 @NotNull ReceiverValue receiver,
104 @NotNull TaskPrioritizerContext<D, F> c
105 ) {
106 ProgressIndicatorProvider.checkCanceled();
107
108 boolean resolveInvoke = c.context.call.getThisObject().exists();
109 if (resolveInvoke) {
110 addCandidatesForInvoke(receiver, c);
111 return;
112 }
113 List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope);
114 if (receiver.exists()) {
115 addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*resolveInvoke=*/false);
116 return;
117 }
118 addCandidatesForNoReceiver(implicitReceivers, c);
119 }
120
121 private static <D extends CallableDescriptor, F extends D> void addCandidatesForExplicitReceiver(
122 @NotNull ReceiverValue receiver,
123 @NotNull List<ReceiverValue> implicitReceivers,
124 @NotNull TaskPrioritizerContext<D, F> c,
125 boolean resolveInvoke
126 ) {
127
128 List<ReceiverValue> variantsForExplicitReceiver = c.autoCastService.getVariantsForReceiver(receiver);
129
130 //members
131 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
132 Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
133 for (ReceiverValue variant : variantsForExplicitReceiver) {
134 Collection<? extends D> membersForThisVariant =
135 callableDescriptorCollector.getMembersByName(variant.getType(), c.name, c.context.trace);
136 convertWithReceivers(membersForThisVariant, Collections.singletonList(variant),
137 Collections.singletonList(NO_RECEIVER), members, resolveInvoke);
138 }
139 c.result.addCandidates(members);
140 }
141
142 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
143 //member extensions
144 for (ReceiverValue implicitReceiver : implicitReceivers) {
145 addMemberExtensionCandidates(implicitReceiver, variantsForExplicitReceiver,
146 callableDescriptorCollector, c, resolveInvoke);
147 }
148 //extensions
149 Collection<ResolutionCandidate<D>> extensions = convertWithImpliedThis(
150 c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace));
151 c.result.addCandidates(extensions);
152 }
153 }
154
155 private static <D extends CallableDescriptor, F extends D> void addMemberExtensionCandidates(
156 @NotNull ReceiverValue implicitReceiver,
157 @NotNull List<ReceiverValue> variantsForExplicitReceiver,
158 @NotNull CallableDescriptorCollector<? extends D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c,
159 boolean resolveInvoke
160 ) {
161 Collection<? extends D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
162 implicitReceiver.getType().getMemberScope(), c.name, c.context.trace);
163 List<ReceiverValue> variantsForImplicitReceiver = c.autoCastService.getVariantsForReceiver(implicitReceiver);
164 c.result.addCandidates(convertWithReceivers(memberExtensions, variantsForImplicitReceiver,
165 variantsForExplicitReceiver, resolveInvoke));
166 }
167
168 private static <D extends CallableDescriptor, F extends D> void addCandidatesForNoReceiver(
169 @NotNull List<ReceiverValue> implicitReceivers,
170 @NotNull TaskPrioritizerContext<D, F> c
171 ) {
172 List<Collection<ResolutionCandidate<D>>> localsList = Lists.newArrayList();
173 List<Collection<ResolutionCandidate<D>>> nonlocalsList = Lists.newArrayList();
174 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
175
176 Collection<ResolutionCandidate<D>> members =
177 convertWithImpliedThis(c.scope, Collections.singletonList(NO_RECEIVER), callableDescriptorCollector
178 .getNonExtensionsByName(c.scope, c.name, c.context.trace));
179
180 List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList();
181 List<ResolutionCandidate<D>> locals = Lists.newArrayList();
182 //noinspection unchecked,RedundantTypeArguments
183 TaskPrioritizer.<D>splitLexicallyLocalDescriptors(members, c.scope.getContainingDeclaration(), locals, nonlocals);
184
185 localsList.add(locals);
186 nonlocalsList.add(nonlocals);
187 }
188
189 //locals
190 c.result.addCandidates(localsList);
191
192 //try all implicit receivers as explicit
193 for (ReceiverValue implicitReceiver : implicitReceivers) {
194 addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*resolveInvoke=*/false);
195 }
196
197 //nonlocals
198 c.result.addCandidates(nonlocalsList);
199 }
200
201 private static <D extends CallableDescriptor, F extends D> void addCandidatesForInvoke(
202 @NotNull ReceiverValue explicitReceiver,
203 @NotNull TaskPrioritizerContext<D, F> c
204 ) {
205 List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope);
206
207 // For 'a.foo()' where foo has function type,
208 // a is explicitReceiver, foo is variableReceiver.
209 ReceiverValue variableReceiver = c.context.call.getThisObject();
210 assert variableReceiver.exists() : "'Invoke' call hasn't got variable receiver";
211
212 // For invocation a.foo() explicit receiver 'a'
213 // can be a receiver for 'foo' variable
214 // or for 'invoke' function.
215
216 // (1) a.foo + foo.invoke()
217 if (!explicitReceiver.exists()) {
218 addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*resolveInvoke=*/true);
219 }
220
221 // (2) foo + a.invoke()
222
223 // 'invoke' is member extension to explicit receiver while variable receiver is 'this object'
224 //trait A
225 //trait Foo { fun A.invoke() }
226
227 if (explicitReceiver.exists()) {
228 //a.foo()
229 addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c);
230 return;
231 }
232 // with (a) { foo() }
233 for (ReceiverValue implicitReceiver : implicitReceivers) {
234 addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c);
235 }
236 }
237
238 private static <D extends CallableDescriptor, F extends D> void addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(
239 @NotNull ReceiverValue variableReceiver,
240 @NotNull ReceiverValue explicitReceiver,
241 @NotNull TaskPrioritizerContext<D, F> c
242 ) {
243 List<ReceiverValue> variantsForExplicitReceiver = c.autoCastService.getVariantsForReceiver(explicitReceiver);
244
245 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
246 addMemberExtensionCandidates(variableReceiver, variantsForExplicitReceiver, callableDescriptorCollector, c, /*resolveInvoke=*/true);
247 }
248 }
249
250 private static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithReceivers(
251 @NotNull Collection<? extends D> descriptors,
252 @NotNull Iterable<ReceiverValue> thisObjects,
253 @NotNull Iterable<ReceiverValue> receiverParameters,
254 boolean hasExplicitThisObject
255 ) {
256 Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
257 convertWithReceivers(descriptors, thisObjects, receiverParameters, result, hasExplicitThisObject);
258 return result;
259 }
260
261 private static <D extends CallableDescriptor> void convertWithReceivers(
262 @NotNull Collection<? extends D> descriptors,
263 @NotNull Iterable<ReceiverValue> thisObjects,
264 @NotNull Iterable<ReceiverValue> receiverParameters,
265 @NotNull Collection<ResolutionCandidate<D>> result,
266 boolean hasExplicitThisObject
267 ) {
268 for (ReceiverValue thisObject : thisObjects) {
269 for (ReceiverValue receiverParameter : receiverParameters) {
270 for (D extension : descriptors) {
271 if (DescriptorUtils.isConstructorOfStaticNestedClass(extension)) {
272 // We don't want static nested classes' constructors to be resolved with expectedThisObject
273 continue;
274 }
275 ResolutionCandidate<D> candidate = ResolutionCandidate.create(extension);
276 candidate.setThisObject(thisObject);
277 candidate.setReceiverArgument(receiverParameter);
278 candidate.setExplicitReceiverKind(
279 hasExplicitThisObject ? ExplicitReceiverKind.BOTH_RECEIVERS : ExplicitReceiverKind.THIS_OBJECT);
280 result.add(candidate);
281 }
282 }
283 }
284 }
285
286 public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThis(
287 @NotNull JetScope scope,
288 @NotNull Collection<ReceiverValue> receiverParameters,
289 @NotNull Collection<? extends D> descriptors
290 ) {
291 Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
292 for (ReceiverValue receiverParameter : receiverParameters) {
293 for (D descriptor : descriptors) {
294 ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor);
295 candidate.setReceiverArgument(receiverParameter);
296 candidate.setExplicitReceiverKind(
297 receiverParameter.exists() ? ExplicitReceiverKind.RECEIVER_ARGUMENT : ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
298 if (setImpliedThis(scope, candidate)) {
299 result.add(candidate);
300 }
301 }
302 }
303 if (receiverParameters.size() == 1 && !receiverParameters.iterator().next().exists()) {
304 for (D descriptor : descriptors) {
305 if (descriptor.getExpectedThisObject() != null && descriptor.getReceiverParameter() == null) {
306 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
307 if (descriptor instanceof ConstructorDescriptor) {
308 containingDeclaration = containingDeclaration.getContainingDeclaration();
309 }
310 if (containingDeclaration != null && isClassObject(containingDeclaration)) {
311 ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor);
312 candidate.setThisObject(((ClassDescriptor) containingDeclaration).getThisAsReceiverParameter().getValue());
313 candidate.setExplicitReceiverKind(ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
314 result.add(candidate);
315 }
316 }
317 }
318 }
319 return result;
320 }
321
322 private static <D extends CallableDescriptor> boolean setImpliedThis(
323 @NotNull JetScope scope,
324 @NotNull ResolutionCandidate<D> candidate
325 ) {
326 ReceiverParameterDescriptor expectedThisObject = candidate.getDescriptor().getExpectedThisObject();
327 if (expectedThisObject == null) return true;
328 List<ReceiverParameterDescriptor> receivers = scope.getImplicitReceiversHierarchy();
329 for (ReceiverParameterDescriptor receiver : receivers) {
330 if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) {
331 // TODO : Autocasts & nullability
332 candidate.setThisObject(expectedThisObject.getValue());
333 return true;
334 }
335 }
336 return false;
337 }
338
339 public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasksFromCandidates(
340 @NotNull BasicCallResolutionContext context,
341 @NotNull JetReferenceExpression functionReference,
342 @NotNull Collection<ResolutionCandidate<D>> candidates,
343 @Nullable TracingStrategy tracing
344 ) {
345 ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(
346 functionReference, context, new MyPriorityProvider<D>(context), tracing);
347 result.addCandidates(candidates);
348 return result.getTasks();
349 }
350
351 private static class MyPriorityProvider<D extends CallableDescriptor>
352 implements ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>> {
353 private final BasicCallResolutionContext context;
354
355 public MyPriorityProvider(BasicCallResolutionContext context) {
356 this.context = context;
357 }
358
359 @Override
360 public int getPriority(ResolutionCandidate<D> call) {
361 return (isVisible(call) ? 2 : 0) + (isSynthesized(call) ? 0 : 1);
362 }
363
364 @Override
365 public int getMaxPriority() {
366 return 3;
367 }
368
369 private boolean isVisible(ResolutionCandidate<D> call) {
370 if (call == null) return false;
371 D candidateDescriptor = call.getDescriptor();
372 if (ErrorUtils.isError(candidateDescriptor)) return true;
373 return Visibilities.isVisible(candidateDescriptor, context.scope.getContainingDeclaration());
374 }
375
376 private boolean isSynthesized(ResolutionCandidate<D> call) {
377 D descriptor = call.getDescriptor();
378 return descriptor instanceof CallableMemberDescriptor &&
379 isOrOverridesSynthesized((CallableMemberDescriptor) descriptor);
380 }
381 }
382
383 private static class TaskPrioritizerContext<D extends CallableDescriptor, F extends D> {
384 @NotNull public final Name name;
385 @NotNull public final ResolutionTaskHolder<D, F> result;
386 @NotNull public final BasicCallResolutionContext context;
387 @NotNull public final JetScope scope;
388 @NotNull public final List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors;
389 @NotNull AutoCastServiceImpl autoCastService;
390
391 private TaskPrioritizerContext(
392 @NotNull Name name,
393 @NotNull ResolutionTaskHolder<D, F> result,
394 @NotNull BasicCallResolutionContext context,
395 @NotNull JetScope scope,
396 @NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors
397 ) {
398 this.name = name;
399 this.result = result;
400 this.context = context;
401 this.scope = scope;
402 this.callableDescriptorCollectors = callableDescriptorCollectors;
403 autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext());
404 }
405 }
406 }