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.google.common.collect.Sets;
021 import com.intellij.openapi.progress.ProgressIndicatorProvider;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.psi.Call;
026 import org.jetbrains.jet.lang.psi.JetExpression;
027 import org.jetbrains.jet.lang.psi.JetSuperExpression;
028 import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext;
029 import org.jetbrains.jet.lang.resolve.calls.smartcasts.SmartCastUtils;
030 import org.jetbrains.jet.lang.resolve.name.Name;
031 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
032 import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils;
033 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
034 import org.jetbrains.jet.lang.resolve.scopes.receivers.QualifierReceiver;
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.JetType;
038 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
039 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
040
041 import java.util.Collection;
042 import java.util.List;
043
044 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
045 import static org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind.*;
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 (ExpressionTypingUtils.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 TracingStrategy tracing,
083 @NotNull CallableDescriptorCollectors<D> callableDescriptorCollectors
084 ) {
085 ReceiverValue explicitReceiver = context.call.getExplicitReceiver();
086 ResolutionTaskHolder<D, F> result =
087 new ResolutionTaskHolder<D, F>(context, new MyPriorityProvider<D>(context), tracing);
088 TaskPrioritizerContext<D, F> taskPrioritizerContext =
089 new TaskPrioritizerContext<D, F>(name, result, context, context.scope, callableDescriptorCollectors);
090
091 if (explicitReceiver instanceof QualifierReceiver) {
092 QualifierReceiver qualifierReceiver = (QualifierReceiver) explicitReceiver;
093 doComputeTasks(NO_RECEIVER, taskPrioritizerContext.replaceScope(qualifierReceiver.getNestedClassesAndPackageMembersScope()));
094 ReceiverValue classObjectReceiver = qualifierReceiver.getClassObjectReceiver();
095 if (classObjectReceiver.exists()) {
096 doComputeTasks(classObjectReceiver, taskPrioritizerContext);
097 }
098 }
099 else {
100 doComputeTasks(explicitReceiver, taskPrioritizerContext);
101 }
102
103 return result.getTasks();
104 }
105
106 private static <D extends CallableDescriptor, F extends D> void doComputeTasks(
107 @NotNull ReceiverValue receiver,
108 @NotNull TaskPrioritizerContext<D, F> c
109 ) {
110 ProgressIndicatorProvider.checkCanceled();
111
112 boolean resolveInvoke = c.context.call.getDispatchReceiver().exists();
113 if (resolveInvoke) {
114 addCandidatesForInvoke(receiver, c);
115 return;
116 }
117 Collection<ReceiverValue> implicitReceivers = Sets.newLinkedHashSet(JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope));
118 if (receiver.exists()) {
119 addCandidatesForExplicitReceiver(receiver, implicitReceivers, c, /*isExplicit=*/true);
120 return;
121 }
122 addCandidatesForNoReceiver(implicitReceivers, c);
123 }
124
125 private static <D extends CallableDescriptor, F extends D> void addCandidatesForExplicitReceiver(
126 @NotNull ReceiverValue explicitReceiver,
127 @NotNull Collection<ReceiverValue> implicitReceivers,
128 @NotNull TaskPrioritizerContext<D, F> c,
129 boolean isExplicit
130 ) {
131
132 List<JetType> variantsForExplicitReceiver = SmartCastUtils.getSmartCastVariants(explicitReceiver, c.context);
133
134 //members
135 for (CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
136 Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
137 for (JetType type : variantsForExplicitReceiver) {
138 Collection<D> membersForThisVariant =
139 callableDescriptorCollector.getMembersByName(type, c.name, c.context.trace);
140 convertWithReceivers(membersForThisVariant, explicitReceiver,
141 NO_RECEIVER, members, createKind(DISPATCH_RECEIVER, isExplicit), c.context.call);
142 }
143 c.result.addCandidates(members);
144 }
145
146 for (CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
147 //member extensions
148 for (ReceiverValue implicitReceiver : implicitReceivers) {
149 addMemberExtensionCandidates(implicitReceiver, explicitReceiver,
150 callableDescriptorCollector, c, createKind(EXTENSION_RECEIVER, isExplicit));
151 }
152 //extensions
153 Collection<ResolutionCandidate<D>> extensions = convertWithImpliedThis(
154 c.scope, explicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace),
155 createKind(EXTENSION_RECEIVER, isExplicit), c.context.call);
156 c.result.addCandidates(extensions);
157 }
158 }
159
160 private static ExplicitReceiverKind createKind(ExplicitReceiverKind kind, boolean isExplicit) {
161 if (isExplicit) return kind;
162 return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER;
163 }
164
165 private static <D extends CallableDescriptor, F extends D> void addMemberExtensionCandidates(
166 @NotNull ReceiverValue dispatchReceiver,
167 @NotNull ReceiverValue receiverParameter,
168 @NotNull CallableDescriptorCollector<D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c,
169 @NotNull ExplicitReceiverKind receiverKind
170 ) {
171 Collection<D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
172 dispatchReceiver.getType().getMemberScope(), c.name, c.context.trace);
173 c.result.addCandidates(convertWithReceivers(
174 memberExtensions, dispatchReceiver, receiverParameter, receiverKind, c.context.call));
175 }
176
177 private static <D extends CallableDescriptor, F extends D> void addCandidatesForNoReceiver(
178 @NotNull Collection<ReceiverValue> implicitReceivers,
179 @NotNull TaskPrioritizerContext<D, F> c
180 ) {
181 List<Collection<ResolutionCandidate<D>>> localsList = Lists.newArrayList();
182 List<Collection<ResolutionCandidate<D>>> nonlocalsList = Lists.newArrayList();
183 for (CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
184
185 Collection<ResolutionCandidate<D>> members = convertWithImpliedThisAndNoReceiver(
186 c.scope, callableDescriptorCollector.getNonExtensionsByName(c.scope, c.name, c.context.trace), c.context.call);
187
188 List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList();
189 List<ResolutionCandidate<D>> locals = Lists.newArrayList();
190 //noinspection unchecked,RedundantTypeArguments
191 TaskPrioritizer.<D>splitLexicallyLocalDescriptors(members, c.scope.getContainingDeclaration(), locals, nonlocals);
192
193 localsList.add(locals);
194 nonlocalsList.add(nonlocals);
195 }
196
197 //locals
198 c.result.addCandidates(localsList);
199
200 //try all implicit receivers as explicit
201 for (ReceiverValue implicitReceiver : implicitReceivers) {
202 addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*isExplicit=*/false);
203 }
204
205 //nonlocals
206 c.result.addCandidates(nonlocalsList);
207 }
208
209 private static <D extends CallableDescriptor, F extends D> void addCandidatesForInvoke(
210 @NotNull ReceiverValue explicitReceiver,
211 @NotNull TaskPrioritizerContext<D, F> c
212 ) {
213 List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope);
214
215 // For 'a.foo()' where foo has function type,
216 // a is explicitReceiver, foo is variableReceiver.
217 ReceiverValue variableReceiver = c.context.call.getDispatchReceiver();
218 assert variableReceiver.exists() : "'Invoke' call hasn't got variable receiver";
219
220 // For invocation a.foo() explicit receiver 'a'
221 // can be a receiver for 'foo' variable
222 // or for 'invoke' function.
223
224 // (1) a.foo + foo.invoke()
225 if (!explicitReceiver.exists()) {
226 addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*isExplicit=*/true);
227 }
228
229 // (2) foo + a.invoke()
230
231 // 'invoke' is member extension to explicit receiver while variable receiver is 'this object'
232 //trait A
233 //trait Foo { fun A.invoke() }
234
235 if (explicitReceiver.exists()) {
236 //a.foo()
237 addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c, BOTH_RECEIVERS);
238 return;
239 }
240 // with (a) { foo() }
241 for (ReceiverValue implicitReceiver : implicitReceivers) {
242 addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c, DISPATCH_RECEIVER);
243 }
244 }
245
246 private static <D extends CallableDescriptor, F extends D> void addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(
247 @NotNull ReceiverValue dispatchReceiver,
248 @NotNull ReceiverValue receiverParameter,
249 @NotNull TaskPrioritizerContext<D, F> c,
250 @NotNull ExplicitReceiverKind receiverKind
251 ) {
252 for (CallableDescriptorCollector<D> callableDescriptorCollector : c.callableDescriptorCollectors) {
253 addMemberExtensionCandidates(dispatchReceiver, receiverParameter, callableDescriptorCollector, c, receiverKind);
254 }
255 }
256
257 private static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithReceivers(
258 @NotNull Collection<D> descriptors,
259 @NotNull ReceiverValue dispatchReceiver,
260 @NotNull ReceiverValue extensionReceiver,
261 @NotNull ExplicitReceiverKind explicitReceiverKind,
262 @NotNull Call call
263 ) {
264 Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
265 convertWithReceivers(descriptors, dispatchReceiver, extensionReceiver, result, explicitReceiverKind, call);
266 return result;
267 }
268
269 private static <D extends CallableDescriptor> void convertWithReceivers(
270 @NotNull Collection<D> descriptors,
271 @NotNull ReceiverValue dispatchReceiver,
272 @NotNull ReceiverValue extensionReceiver,
273 @NotNull Collection<ResolutionCandidate<D>> result,
274 @NotNull ExplicitReceiverKind explicitReceiverKind,
275 @NotNull Call call
276 ) {
277 for (D descriptor : descriptors) {
278 ResolutionCandidate<D> candidate = ResolutionCandidate.create(call, descriptor);
279 candidate.setDispatchReceiver(dispatchReceiver);
280 candidate.setExtensionReceiver(extensionReceiver);
281 candidate.setExplicitReceiverKind(explicitReceiverKind);
282 result.add(candidate);
283 }
284 }
285
286 public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThisAndNoReceiver(
287 @NotNull JetScope scope,
288 @NotNull Collection<? extends D> descriptors,
289 @NotNull Call call
290 ) {
291 return convertWithImpliedThis(scope, NO_RECEIVER, descriptors, NO_EXPLICIT_RECEIVER, call);
292 }
293
294 public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThis(
295 @NotNull JetScope scope,
296 @NotNull ReceiverValue receiverParameter,
297 @NotNull Collection<? extends D> descriptors,
298 @NotNull ExplicitReceiverKind receiverKind,
299 @NotNull Call call
300 ) {
301 Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
302 for (D descriptor : descriptors) {
303 ResolutionCandidate<D> candidate = ResolutionCandidate.create(call, descriptor);
304 candidate.setExtensionReceiver(receiverParameter);
305 candidate.setExplicitReceiverKind(receiverKind);
306 if (setImpliedThis(scope, candidate)) {
307 result.add(candidate);
308 }
309 }
310 return result;
311 }
312
313 private static <D extends CallableDescriptor> boolean setImpliedThis(
314 @NotNull JetScope scope,
315 @NotNull ResolutionCandidate<D> candidate
316 ) {
317 ReceiverParameterDescriptor dispatchReceiver = candidate.getDescriptor().getDispatchReceiverParameter();
318 if (dispatchReceiver == null) return true;
319 List<ReceiverParameterDescriptor> receivers = scope.getImplicitReceiversHierarchy();
320 for (ReceiverParameterDescriptor receiver : receivers) {
321 if (JetTypeChecker.DEFAULT.isSubtypeOf(receiver.getType(), dispatchReceiver.getType())) {
322 // TODO : Smartcasts & nullability
323 candidate.setDispatchReceiver(dispatchReceiver.getValue());
324 return true;
325 }
326 }
327 return false;
328 }
329
330 public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasksFromCandidates(
331 @NotNull BasicCallResolutionContext context,
332 @NotNull Collection<ResolutionCandidate<D>> candidates,
333 @NotNull TracingStrategy tracing
334 ) {
335 ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(
336 context, new MyPriorityProvider<D>(context), tracing);
337 result.addCandidates(candidates);
338 return result.getTasks();
339 }
340
341 private static class MyPriorityProvider<D extends CallableDescriptor>
342 implements ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>> {
343 private final BasicCallResolutionContext context;
344
345 public MyPriorityProvider(BasicCallResolutionContext context) {
346 this.context = context;
347 }
348
349 @Override
350 public int getPriority(ResolutionCandidate<D> call) {
351 return (isVisible(call) ? 2 : 0) + (isSynthesized(call) ? 0 : 1);
352 }
353
354 @Override
355 public int getMaxPriority() {
356 return 3;
357 }
358
359 private boolean isVisible(ResolutionCandidate<D> call) {
360 if (call == null) return false;
361 D candidateDescriptor = call.getDescriptor();
362 if (ErrorUtils.isError(candidateDescriptor)) return true;
363 return Visibilities.isVisible(candidateDescriptor, context.scope.getContainingDeclaration());
364 }
365
366 private boolean isSynthesized(ResolutionCandidate<D> call) {
367 D descriptor = call.getDescriptor();
368 return descriptor instanceof CallableMemberDescriptor &&
369 isOrOverridesSynthesized((CallableMemberDescriptor) descriptor);
370 }
371 }
372
373 private static class TaskPrioritizerContext<D extends CallableDescriptor, F extends D> {
374 @NotNull public final Name name;
375 @NotNull public final ResolutionTaskHolder<D, F> result;
376 @NotNull public final BasicCallResolutionContext context;
377 @NotNull public final JetScope scope;
378 @NotNull public final CallableDescriptorCollectors<D> callableDescriptorCollectors;
379
380 private TaskPrioritizerContext(
381 @NotNull Name name,
382 @NotNull ResolutionTaskHolder<D, F> result,
383 @NotNull BasicCallResolutionContext context,
384 @NotNull JetScope scope,
385 @NotNull CallableDescriptorCollectors<D> callableDescriptorCollectors
386 ) {
387 this.name = name;
388 this.result = result;
389 this.context = context;
390 this.scope = scope;
391 this.callableDescriptorCollectors = callableDescriptorCollectors;
392 }
393
394 private TaskPrioritizerContext<D, F> replaceScope(JetScope newScope) {
395 return new TaskPrioritizerContext<D, F>(name, result, context, newScope, callableDescriptorCollectors);
396 }
397 }
398 }