Store resolved calls for loop range's iterator(), next(), hasNext()

+ code duplication removed from expression typing visitor
This commit is contained in:
Andrey Breslav
2012-08-23 16:32:59 +04:00
parent b1ba3e1260
commit 784bf31a3e
5 changed files with 81 additions and 66 deletions
@@ -81,9 +81,11 @@ public interface BindingContext {
WritableSlice<CallKey, OverloadResolutionResults<VariableDescriptor>> RESOLUTION_RESULTS_FOR_PROPERTY = Slices.createSimpleSlice();
WritableSlice<JetExpression, DelegatingBindingTrace> TRACE_DELTAS_CACHE = Slices.createSimpleSlice();
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_ITERATOR = Slices.createSimpleSlice();
WritableSlice<JetExpression, CallableDescriptor> LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice();
WritableSlice<JetExpression, FunctionDescriptor> LOOP_RANGE_NEXT = Slices.createSimpleSlice();
WritableSlice<JetExpression, ResolvedCall<FunctionDescriptor>> LOOP_RANGE_ITERATOR_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<JetExpression, Call> LOOP_RANGE_ITERATOR_CALL = Slices.createSimpleSlice();
WritableSlice<JetExpression, ResolvedCall<FunctionDescriptor>> LOOP_RANGE_HAS_NEXT_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<JetExpression, ResolvedCall<FunctionDescriptor>> LOOP_RANGE_NEXT_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<JetMultiDeclarationEntry, ResolvedCall<FunctionDescriptor>> COMPONENT_RESOLVED_CALL = Slices.createSimpleSlice();
@@ -16,6 +16,7 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
@@ -25,11 +26,13 @@ import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.diagnostics.SimpleDiagnosticFactory;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -41,6 +44,7 @@ import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.ArrayList;
import java.util.Arrays;
@@ -324,44 +328,37 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
// Make a fake call loopRange.iterator(), and try to resolve it
Name iterator = Name.identifier("iterator");
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = resolveFakeCall(loopRange, context, iterator);
Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls = makeAndResolveFakeCall(loopRange, context, iterator);
Call iteratorCall = calls.getFirst();
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = calls.getSecond();
// We allow the loop range to be null (nothing happens), so we make the receiver type non-null
if (!iteratorResolutionResults.isSuccess()) {
ExpressionReceiver nonNullReceiver = new ExpressionReceiver(loopRange.getExpression(), TypeUtils.makeNotNullable(loopRange.getType()));
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResultsWithNonNullReceiver = resolveFakeCall(nonNullReceiver, context, iterator);
Pair<Call,OverloadResolutionResults<FunctionDescriptor>> callsNonNull = makeAndResolveFakeCall(nonNullReceiver, context, iterator);
Call iteratorCallWithNonNullReceiver = callsNonNull.getFirst();
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResultsWithNonNullReceiver = callsNonNull.getSecond();
if (iteratorResolutionResultsWithNonNullReceiver.isSuccess()) {
iteratorResolutionResults = iteratorResolutionResultsWithNonNullReceiver;
iteratorCall = iteratorCallWithNonNullReceiver;
}
}
if (iteratorResolutionResults.isSuccess()) {
FunctionDescriptor iteratorFunction = iteratorResolutionResults.getResultingCall().getResultingDescriptor();
context.trace.record(LOOP_RANGE_ITERATOR, loopRangeExpression, iteratorFunction);
ResolvedCall<FunctionDescriptor> iteratorResolvedCall = iteratorResolutionResults.getResultingCall();
context.trace.record(LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRangeExpression, iteratorResolvedCall);
context.trace.record(LOOP_RANGE_ITERATOR_CALL, loopRangeExpression, iteratorCall);
FunctionDescriptor iteratorFunction = iteratorResolvedCall.getResultingDescriptor();
JetType iteratorType = iteratorFunction.getReturnType();
FunctionDescriptor hasNextFunction = checkHasNextFunctionSupport(loopRangeExpression, iteratorType, context);
boolean hasNextFunctionSupported = hasNextFunction != null;
if (!hasNextFunctionSupported) {
context.trace.report(HAS_NEXT_MISSING.on(loopRangeExpression));
}
else {
context.trace.record(LOOP_RANGE_HAS_NEXT, loopRange.getExpression(), hasNextFunction);
}
OverloadResolutionResults<FunctionDescriptor> nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), Name.identifier("next"), Collections.<JetType>emptyList());
if (nextResolutionResults.isAmbiguity()) {
context.trace.report(NEXT_AMBIGUITY.on(loopRangeExpression));
}
else if (nextResolutionResults.isNothing()) {
context.trace.report(NEXT_MISSING.on(loopRangeExpression));
}
else {
FunctionDescriptor nextFunction = nextResolutionResults.getResultingCall().getResultingDescriptor();
context.trace.record(LOOP_RANGE_NEXT, loopRange.getExpression(), nextFunction);
return nextFunction.getReturnType();
JetType hasNextType = checkConventionForIterator(context, loopRangeExpression, iteratorType, "hasNext",
HAS_NEXT_FUNCTION_AMBIGUITY, HAS_NEXT_MISSING,
LOOP_RANGE_HAS_NEXT_RESOLVED_CALL);
if (hasNextType != null && !isBoolean(hasNextType)) {
context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRangeExpression, hasNextType));
}
return checkConventionForIterator(context, loopRangeExpression, iteratorType, "next", NEXT_AMBIGUITY, NEXT_MISSING,
LOOP_RANGE_NEXT_RESOLVED_CALL);
}
else {
if (iteratorResolutionResults.isAmbiguity()) {
@@ -380,22 +377,30 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
}
@Nullable
private static FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, ExpressionTypingContext context) {
OverloadResolutionResults<FunctionDescriptor> hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), Name.identifier("hasNext"), Collections.<JetType>emptyList());
if (hasNextResolutionResults.isAmbiguity()) {
context.trace.report(HAS_NEXT_FUNCTION_AMBIGUITY.on(loopRange));
private static JetType checkConventionForIterator(
@NotNull ExpressionTypingContext context,
@NotNull JetExpression loopRangeExpression,
@NotNull JetType iteratorType,
@NotNull String name,
@NotNull SimpleDiagnosticFactory<JetExpression> ambiguity,
@NotNull SimpleDiagnosticFactory<JetExpression> missing,
@NotNull WritableSlice<JetExpression, ResolvedCall<FunctionDescriptor>> call
) {
OverloadResolutionResults<FunctionDescriptor>
nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), Name.identifier(name), Collections
.<JetType>emptyList());
if (nextResolutionResults.isAmbiguity()) {
context.trace.report(ambiguity.on(loopRangeExpression));
}
else if (hasNextResolutionResults.isNothing()) {
return null;
else if (nextResolutionResults.isNothing()) {
context.trace.report(missing.on(loopRangeExpression));
}
else {
assert hasNextResolutionResults.isSuccess();
JetType hasNextReturnType = hasNextResolutionResults.getResultingDescriptor().getReturnType();
if (!isBoolean(hasNextReturnType)) {
context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRange, hasNextReturnType));
}
ResolvedCall<FunctionDescriptor> nextCall = nextResolutionResults.getResultingCall();
context.trace.record(call, loopRangeExpression, nextCall);
return nextCall.getResultingDescriptor().getReturnType();
}
return hasNextResolutionResults.getResultingCall().getResultingDescriptor();
return null;
}
@Override
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;
@@ -28,7 +29,10 @@ import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.inference.*;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -248,11 +252,20 @@ public class ExpressionTypingUtils {
@NotNull ReceiverDescriptor receiver,
@NotNull ExpressionTypingContext context,
@NotNull Name name
) {
return makeAndResolveFakeCall(receiver, context, name).getSecond();
}
@NotNull
public static Pair<Call, OverloadResolutionResults<FunctionDescriptor>> makeAndResolveFakeCall(
@NotNull ReceiverDescriptor receiver,
@NotNull ExpressionTypingContext context,
@NotNull Name name
) {
JetReferenceExpression fake = JetPsiFactory.createSimpleName(context.expressionTypingServices.getProject(), "fake");
BindingTrace fakeTrace = TemporaryBindingTrace.create(context.trace);
Call call = CallMaker.makeCall(fake, receiver, null, fake, Collections.<ValueArgument>emptyList());
return context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name);
return Pair.create(call, context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name));
}
public static void defineLocalVariablesFromMultiDeclaration(
@@ -20,10 +20,10 @@ import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetForExpression;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.general.Translation;
import org.jetbrains.k2js.translate.reference.CallBuilder;
@@ -61,24 +61,24 @@ public final class IteratorForTranslator extends ForTranslator {
@NotNull
private JsExpression hasNextMethodInvocation() {
CallableDescriptor hasNextFunction = getHasNextCallable(bindingContext(), getLoopRange(expression));
return translateMethodInvocation(iterator.second, hasNextFunction);
ResolvedCall<FunctionDescriptor> resolvedCall = getHasNextCallable(bindingContext(), getLoopRange(expression));
return translateMethodInvocation(iterator.second, resolvedCall);
}
@NotNull
private JsExpression iteratorMethodInvocation() {
JetExpression rangeExpression = getLoopRange(expression);
JsExpression range = Translation.translateAsExpression(rangeExpression, context());
FunctionDescriptor iteratorFunction = getIteratorFunction(bindingContext(), rangeExpression);
return translateMethodInvocation(range, iteratorFunction);
ResolvedCall<FunctionDescriptor> resolvedCall = getIteratorFunction(bindingContext(), rangeExpression);
return translateMethodInvocation(range, resolvedCall);
}
@NotNull
private JsExpression translateMethodInvocation(@Nullable JsExpression receiver,
@NotNull CallableDescriptor descriptor) {
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall) {
return CallBuilder.build(context())
.resolvedCall(resolvedCall)
.receiver(receiver)
.descriptor(descriptor)
.translate();
}
}
@@ -227,35 +227,30 @@ public final class BindingUtils {
}
@NotNull
public static FunctionDescriptor getIteratorFunction(@NotNull BindingContext context,
public static ResolvedCall<FunctionDescriptor> getIteratorFunction(@NotNull BindingContext context,
@NotNull JetExpression rangeExpression) {
FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_ITERATOR, rangeExpression);
assert functionDescriptor != null :
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, rangeExpression);
assert resolvedCall != null :
message(rangeExpression, "Range expression must have a descriptor for iterator function");
return functionDescriptor;
return resolvedCall;
}
@NotNull
public static FunctionDescriptor getNextFunction(@NotNull BindingContext context,
public static ResolvedCall<FunctionDescriptor> getNextFunction(@NotNull BindingContext context,
@NotNull JetExpression rangeExpression) {
FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_NEXT, rangeExpression);
assert functionDescriptor != null : ErrorReportingUtils
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, rangeExpression);
assert resolvedCall != null : ErrorReportingUtils
.message(rangeExpression, "Range expression must have a descriptor for next function");
return functionDescriptor;
return resolvedCall;
}
@NotNull
public static CallableDescriptor getHasNextCallable(@NotNull BindingContext context,
public static ResolvedCall<FunctionDescriptor> getHasNextCallable(@NotNull BindingContext context,
@NotNull JetExpression rangeExpression) {
CallableDescriptor hasNextDescriptor = context.get(BindingContext.LOOP_RANGE_HAS_NEXT, rangeExpression);
assert hasNextDescriptor != null
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, rangeExpression);
assert resolvedCall != null
: message(rangeExpression, "Range expression must have a descriptor for hasNext function or property");
if (hasNextDescriptor instanceof PropertyDescriptor) {
PropertyGetterDescriptor getter = ((PropertyDescriptor) hasNextDescriptor).getGetter();
assert getter != null : "Loop range hasNext val should have a getter.";
return getter;
}
return hasNextDescriptor;
return resolvedCall;
}
@NotNull