Store resolved calls for loop range's iterator(), next(), hasNext()
+ code duplication removed from expression typing visitor
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
+42
-37
@@ -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
|
||||
|
||||
+15
-2
@@ -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(
|
||||
|
||||
+7
-7
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user