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