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