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
017package org.jetbrains.jet.lang.resolve.calls;
018
019import com.intellij.lang.ASTNode;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.jet.lang.descriptors.*;
023import org.jetbrains.jet.lang.psi.*;
024import org.jetbrains.jet.lang.resolve.BindingContext;
025import org.jetbrains.jet.lang.resolve.BindingTrace;
026import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
027import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
028import org.jetbrains.jet.lang.resolve.calls.context.*;
029import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
030import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
031import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
032import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
033import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
034import org.jetbrains.jet.lang.resolve.constants.ConstantUtils;
035import org.jetbrains.jet.lang.resolve.name.Name;
036import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
037import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl;
039import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
040import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
041import org.jetbrains.jet.lang.types.*;
042import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
043import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
044import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
045import org.jetbrains.jet.lexer.JetTokens;
046
047import javax.inject.Inject;
048import java.util.ArrayList;
049import java.util.Collections;
050import java.util.List;
051
052import static org.jetbrains.jet.lang.diagnostics.Errors.*;
053import static org.jetbrains.jet.lang.resolve.BindingContext.*;
054import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
055import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
056
057public 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}