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    }