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    }