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