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;
018    
019    import com.intellij.lang.ASTNode;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.psi.*;
024    import org.jetbrains.jet.lang.resolve.BindingContext;
025    import org.jetbrains.jet.lang.resolve.BindingTrace;
026    import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
027    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
028    import org.jetbrains.jet.lang.resolve.calls.context.*;
029    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
030    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
031    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
032    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
033    import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
034    import org.jetbrains.jet.lang.resolve.constants.ConstantUtils;
035    import org.jetbrains.jet.lang.resolve.name.Name;
036    import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
037    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038    import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl;
039    import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
040    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
041    import org.jetbrains.jet.lang.types.*;
042    import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
043    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
044    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
045    import org.jetbrains.jet.lexer.JetTokens;
046    
047    import javax.inject.Inject;
048    import java.util.ArrayList;
049    import java.util.Collections;
050    import java.util.List;
051    
052    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
053    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
054    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
055    import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
056    
057    public class CallExpressionResolver {
058        @NotNull
059        private ExpressionTypingServices expressionTypingServices;
060    
061        @Inject
062        public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
063            this.expressionTypingServices = expressionTypingServices;
064        }
065    
066        @Nullable
067        private JetType lookupNamespaceOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) {
068            Name referencedName = expression.getReferencedNameAsName();
069            final ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
070            if (classifier != null) {
071                JetType classObjectType = classifier.getClassObjectType();
072                if (classObjectType != null) {
073                    context.trace.record(REFERENCE_TARGET, expression, classifier);
074                    JetType result = getExtendedClassObjectType(classObjectType, referencedName, classifier, context);
075                    return DataFlowUtils.checkType(result, expression, context);
076                }
077            }
078            JetType[] result = new JetType[1];
079            TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
080                    context.trace, "trace for namespace/class object lookup of name", referencedName);
081            if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
082                temporaryTrace.commit();
083                return DataFlowUtils.checkType(result[0], expression, context);
084            }
085            // To report NO_CLASS_OBJECT when no namespace found
086            if (classifier != null) {
087                if (classifier instanceof TypeParameterDescriptor) {
088                    if (context.expressionPosition == ExpressionPosition.FREE) {
089                        context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, (TypeParameterDescriptor) classifier));
090                    }
091                    else {
092                        context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, (TypeParameterDescriptor) classifier));
093                    }
094                }
095                else if (context.expressionPosition == ExpressionPosition.FREE) {
096                    context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
097                }
098                context.trace.record(REFERENCE_TARGET, expression, classifier);
099                JetScope scopeForStaticMembersResolution =
100                        classifier instanceof ClassDescriptor
101                        ? getStaticNestedClassesScope((ClassDescriptor) classifier)
102                        : new JetScopeImpl() {
103                                @NotNull
104                                @Override
105                                public DeclarationDescriptor getContainingDeclaration() {
106                                    return classifier;
107                                }
108    
109                                @Override
110                                public String toString() {
111                                    return "Scope for the type parameter on the left hand side of dot";
112                                }
113                            };
114                return new NamespaceType(referencedName, scopeForStaticMembersResolution);
115            }
116            temporaryTrace.commit();
117            return result[0];
118        }
119    
120        @NotNull
121        private JetType getExtendedClassObjectType(
122                @NotNull JetType classObjectType,
123                @NotNull Name referencedName,
124                @NotNull ClassifierDescriptor classifier,
125                @NotNull ResolutionContext context
126        ) {
127            if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT && classifier instanceof ClassDescriptor) {
128                List<JetScope> scopes = new ArrayList<JetScope>(3);
129    
130                scopes.add(classObjectType.getMemberScope());
131                scopes.add(getStaticNestedClassesScope((ClassDescriptor) classifier));
132    
133                NamespaceDescriptor namespace = context.scope.getNamespace(referencedName);
134                if (namespace != null) {
135                    //for enums loaded from java binaries
136                    scopes.add(namespace.getMemberScope());
137                }
138    
139                JetScope scope = new ChainedScope(classifier, scopes.toArray(new JetScope[scopes.size()]));
140                return new NamespaceType(referencedName, scope);
141            }
142            return classObjectType;
143        }
144    
145        private boolean furtherNameLookup(
146                @NotNull JetSimpleNameExpression expression,
147                @NotNull JetType[] result,
148                @NotNull ResolutionContext context
149        ) {
150            NamespaceType namespaceType = lookupNamespaceType(expression, context);
151            if (namespaceType == null) {
152                return false;
153            }
154            if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT) {
155                result[0] = namespaceType;
156                return true;
157            }
158            context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression));
159            result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName());
160            return false;
161        }
162    
163        @Nullable
164        private NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) {
165            Name name = expression.getReferencedNameAsName();
166            NamespaceDescriptor namespace = context.scope.getNamespace(name);
167            if (namespace == null) {
168                return null;
169            }
170            context.trace.record(REFERENCE_TARGET, expression, namespace);
171    
172            // Construct a NamespaceType with everything from the namespace and with nested classes of the corresponding class (if any)
173            JetScope scope;
174            ClassifierDescriptor classifier = context.scope.getClassifier(name);
175            if (classifier instanceof ClassDescriptor) {
176                scope = new ChainedScope(namespace, namespace.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier));
177            }
178            else {
179                scope = namespace.getMemberScope();
180            }
181            return new NamespaceType(name, scope);
182        }
183    
184        @Nullable
185        public ResolvedCallWithTrace<FunctionDescriptor> getResolvedCallForFunction(
186                @NotNull Call call, @NotNull JetExpression callExpression,
187                @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode,
188                @NotNull CheckValueArgumentsMode checkArguments, @NotNull ResolutionResultsCache resolutionResultsCache,
189                @NotNull boolean[] result
190        ) {
191            CallResolver callResolver = expressionTypingServices.getCallResolver();
192            OverloadResolutionResultsImpl<FunctionDescriptor> results = callResolver.resolveFunctionCall(
193                    BasicCallResolutionContext.create(context, call, resolveMode, checkArguments, resolutionResultsCache));
194            if (!results.isNothing()) {
195                checkSuper(call.getExplicitReceiver(), results, context.trace, callExpression);
196                result[0] = true;
197                if (results.isSingleResult() && resolveMode == ResolveMode.TOP_LEVEL_CALL) {
198                    if (!CallResolverUtil.hasInferredReturnType(results.getResultingCall())) return null;
199                }
200    
201                return results.isSingleResult() ? results.getResultingCall() : null;
202            }
203            result[0] = false;
204            return null;
205        }
206    
207        @Nullable
208        private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
209                @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull boolean[] result
210        ) {
211            TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(
212                    context.trace, "trace to resolve as local variable or property", nameExpression);
213            CallResolver callResolver = expressionTypingServices.getCallResolver();
214            Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression);
215            OverloadResolutionResults<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty(
216                    BasicCallResolutionContext.create(context.replaceBindingTrace(traceForVariable), call, ResolveMode.TOP_LEVEL_CALL,
217                                                      CheckValueArgumentsMode.ENABLED, ResolutionResultsCache.create()));
218            if (!resolutionResult.isNothing()) {
219                traceForVariable.commit();
220                checkSuper(receiver, resolutionResult, context.trace, nameExpression);
221                result[0] = true;
222                return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
223            }
224    
225            ResolutionContext newContext = receiver.exists()
226                                                 ? context.replaceScope(receiver.getType().getMemberScope())
227                                                 : context;
228            TemporaryBindingTrace traceForNamespaceOrClassObject = TemporaryBindingTrace.create(
229                    context.trace, "trace to resolve as namespace or class object", nameExpression);
230            JetType jetType = lookupNamespaceOrClassObject(nameExpression, newContext.replaceBindingTrace(traceForNamespaceOrClassObject));
231            if (jetType != null) {
232                traceForNamespaceOrClassObject.commit();
233    
234                // Uncommitted changes in temp context
235                context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope);
236                if (context.dataFlowInfo.hasTypeInfoConstraints()) {
237                    context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo);
238                }
239                result[0] = true;
240                return jetType;
241            }
242            result[0] = false;
243            return null;
244        }
245    
246        @NotNull
247        public JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
248                @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context
249        ) {
250            boolean[] result = new boolean[1];
251    
252            TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace, "trace to resolve as variable", nameExpression);
253            JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result);
254            if (result[0]) {
255                traceForVariable.commit();
256                if (type instanceof NamespaceType && context.expressionPosition == ExpressionPosition.FREE) {
257                    type = null;
258                }
259                return JetTypeInfo.create(type, context.dataFlowInfo);
260            }
261    
262            Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
263            TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression);
264            ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
265                    call, nameExpression, context, ResolveMode.TOP_LEVEL_CALL, CheckValueArgumentsMode.ENABLED,
266                    ResolutionResultsCache.create(), result);
267            if (result[0]) {
268                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
269                traceForFunction.commit();
270                boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
271                context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
272                type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
273                return JetTypeInfo.create(type, context.dataFlowInfo);
274            }
275    
276            traceForVariable.commit();
277            return JetTypeInfo.create(null, context.dataFlowInfo);
278        }
279    
280        @NotNull
281        public JetTypeInfo getCallExpressionTypeInfo(
282                @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
283                @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode,
284                @NotNull ResolutionResultsCache resolutionResultsCache
285        ) {
286            JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
287                    callExpression, receiver, callOperationNode, context, resolveMode, resolutionResultsCache);
288            if (resolveMode == ResolveMode.TOP_LEVEL_CALL) {
289                DataFlowUtils.checkType(typeInfo.getType(), callExpression, context, typeInfo.getDataFlowInfo());
290            }
291            return typeInfo;
292        }
293    
294        @NotNull
295        public JetTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
296                @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
297                @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode,
298                @NotNull ResolutionResultsCache resolutionResultsCache
299        ) {
300            boolean[] result = new boolean[1];
301            Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
302    
303            TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function call", callExpression);
304            ResolvedCallWithTrace<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
305                    call, callExpression, context.replaceBindingTrace(traceForFunction), resolveMode, CheckValueArgumentsMode.ENABLED,
306                    resolutionResultsCache, result);
307            if (result[0]) {
308                FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
309                traceForFunction.commit();
310                if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
311                    // there are only type arguments
312                    boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
313                    context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
314                }
315                if (functionDescriptor == null) {
316                    return JetTypeInfo.create(null, context.dataFlowInfo);
317                }
318                JetType type = functionDescriptor.getReturnType();
319    
320                return JetTypeInfo.create(type, resolvedCall.getDataFlowInfo());
321            }
322    
323            JetExpression calleeExpression = callExpression.getCalleeExpression();
324            if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
325                TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(
326                        context.trace, "trace to resolve as variable with 'invoke' call", callExpression);
327                JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode,
328                                               context.replaceBindingTrace(traceForVariable), result);
329                if (result[0]) {
330                    traceForVariable.commit();
331                    context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
332                                                              type != null ? type : ErrorUtils.createErrorType("")));
333                    return JetTypeInfo.create(null, context.dataFlowInfo);
334                }
335            }
336            traceForFunction.commit();
337            return JetTypeInfo.create(null, context.dataFlowInfo);
338        }
339    
340        private void checkSuper(@NotNull ReceiverValue receiverValue, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
341                @NotNull BindingTrace trace, @NotNull JetExpression expression) {
342            if (!results.isSingleResult()) return;
343            if (!(receiverValue instanceof ExpressionReceiver)) return;
344            JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
345            CallableDescriptor descriptor = results.getResultingDescriptor();
346            if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
347                if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
348                    trace.report(ABSTRACT_SUPER_CALL.on(expression));
349                }
350            }
351        }
352    
353        @NotNull
354        private JetTypeInfo getSelectorReturnTypeInfo(
355                @NotNull ReceiverValue receiver,
356                @Nullable ASTNode callOperationNode,
357                @NotNull JetExpression selectorExpression,
358                @NotNull ResolutionContext context,
359                @NotNull ResolveMode resolveMode,
360                @NotNull ResolutionResultsCache resolutionResultsCache
361        ) {
362            if (selectorExpression instanceof JetCallExpression) {
363                return getCallExpressionTypeInfoWithoutFinalTypeCheck((JetCallExpression) selectorExpression, receiver,
364                                                                      callOperationNode, context, resolveMode, resolutionResultsCache);
365            }
366            else if (selectorExpression instanceof JetSimpleNameExpression) {
367                return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
368            }
369            else if (selectorExpression instanceof JetQualifiedExpression) {
370                JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
371                JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression();
372                JetTypeInfo newReceiverTypeInfo = getSelectorReturnTypeInfo(
373                        receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE), resolveMode, resolutionResultsCache);
374                JetType newReceiverType = newReceiverTypeInfo.getType();
375                DataFlowInfo newReceiverDataFlowInfo = newReceiverTypeInfo.getDataFlowInfo();
376                JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression();
377                if (newReceiverType != null && newSelectorExpression != null) {
378                    ExpressionReceiver expressionReceiver = new ExpressionReceiver(newReceiverExpression, newReceiverType);
379                    return getSelectorReturnTypeInfo(
380                            expressionReceiver, qualifiedExpression.getOperationTokenNode(),
381                            newSelectorExpression, context.replaceDataFlowInfo(newReceiverDataFlowInfo), resolveMode, resolutionResultsCache);
382                }
383            }
384            else {
385                context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
386            }
387            return JetTypeInfo.create(null, context.dataFlowInfo);
388        }
389    
390        @NotNull
391        public JetTypeInfo getQualifiedExpressionTypeInfo(
392                @NotNull JetQualifiedExpression expression, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode,
393                @NotNull ResolutionResultsCache resolutionResultsCache
394        ) {
395            // TODO : functions as values
396            JetExpression selectorExpression = expression.getSelectorExpression();
397            JetExpression receiverExpression = expression.getReceiverExpression();
398            JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfoWithNamespaces(
399                    receiverExpression, context.scope, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
400            JetType receiverType = receiverTypeInfo.getType();
401            if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo);
402            if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
403    
404            context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
405    
406            if (selectorExpression instanceof JetSimpleNameExpression) {
407                ConstantUtils.propagateConstantValues(expression, context.trace, (JetSimpleNameExpression) selectorExpression);
408            }
409    
410            JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
411                    new ExpressionReceiver(receiverExpression, receiverType),
412                    expression.getOperationTokenNode(), selectorExpression, context, resolveMode, resolutionResultsCache);
413            JetType selectorReturnType = selectorReturnTypeInfo.getType();
414    
415            //TODO move further
416            if (!(receiverType instanceof NamespaceType) && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
417                if (selectorReturnType != null && !selectorReturnType.isNullable() && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
418                    if (receiverType.isNullable()) {
419                        selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
420                    }
421                }
422            }
423    
424            // TODO : this is suspicious: remove this code?
425            if (selectorReturnType != null) {
426                context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
427            }
428            JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
429            if (resolveMode == ResolveMode.TOP_LEVEL_CALL) {
430                DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo());
431            }
432            return typeInfo;
433        }
434    }