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