From 664e25d113e88cc3317f71c9d336db68c2e6cb71 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Thu, 7 Feb 2013 20:40:52 +0400 Subject: [PATCH] added CallExpressionResolver call expression resolution logic moved there (from BasicExpressionTypingVisitor) --- .../resolve/calls/CallExpressionResolver.java | 317 ++++++++++++++++++ .../BasicExpressionTypingVisitor.java | 278 +-------------- 2 files changed, 323 insertions(+), 272 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java new file mode 100644 index 00000000000..56b703c6ff0 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -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() { + @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 getResolvedCallForFunction( + @NotNull Call call, @NotNull JetExpression callExpression, @NotNull ReceiverValue receiver, + @NotNull ExpressionTypingContext context, @NotNull boolean[] result + ) { + + OverloadResolutionResults 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 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.emptyList()); + TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression); + ResolvedCall 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 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 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); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 5de36c89905..b5ae90b5954 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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() { - @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 getResolvedCallForFunction( - @NotNull Call call, @NotNull JetExpression callExpression, @NotNull ReceiverValue receiver, - @NotNull ExpressionTypingContext context, @NotNull boolean[] result - ) { - - OverloadResolutionResults 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 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.emptyList()); - TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression); - ResolvedCall 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 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 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()); }