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    }