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