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.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.JetType;
038 import org.jetbrains.jet.lang.types.NamespaceType;
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.DescriptorUtils.isClassObject;
047 import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.isOrOverridesSynthesized;
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 NamespaceType) {
091 JetType receiverType = explicitReceiver.getType();
092 variants.add(Pair.create(receiverType.getMemberScope(), NO_RECEIVER));
093 ReceiverValue value = ((NamespaceType) 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, /*resolveInvoke=*/false);
125 return;
126 }
127 addCandidatesForNoReceiver(implicitReceivers, c);
128 }
129
130 private static <D extends CallableDescriptor, F extends D> void addCandidatesForExplicitReceiver(
131 @NotNull ReceiverValue receiver,
132 @NotNull List<ReceiverValue> implicitReceivers,
133 @NotNull TaskPrioritizerContext<D, F> c,
134 boolean resolveInvoke
135 ) {
136
137 List<ReceiverValue> variantsForExplicitReceiver = c.autoCastService.getVariantsForReceiver(receiver);
138
139 //members
140 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
141 Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
142 for (ReceiverValue variant : variantsForExplicitReceiver) {
143 Collection<? extends D> membersForThisVariant =
144 callableDescriptorCollector.getMembersByName(variant.getType(), c.name, c.context.trace);
145 convertWithReceivers(membersForThisVariant, Collections.singletonList(variant),
146 Collections.singletonList(NO_RECEIVER), members, resolveInvoke);
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, variantsForExplicitReceiver,
155 callableDescriptorCollector, c, resolveInvoke);
156 }
157 //extensions
158 Collection<ResolutionCandidate<D>> extensions = convertWithImpliedThis(
159 c.scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace));
160 c.result.addCandidates(extensions);
161 }
162 }
163
164 private static <D extends CallableDescriptor, F extends D> void addMemberExtensionCandidates(
165 @NotNull ReceiverValue implicitReceiver,
166 @NotNull List<ReceiverValue> variantsForExplicitReceiver,
167 @NotNull CallableDescriptorCollector<? extends D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c,
168 boolean resolveInvoke
169 ) {
170 Collection<? extends D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
171 implicitReceiver.getType().getMemberScope(), c.name, c.context.trace);
172 List<ReceiverValue> variantsForImplicitReceiver = c.autoCastService.getVariantsForReceiver(implicitReceiver);
173 c.result.addCandidates(convertWithReceivers(memberExtensions, variantsForImplicitReceiver,
174 variantsForExplicitReceiver, resolveInvoke));
175 }
176
177 private static <D extends CallableDescriptor, F extends D> void addCandidatesForNoReceiver(
178 @NotNull List<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<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
184
185 Collection<ResolutionCandidate<D>> members =
186 convertWithImpliedThis(c.scope, Collections.singletonList(NO_RECEIVER), callableDescriptorCollector
187 .getNonExtensionsByName(c.scope, c.name, c.context.trace));
188
189 List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList();
190 List<ResolutionCandidate<D>> locals = Lists.newArrayList();
191 //noinspection unchecked,RedundantTypeArguments
192 TaskPrioritizer.<D>splitLexicallyLocalDescriptors(members, c.scope.getContainingDeclaration(), locals, nonlocals);
193
194 localsList.add(locals);
195 nonlocalsList.add(nonlocals);
196 }
197
198 //locals
199 c.result.addCandidates(localsList);
200
201 //try all implicit receivers as explicit
202 for (ReceiverValue implicitReceiver : implicitReceivers) {
203 addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*resolveInvoke=*/false);
204 }
205
206 //nonlocals
207 c.result.addCandidates(nonlocalsList);
208 }
209
210 private static <D extends CallableDescriptor, F extends D> void addCandidatesForInvoke(
211 @NotNull ReceiverValue explicitReceiver,
212 @NotNull TaskPrioritizerContext<D, F> c
213 ) {
214 List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope);
215
216 // For 'a.foo()' where foo has function type,
217 // a is explicitReceiver, foo is variableReceiver.
218 ReceiverValue variableReceiver = c.context.call.getThisObject();
219 assert variableReceiver.exists() : "'Invoke' call hasn't got variable receiver";
220
221 // For invocation a.foo() explicit receiver 'a'
222 // can be a receiver for 'foo' variable
223 // or for 'invoke' function.
224
225 // (1) a.foo + foo.invoke()
226 if (!explicitReceiver.exists()) {
227 addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*resolveInvoke=*/true);
228 }
229
230 // (2) foo + a.invoke()
231
232 // 'invoke' is member extension to explicit receiver while variable receiver is 'this object'
233 //trait A
234 //trait Foo { fun A.invoke() }
235
236 if (explicitReceiver.exists()) {
237 //a.foo()
238 addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c);
239 return;
240 }
241 // with (a) { foo() }
242 for (ReceiverValue implicitReceiver : implicitReceivers) {
243 addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c);
244 }
245 }
246
247 private static <D extends CallableDescriptor, F extends D> void addCandidatesWhenInvokeIsMemberExtensionToExplicitReceiver(
248 @NotNull ReceiverValue variableReceiver,
249 @NotNull ReceiverValue explicitReceiver,
250 @NotNull TaskPrioritizerContext<D, F> c
251 ) {
252 List<ReceiverValue> variantsForExplicitReceiver = c.autoCastService.getVariantsForReceiver(explicitReceiver);
253
254 for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
255 addMemberExtensionCandidates(variableReceiver, variantsForExplicitReceiver, callableDescriptorCollector, c, /*resolveInvoke=*/true);
256 }
257 }
258
259 private static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithReceivers(
260 @NotNull Collection<? extends D> descriptors,
261 @NotNull Iterable<ReceiverValue> thisObjects,
262 @NotNull Iterable<ReceiverValue> receiverParameters,
263 boolean hasExplicitThisObject
264 ) {
265 Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
266 convertWithReceivers(descriptors, thisObjects, receiverParameters, result, hasExplicitThisObject);
267 return result;
268 }
269
270 private static <D extends CallableDescriptor> void convertWithReceivers(
271 @NotNull Collection<? extends D> descriptors,
272 @NotNull Iterable<ReceiverValue> thisObjects,
273 @NotNull Iterable<ReceiverValue> receiverParameters,
274 @NotNull Collection<ResolutionCandidate<D>> result,
275 boolean hasExplicitThisObject
276 ) {
277 for (ReceiverValue thisObject : thisObjects) {
278 for (ReceiverValue receiverParameter : receiverParameters) {
279 for (D extension : descriptors) {
280 if (DescriptorUtils.isConstructorOfStaticNestedClass(extension)) {
281 // We don't want static nested classes' constructors to be resolved with expectedThisObject
282 continue;
283 }
284 ResolutionCandidate<D> candidate = ResolutionCandidate.create(extension);
285 candidate.setThisObject(thisObject);
286 candidate.setReceiverArgument(receiverParameter);
287 candidate.setExplicitReceiverKind(
288 hasExplicitThisObject ? ExplicitReceiverKind.BOTH_RECEIVERS : ExplicitReceiverKind.THIS_OBJECT);
289 result.add(candidate);
290 }
291 }
292 }
293 }
294
295 public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThis(
296 @NotNull JetScope scope,
297 @NotNull Collection<ReceiverValue> receiverParameters,
298 @NotNull Collection<? extends D> descriptors
299 ) {
300 Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
301 for (ReceiverValue receiverParameter : receiverParameters) {
302 for (D descriptor : descriptors) {
303 ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor);
304 candidate.setReceiverArgument(receiverParameter);
305 candidate.setExplicitReceiverKind(
306 receiverParameter.exists() ? ExplicitReceiverKind.RECEIVER_ARGUMENT : ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
307 if (setImpliedThis(scope, candidate)) {
308 result.add(candidate);
309 }
310 }
311 }
312 if (receiverParameters.size() == 1 && !receiverParameters.iterator().next().exists()) {
313 for (D descriptor : descriptors) {
314 if (descriptor.getExpectedThisObject() != null && descriptor.getReceiverParameter() == null) {
315 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
316 if (descriptor instanceof ConstructorDescriptor) {
317 containingDeclaration = containingDeclaration.getContainingDeclaration();
318 }
319 if (containingDeclaration != null && isClassObject(containingDeclaration)) {
320 ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor);
321 candidate.setThisObject(((ClassDescriptor) containingDeclaration).getThisAsReceiverParameter().getValue());
322 candidate.setExplicitReceiverKind(ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
323 result.add(candidate);
324 }
325 }
326 }
327 }
328 return result;
329 }
330
331 private static <D extends CallableDescriptor> boolean setImpliedThis(
332 @NotNull JetScope scope,
333 @NotNull ResolutionCandidate<D> candidate
334 ) {
335 ReceiverParameterDescriptor expectedThisObject = candidate.getDescriptor().getExpectedThisObject();
336 if (expectedThisObject == null) return true;
337 List<ReceiverParameterDescriptor> receivers = scope.getImplicitReceiversHierarchy();
338 for (ReceiverParameterDescriptor receiver : receivers) {
339 if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) {
340 // TODO : Autocasts & nullability
341 candidate.setThisObject(expectedThisObject.getValue());
342 return true;
343 }
344 }
345 return false;
346 }
347
348 public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasksFromCandidates(
349 @NotNull BasicCallResolutionContext context,
350 @NotNull JetReferenceExpression functionReference,
351 @NotNull Collection<ResolutionCandidate<D>> candidates,
352 @Nullable TracingStrategy tracing
353 ) {
354 ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(
355 functionReference, context, new MyPriorityProvider<D>(context), tracing);
356 result.addCandidates(candidates);
357 return result.getTasks();
358 }
359
360 private static class MyPriorityProvider<D extends CallableDescriptor>
361 implements ResolutionTaskHolder.PriorityProvider<ResolutionCandidate<D>> {
362 private final BasicCallResolutionContext context;
363
364 public MyPriorityProvider(BasicCallResolutionContext context) {
365 this.context = context;
366 }
367
368 @Override
369 public int getPriority(ResolutionCandidate<D> call) {
370 return (isVisible(call) ? 2 : 0) + (isSynthesized(call) ? 0 : 1);
371 }
372
373 @Override
374 public int getMaxPriority() {
375 return 3;
376 }
377
378 private boolean isVisible(ResolutionCandidate<D> call) {
379 if (call == null) return false;
380 D candidateDescriptor = call.getDescriptor();
381 if (ErrorUtils.isError(candidateDescriptor)) return true;
382 return Visibilities.isVisible(candidateDescriptor, context.scope.getContainingDeclaration());
383 }
384
385 private boolean isSynthesized(ResolutionCandidate<D> call) {
386 D descriptor = call.getDescriptor();
387 return descriptor instanceof CallableMemberDescriptor &&
388 isOrOverridesSynthesized((CallableMemberDescriptor) descriptor);
389 }
390 }
391
392 private static class TaskPrioritizerContext<D extends CallableDescriptor, F extends D> {
393 @NotNull public final Name name;
394 @NotNull public final ResolutionTaskHolder<D, F> result;
395 @NotNull public final BasicCallResolutionContext context;
396 @NotNull public final JetScope scope;
397 @NotNull public final List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors;
398 @NotNull AutoCastServiceImpl autoCastService;
399
400 private TaskPrioritizerContext(
401 @NotNull Name name,
402 @NotNull ResolutionTaskHolder<D, F> result,
403 @NotNull BasicCallResolutionContext context,
404 @NotNull JetScope scope,
405 @NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors
406 ) {
407 this.name = name;
408 this.result = result;
409 this.context = context;
410 this.scope = scope;
411 this.callableDescriptorCollectors = callableDescriptorCollectors;
412 autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext());
413 }
414 }
415 }