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