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.AutoCastUtils;
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.PackageType;
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.calls.CallResolverUtil.isOrOverridesSynthesized;
047    import static org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind.*;
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 PackageType) {
091                JetType receiverType = explicitReceiver.getType();
092                variants.add(Pair.create(receiverType.getMemberScope(), NO_RECEIVER));
093                ReceiverValue value = ((PackageType) 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, /*isExplicit=*/true);
125                return;
126            }
127            addCandidatesForNoReceiver(implicitReceivers, c);
128        }
129    
130        private static <D extends CallableDescriptor, F extends D> void addCandidatesForExplicitReceiver(
131                @NotNull ReceiverValue explicitReceiver,
132                @NotNull List<ReceiverValue> implicitReceivers,
133                @NotNull TaskPrioritizerContext<D, F> c,
134                boolean isExplicit
135        ) {
136    
137            List<JetType> variantsForExplicitReceiver = AutoCastUtils.getAutoCastVariants(explicitReceiver, c.context);
138    
139            //members
140            for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
141                Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
142                for (JetType type : variantsForExplicitReceiver) {
143                    Collection<? extends D> membersForThisVariant =
144                            callableDescriptorCollector.getMembersByName(type, c.name, c.context.trace);
145                    convertWithReceivers(membersForThisVariant, explicitReceiver,
146                                         NO_RECEIVER, members, createKind(THIS_OBJECT, isExplicit));
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, explicitReceiver,
155                                                 callableDescriptorCollector, c, createKind(RECEIVER_ARGUMENT, isExplicit));
156                }
157                //extensions
158                Collection<ResolutionCandidate<D>> extensions = convertWithImpliedThis(
159                        c.scope, explicitReceiver, callableDescriptorCollector.getNonMembersByName(c.scope, c.name, c.context.trace),
160                        createKind(RECEIVER_ARGUMENT, isExplicit));
161                c.result.addCandidates(extensions);
162            }
163        }
164    
165        private static ExplicitReceiverKind createKind(ExplicitReceiverKind kind, boolean isExplicit) {
166            if (isExplicit) return kind;
167            return ExplicitReceiverKind.NO_EXPLICIT_RECEIVER;
168        }
169    
170        private static <D extends CallableDescriptor, F extends D> void addMemberExtensionCandidates(
171                @NotNull ReceiverValue thisObject,
172                @NotNull ReceiverValue receiverParameter,
173                @NotNull CallableDescriptorCollector<? extends D> callableDescriptorCollector, TaskPrioritizerContext<D, F> c,
174                @NotNull ExplicitReceiverKind receiverKind
175        ) {
176            Collection<? extends D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
177                    thisObject.getType().getMemberScope(), c.name, c.context.trace);
178            c.result.addCandidates(convertWithReceivers(
179                    memberExtensions, thisObject, receiverParameter, receiverKind));
180        }
181    
182        private static <D extends CallableDescriptor, F extends D> void addCandidatesForNoReceiver(
183                @NotNull List<ReceiverValue> implicitReceivers,
184                @NotNull TaskPrioritizerContext<D, F> c
185        ) {
186            List<Collection<ResolutionCandidate<D>>> localsList = Lists.newArrayList();
187            List<Collection<ResolutionCandidate<D>>> nonlocalsList = Lists.newArrayList();
188            for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
189    
190                Collection<ResolutionCandidate<D>> members = convertWithImpliedThisAndNoReceiver(
191                        c.scope, callableDescriptorCollector.getNonExtensionsByName(c.scope, c.name, c.context.trace));
192    
193                List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList();
194                List<ResolutionCandidate<D>> locals = Lists.newArrayList();
195                //noinspection unchecked,RedundantTypeArguments
196                TaskPrioritizer.<D>splitLexicallyLocalDescriptors(members, c.scope.getContainingDeclaration(), locals, nonlocals);
197    
198                localsList.add(locals);
199                nonlocalsList.add(nonlocals);
200            }
201    
202            //locals
203            c.result.addCandidates(localsList);
204    
205            //try all implicit receivers as explicit
206            for (ReceiverValue implicitReceiver : implicitReceivers) {
207                addCandidatesForExplicitReceiver(implicitReceiver, implicitReceivers, c, /*isExplicit=*/false);
208            }
209    
210            //nonlocals
211            c.result.addCandidates(nonlocalsList);
212        }
213    
214        private static <D extends CallableDescriptor, F extends D> void addCandidatesForInvoke(
215                @NotNull ReceiverValue explicitReceiver,
216                @NotNull TaskPrioritizerContext<D, F> c
217        ) {
218            List<ReceiverValue> implicitReceivers = JetScopeUtils.getImplicitReceiversHierarchyValues(c.scope);
219    
220            // For 'a.foo()' where foo has function type,
221            // a is explicitReceiver, foo is variableReceiver.
222            ReceiverValue variableReceiver = c.context.call.getThisObject();
223            assert variableReceiver.exists() : "'Invoke' call hasn't got variable receiver";
224    
225            // For invocation a.foo() explicit receiver 'a'
226            // can be a receiver for 'foo' variable
227            // or for 'invoke' function.
228    
229            // (1) a.foo + foo.invoke()
230            if (!explicitReceiver.exists()) {
231                addCandidatesForExplicitReceiver(variableReceiver, implicitReceivers, c, /*isExplicit=*/true);
232            }
233    
234            // (2) foo + a.invoke()
235    
236            // 'invoke' is member extension to explicit receiver while variable receiver is 'this object'
237            //trait A
238            //trait Foo { fun A.invoke() }
239    
240            if (explicitReceiver.exists()) {
241                //a.foo()
242                addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver, explicitReceiver, c, BOTH_RECEIVERS);
243                return;
244            }
245            // with (a) { foo() }
246            for (ReceiverValue implicitReceiver : implicitReceivers) {
247                addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(variableReceiver, implicitReceiver, c, THIS_OBJECT);
248            }
249        }
250    
251        private static <D extends CallableDescriptor, F extends D> void addCandidatesWhenInvokeIsMemberAndExtensionToExplicitReceiver(
252                @NotNull ReceiverValue thisObject,
253                @NotNull ReceiverValue receiverParameter,
254                @NotNull TaskPrioritizerContext<D, F> c,
255                @NotNull ExplicitReceiverKind receiverKind
256        ) {
257            for (CallableDescriptorCollector<? extends D> callableDescriptorCollector : c.callableDescriptorCollectors) {
258                addMemberExtensionCandidates(thisObject, receiverParameter, callableDescriptorCollector, c, receiverKind);
259            }
260        }
261    
262        private static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithReceivers(
263                @NotNull Collection<? extends D> descriptors,
264                @NotNull ReceiverValue thisObject,
265                @NotNull ReceiverValue receiverParameter,
266                @NotNull ExplicitReceiverKind explicitReceiverKind
267        ) {
268            Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
269            convertWithReceivers(descriptors, thisObject, receiverParameter, result, explicitReceiverKind);
270            return result;
271        }
272    
273        private static <D extends CallableDescriptor> void convertWithReceivers(
274                @NotNull Collection<? extends D> descriptors,
275                @NotNull ReceiverValue thisObject,
276                @NotNull ReceiverValue receiverParameter,
277                @NotNull Collection<ResolutionCandidate<D>> result,
278                @NotNull ExplicitReceiverKind explicitReceiverKind
279        ) {
280            for (D extension : descriptors) {
281                if (DescriptorUtils.isConstructorOfStaticNestedClass(extension)) {
282                    // We don't want static nested classes' constructors to be resolved with expectedThisObject
283                    continue;
284                }
285                ResolutionCandidate<D> candidate = ResolutionCandidate.create(extension);
286                candidate.setThisObject(thisObject);
287                candidate.setReceiverArgument(receiverParameter);
288                candidate.setExplicitReceiverKind(explicitReceiverKind);
289                result.add(candidate);
290            }
291        }
292    
293        public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThisAndNoReceiver(
294                @NotNull JetScope scope,
295                @NotNull Collection<? extends D> descriptors
296        ) {
297            return convertWithImpliedThis(scope, NO_RECEIVER, descriptors, NO_EXPLICIT_RECEIVER);
298        }
299    
300        public static <D extends CallableDescriptor> Collection<ResolutionCandidate<D>> convertWithImpliedThis(
301                @NotNull JetScope scope,
302                @NotNull ReceiverValue receiverParameter,
303                @NotNull Collection<? extends D> descriptors,
304                ExplicitReceiverKind receiverKind
305        ) {
306            Collection<ResolutionCandidate<D>> result = Lists.newArrayList();
307            for (D descriptor : descriptors) {
308                ResolutionCandidate<D> candidate = ResolutionCandidate.create(descriptor);
309                candidate.setReceiverArgument(receiverParameter);
310                candidate.setExplicitReceiverKind(receiverKind);
311                if (setImpliedThis(scope, candidate)) {
312                    result.add(candidate);
313                }
314            }
315            return result;
316        }
317    
318        private static <D extends CallableDescriptor> boolean setImpliedThis(
319                @NotNull JetScope scope,
320                @NotNull ResolutionCandidate<D> candidate
321        ) {
322            ReceiverParameterDescriptor expectedThisObject = candidate.getDescriptor().getExpectedThisObject();
323            if (expectedThisObject == null) return true;
324            List<ReceiverParameterDescriptor> receivers = scope.getImplicitReceiversHierarchy();
325            for (ReceiverParameterDescriptor receiver : receivers) {
326                if (JetTypeChecker.INSTANCE.isSubtypeOf(receiver.getType(), expectedThisObject.getType())) {
327                    // TODO : Autocasts & nullability
328                    candidate.setThisObject(expectedThisObject.getValue());
329                    return true;
330                }
331            }
332            return false;
333        }
334    
335        public static <D extends CallableDescriptor, F extends D> List<ResolutionTask<D, F>> computePrioritizedTasksFromCandidates(
336                @NotNull BasicCallResolutionContext context,
337                @NotNull JetReferenceExpression functionReference,
338                @NotNull Collection<ResolutionCandidate<D>> candidates,
339                @Nullable TracingStrategy tracing
340        ) {
341            ResolutionTaskHolder<D, F> result = new ResolutionTaskHolder<D, F>(
342                    functionReference, context, new MyPriorityProvider<D>(context), tracing);
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    
386            private TaskPrioritizerContext(
387                    @NotNull Name name,
388                    @NotNull ResolutionTaskHolder<D, F> result,
389                    @NotNull BasicCallResolutionContext context,
390                    @NotNull JetScope scope,
391                    @NotNull List<CallableDescriptorCollector<? extends D>> callableDescriptorCollectors
392            ) {
393                this.name = name;
394                this.result = result;
395                this.context = context;
396                this.scope = scope;
397                this.callableDescriptorCollectors = callableDescriptorCollectors;
398            }
399        }
400    }