added CallExpressionResolver

call expression resolution logic moved there (from BasicExpressionTypingVisitor)
This commit is contained in:
Svetlana Isakova
2013-02-07 20:40:52 +04:00
parent e739fd936e
commit 664e25d113
2 changed files with 323 additions and 272 deletions
@@ -0,0 +1,317 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.base.Predicate;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInfo;
import org.jetbrains.jet.lang.types.NamespaceType;
import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
import java.util.Collections;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.NON_DEFAULT_EXPRESSION_DATA_FLOW;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.RESOLUTION_SCOPE;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
public class CallExpressionResolver {
@Nullable
private static JetType lookupNamespaceOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) {
Name referencedName = expression.getReferencedNameAsName();
ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
if (classifier != null) {
JetType classObjectType = classifier.getClassObjectType();
if (classObjectType != null) {
context.trace.record(REFERENCE_TARGET, expression, classifier);
JetType result;
if (context.namespacesAllowed && classifier instanceof ClassDescriptor) {
JetScope scope = new ChainedScope(classifier, classObjectType.getMemberScope(),
getStaticNestedClassesScope((ClassDescriptor) classifier));
result = new NamespaceType(referencedName, scope);
}
else if (context.namespacesAllowed || classifier.isClassObjectAValue()) {
result = classObjectType;
}
else {
context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
result = null;
}
return DataFlowUtils.checkType(result, expression, context);
}
}
JetType[] result = new JetType[1];
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
context.trace, "trace for namespace/class object lookup of name", referencedName);
if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
temporaryTrace.commit();
return DataFlowUtils.checkType(result[0], expression, context);
}
// To report NO_CLASS_OBJECT when no namespace found
if (classifier != null) {
if (!context.namespacesAllowed) {
context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
}
context.trace.record(REFERENCE_TARGET, expression, classifier);
JetScope scopeForStaticMembersResolution = classifier instanceof ClassDescriptor
? getStaticNestedClassesScope((ClassDescriptor) classifier)
: JetScope.EMPTY;
return new NamespaceType(referencedName, scopeForStaticMembersResolution);
}
temporaryTrace.commit();
return result[0];
}
@NotNull
private static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
@Override
public boolean apply(@Nullable DeclarationDescriptor descriptor) {
return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
}
});
}
private static boolean furtherNameLookup(
@NotNull JetSimpleNameExpression expression,
@NotNull JetType[] result,
@NotNull ExpressionTypingContext context
) {
NamespaceType namespaceType = lookupNamespaceType(expression, context);
if (namespaceType == null) {
return false;
}
if (context.namespacesAllowed) {
result[0] = namespaceType;
return true;
}
context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression));
result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName());
return false;
}
@Nullable
private static NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) {
Name name = expression.getReferencedNameAsName();
NamespaceDescriptor namespace = context.scope.getNamespace(name);
if (namespace == null) {
return null;
}
context.trace.record(REFERENCE_TARGET, expression, namespace);
// Construct a NamespaceType with everything from the namespace and with static nested classes of the corresponding class (if any)
JetScope scope;
ClassifierDescriptor classifier = context.scope.getClassifier(name);
if (classifier instanceof ClassDescriptor) {
scope = new ChainedScope(namespace, namespace.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier));
}
else {
scope = namespace.getMemberScope();
}
return new NamespaceType(name, scope);
}
@Nullable
private static ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
@NotNull Call call, @NotNull JetExpression callExpression, @NotNull ReceiverValue receiver,
@NotNull ExpressionTypingContext context, @NotNull boolean[] result
) {
OverloadResolutionResults<FunctionDescriptor> results = context.resolveFunctionCall(call);
if (!results.isNothing()) {
checkSuper(receiver, results, context.trace, callExpression);
result[0] = true;
if (results.isIncomplete()) {
return null;
}
return results.isSingleResult() ? results.getResultingCall() : null;
}
result[0] = false;
return null;
}
@Nullable
private static JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result) {
TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(
context.trace, "trace to resolve as local variable or property", nameExpression);
OverloadResolutionResults<VariableDescriptor> resolutionResult = context.replaceBindingTrace(traceForVariable).resolveSimpleProperty(receiver, callOperationNode, nameExpression);
if (!resolutionResult.isNothing()) {
traceForVariable.commit();
checkSuper(receiver, resolutionResult, context.trace, nameExpression);
result[0] = true;
return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
}
ExpressionTypingContext newContext = receiver.exists()
? context.replaceScope(receiver.getType().getMemberScope())
: context;
TemporaryBindingTrace traceForNamespaceOrClassObject = TemporaryBindingTrace.create(
context.trace, "trace to resolve as namespace or class object", nameExpression);
JetType jetType = lookupNamespaceOrClassObject(nameExpression, newContext.replaceBindingTrace(traceForNamespaceOrClassObject));
if (jetType != null) {
traceForNamespaceOrClassObject.commit();
// Uncommitted changes in temp context
context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope);
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo);
}
result[0] = true;
return jetType;
}
result[0] = false;
return null;
}
@NotNull
public static JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
boolean[] result = new boolean[1];
TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace, "trace to resolve as variable", nameExpression);
JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result);
if (result[0]) {
traceForVariable.commit();
return JetTypeInfo.create(type, context.dataFlowInfo);
}
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(call, nameExpression, receiver, context, result);
if (result[0]) {
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
traceForFunction.commit();
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
return JetTypeInfo.create(type, context.dataFlowInfo);
}
traceForVariable.commit();
return JetTypeInfo.create(null, context.dataFlowInfo);
}
@NotNull
public static JetTypeInfo getCallExpressionTypeInfo(@NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
boolean[] result = new boolean[1];
Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function call", callExpression);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(call, callExpression, receiver,
context.replaceBindingTrace(traceForFunction), result);
if (result[0]) {
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
traceForFunction.commit();
if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
// there are only type arguments
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
}
if (functionDescriptor == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
}
JetType type = functionDescriptor.getReturnType();
return JetTypeInfo.create(type, resolvedCall.getDataFlowInfo());
}
JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(
context.trace, "trace to resolve as variable with 'invoke' call", callExpression);
JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode,
context.replaceBindingTrace(traceForVariable), result);
if (result[0]) {
traceForVariable.commit();
context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
type != null ? type : ErrorUtils.createErrorType("")));
return JetTypeInfo.create(null, context.dataFlowInfo);
}
}
traceForFunction.commit();
return JetTypeInfo.create(null, context.dataFlowInfo);
}
private static void checkSuper(@NotNull ReceiverValue receiverValue, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
@NotNull BindingTrace trace, @NotNull JetExpression expression) {
if (!results.isSingleResult()) return;
if (!(receiverValue instanceof ExpressionReceiver)) return;
JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
CallableDescriptor descriptor = results.getResultingDescriptor();
if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
trace.report(ABSTRACT_SUPER_CALL.on(expression));
}
}
}
@NotNull
public static JetTypeInfo getSelectorReturnTypeInfo(
@NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode,
@NotNull JetExpression selectorExpression,
@NotNull ExpressionTypingContext context
) {
if (selectorExpression instanceof JetCallExpression) {
return getCallExpressionTypeInfo((JetCallExpression) selectorExpression, receiver, callOperationNode, context);
}
else if (selectorExpression instanceof JetSimpleNameExpression) {
return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
}
else if (selectorExpression instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression();
JetTypeInfo newReceiverTypeInfo = getSelectorReturnTypeInfo(receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
JetType newReceiverType = newReceiverTypeInfo.getType();
DataFlowInfo newReceiverDataFlowInfo = newReceiverTypeInfo.getDataFlowInfo();
JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression();
if (newReceiverType != null && newSelectorExpression != null) {
return getSelectorReturnTypeInfo(new ExpressionReceiver(newReceiverExpression, newReceiverType), qualifiedExpression.getOperationTokenNode(), newSelectorExpression, context.replaceDataFlowInfo(newReceiverDataFlowInfo));
}
}
else {
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
}
return JetTypeInfo.create(null, context.dataFlowInfo);
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.types.expressions;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.intellij.lang.ASTNode;
@@ -29,11 +28,11 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
@@ -41,12 +40,9 @@ import org.jetbrains.jet.lang.resolve.constants.*;
import org.jetbrains.jet.lang.resolve.constants.StringValue;
import org.jetbrains.jet.lang.resolve.name.LabelName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure;
@@ -73,108 +69,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
public JetTypeInfo visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) {
// TODO : other members
// TODO : type substitutions???
JetTypeInfo typeInfo = getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
JetTypeInfo typeInfo = CallExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context);
JetType type = DataFlowUtils.checkType(typeInfo.getType(), expression, context);
ExpressionTypingUtils.checkWrappingInRef(expression, context.trace, context.scope);
return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this
}
@Nullable
private static JetType lookupNamespaceOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) {
Name referencedName = expression.getReferencedNameAsName();
ClassifierDescriptor classifier = context.scope.getClassifier(referencedName);
if (classifier != null) {
JetType classObjectType = classifier.getClassObjectType();
if (classObjectType != null) {
context.trace.record(REFERENCE_TARGET, expression, classifier);
JetType result;
if (context.namespacesAllowed && classifier instanceof ClassDescriptor) {
JetScope scope = new ChainedScope(classifier, classObjectType.getMemberScope(),
getStaticNestedClassesScope((ClassDescriptor) classifier));
result = new NamespaceType(referencedName, scope);
}
else if (context.namespacesAllowed || classifier.isClassObjectAValue()) {
result = classObjectType;
}
else {
context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
result = null;
}
return DataFlowUtils.checkType(result, expression, context);
}
}
JetType[] result = new JetType[1];
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(
context.trace, "trace for namespace/class object lookup of name", referencedName);
if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) {
temporaryTrace.commit();
return DataFlowUtils.checkType(result[0], expression, context);
}
// To report NO_CLASS_OBJECT when no namespace found
if (classifier != null) {
if (!context.namespacesAllowed) {
context.trace.report(NO_CLASS_OBJECT.on(expression, classifier));
}
context.trace.record(REFERENCE_TARGET, expression, classifier);
JetScope scopeForStaticMembersResolution = classifier instanceof ClassDescriptor
? getStaticNestedClassesScope((ClassDescriptor) classifier)
: JetScope.EMPTY;
return new NamespaceType(referencedName, scopeForStaticMembersResolution);
}
temporaryTrace.commit();
return result[0];
}
@NotNull
private static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
@Override
public boolean apply(@Nullable DeclarationDescriptor descriptor) {
return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
}
});
}
private static boolean furtherNameLookup(
@NotNull JetSimpleNameExpression expression,
@NotNull JetType[] result,
@NotNull ExpressionTypingContext context
) {
NamespaceType namespaceType = lookupNamespaceType(expression, context);
if (namespaceType == null) {
return false;
}
if (context.namespacesAllowed) {
result[0] = namespaceType;
return true;
}
context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression));
result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName());
return false;
}
@Nullable
private static NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull ExpressionTypingContext context) {
Name name = expression.getReferencedNameAsName();
NamespaceDescriptor namespace = context.scope.getNamespace(name);
if (namespace == null) {
return null;
}
context.trace.record(REFERENCE_TARGET, expression, namespace);
// Construct a NamespaceType with everything from the namespace and with static nested classes of the corresponding class (if any)
JetScope scope;
ClassifierDescriptor classifier = context.scope.getClassifier(name);
if (classifier instanceof ClassDescriptor) {
scope = new ChainedScope(namespace, namespace.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier));
}
else {
scope = namespace.getMemberScope();
}
return new NamespaceType(name, scope);
}
@Override
public JetTypeInfo visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context) {
return visitParenthesizedExpression(expression, context, false);
@@ -704,7 +604,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
propagateConstantValues(expression, context, (JetSimpleNameExpression) selectorExpression);
}
JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context);
JetTypeInfo selectorReturnTypeInfo = CallExpressionResolver.getSelectorReturnTypeInfo(
new ExpressionReceiver(receiverExpression, receiverType), expression.getOperationTokenNode(), selectorExpression, context);
JetType selectorReturnType = selectorReturnTypeInfo.getType();
//TODO move further
@@ -723,7 +624,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return DataFlowUtils.checkType(selectorReturnType, expression, context, selectorReturnTypeInfo.getDataFlowInfo());
}
private void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
private static void propagateConstantValues(JetQualifiedExpression expression, ExpressionTypingContext context, JetSimpleNameExpression selectorExpression) {
JetExpression receiverExpression = expression.getReceiverExpression();
CompileTimeConstant<?> receiverValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, receiverExpression);
CompileTimeConstant<?> wholeExpressionValue = context.trace.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression);
@@ -755,176 +656,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
}
@Nullable
public static ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
@NotNull Call call, @NotNull JetExpression callExpression, @NotNull ReceiverValue receiver,
@NotNull ExpressionTypingContext context, @NotNull boolean[] result
) {
OverloadResolutionResults<FunctionDescriptor> results = context.resolveFunctionCall(call);
if (!results.isNothing()) {
checkSuper(receiver, results, context.trace, callExpression);
result[0] = true;
if (results.isIncomplete()) {
return null;
}
return results.isSingleResult() ? results.getResultingCall() : null;
}
result[0] = false;
return null;
}
@Nullable
public static JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result) {
TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(
context.trace, "trace to resolve as local variable or property", nameExpression);
OverloadResolutionResults<VariableDescriptor> resolutionResult = context.replaceBindingTrace(traceForVariable).resolveSimpleProperty(receiver, callOperationNode, nameExpression);
if (!resolutionResult.isNothing()) {
traceForVariable.commit();
checkSuper(receiver, resolutionResult, context.trace, nameExpression);
result[0] = true;
return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
}
ExpressionTypingContext newContext = receiver.exists()
? context.replaceScope(receiver.getType().getMemberScope())
: context;
TemporaryBindingTrace traceForNamespaceOrClassObject = TemporaryBindingTrace.create(
context.trace, "trace to resolve as namespace or class object", nameExpression);
JetType jetType = lookupNamespaceOrClassObject(nameExpression, newContext.replaceBindingTrace(traceForNamespaceOrClassObject));
if (jetType != null) {
traceForNamespaceOrClassObject.commit();
// Uncommitted changes in temp context
context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope);
if (context.dataFlowInfo.hasTypeInfoConstraints()) {
context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo);
}
result[0] = true;
return jetType;
}
result[0] = false;
return null;
}
@NotNull
private JetTypeInfo getSelectorReturnTypeInfo(@NotNull ReceiverValue receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context) {
if (selectorExpression instanceof JetCallExpression) {
return getCallExpressionTypeInfo((JetCallExpression) selectorExpression, receiver, callOperationNode, context);
}
else if (selectorExpression instanceof JetSimpleNameExpression) {
return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
}
else if (selectorExpression instanceof JetQualifiedExpression) {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression;
JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression();
JetTypeInfo newReceiverTypeInfo = getSelectorReturnTypeInfo(receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE));
JetType newReceiverType = newReceiverTypeInfo.getType();
DataFlowInfo newReceiverDataFlowInfo = newReceiverTypeInfo.getDataFlowInfo();
JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression();
if (newReceiverType != null && newSelectorExpression != null) {
return getSelectorReturnTypeInfo(new ExpressionReceiver(newReceiverExpression, newReceiverType), qualifiedExpression.getOperationTokenNode(), newSelectorExpression, context.replaceDataFlowInfo(newReceiverDataFlowInfo));
}
}
else {
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
}
return JetTypeInfo.create(null, context.dataFlowInfo);
}
@NotNull
private static JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
boolean[] result = new boolean[1];
TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace, "trace to resolve as variable", nameExpression);
JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result);
if (result[0]) {
traceForVariable.commit();
if (type instanceof NamespaceType && !context.namespacesAllowed) {
type = null;
}
return JetTypeInfo.create(type, context.dataFlowInfo);
}
Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(call, nameExpression, receiver, context, result);
if (result[0]) {
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
traceForFunction.commit();
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
return JetTypeInfo.create(type, context.dataFlowInfo);
}
traceForVariable.commit();
return JetTypeInfo.create(null, context.dataFlowInfo);
}
@NotNull
private static JetTypeInfo getCallExpressionTypeInfo(@NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
@Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context) {
boolean[] result = new boolean[1];
Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function call", callExpression);
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(call, callExpression, receiver,
context.replaceBindingTrace(traceForFunction), result);
if (result[0]) {
FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
traceForFunction.commit();
if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
// there are only type arguments
boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
}
if (functionDescriptor == null) {
return JetTypeInfo.create(null, context.dataFlowInfo);
}
JetType type = functionDescriptor.getReturnType();
return JetTypeInfo.create(type, resolvedCall.getDataFlowInfo());
}
JetExpression calleeExpression = callExpression.getCalleeExpression();
if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(
context.trace, "trace to resolve as variable with 'invoke' call", callExpression);
JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode,
context.replaceBindingTrace(traceForVariable), result);
if (result[0]) {
traceForVariable.commit();
context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression,
type != null ? type : ErrorUtils.createErrorType("")));
return JetTypeInfo.create(null, context.dataFlowInfo);
}
}
traceForFunction.commit();
return JetTypeInfo.create(null, context.dataFlowInfo);
}
private static void checkSuper(@NotNull ReceiverValue receiverValue, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results,
@NotNull BindingTrace trace, @NotNull JetExpression expression) {
if (!results.isSingleResult()) return;
if (!(receiverValue instanceof ExpressionReceiver)) return;
JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
CallableDescriptor descriptor = results.getResultingDescriptor();
if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
trace.report(ABSTRACT_SUPER_CALL.on(expression));
}
}
}
@Override
public JetTypeInfo visitCallExpression(JetCallExpression expression, ExpressionTypingContext context) {
JetTypeInfo expressionTypeInfo = getCallExpressionTypeInfo(expression, NO_RECEIVER, null, context);
JetTypeInfo expressionTypeInfo = CallExpressionResolver.getCallExpressionTypeInfo(expression, NO_RECEIVER, null, context);
return DataFlowUtils.checkType(expressionTypeInfo.getType(), expression, context, expressionTypeInfo.getDataFlowInfo());
}