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