From 784bf31a3e6563a5947f40426fa2e2e32ac0d03b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 23 Aug 2012 16:32:59 +0400 Subject: [PATCH] Store resolved calls for loop range's iterator(), next(), hasNext() + code duplication removed from expression typing visitor --- .../jet/lang/resolve/BindingContext.java | 8 +- .../ControlStructureTypingVisitor.java | 79 ++++++++++--------- .../expressions/ExpressionTypingUtils.java | 17 +++- .../foreach/IteratorForTranslator.java | 14 ++-- .../k2js/translate/utils/BindingUtils.java | 29 +++---- 5 files changed, 81 insertions(+), 66 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index ca430378f6f..e902bccbd86 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -81,9 +81,11 @@ public interface BindingContext { WritableSlice> RESOLUTION_RESULTS_FOR_PROPERTY = Slices.createSimpleSlice(); WritableSlice TRACE_DELTAS_CACHE = Slices.createSimpleSlice(); - WritableSlice LOOP_RANGE_ITERATOR = Slices.createSimpleSlice(); - WritableSlice LOOP_RANGE_HAS_NEXT = Slices.createSimpleSlice(); - WritableSlice LOOP_RANGE_NEXT = Slices.createSimpleSlice(); + WritableSlice> LOOP_RANGE_ITERATOR_RESOLVED_CALL = Slices.createSimpleSlice(); + WritableSlice LOOP_RANGE_ITERATOR_CALL = Slices.createSimpleSlice(); + + WritableSlice> LOOP_RANGE_HAS_NEXT_RESOLVED_CALL = Slices.createSimpleSlice(); + WritableSlice> LOOP_RANGE_NEXT_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice> COMPONENT_RESOLVED_CALL = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index 5f2c811db9f..84f12b9fc98 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -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 iteratorResolutionResults = resolveFakeCall(loopRange, context, iterator); + Pair> calls = makeAndResolveFakeCall(loopRange, context, iterator); + Call iteratorCall = calls.getFirst(); + OverloadResolutionResults 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 iteratorResolutionResultsWithNonNullReceiver = resolveFakeCall(nonNullReceiver, context, iterator); + Pair> callsNonNull = makeAndResolveFakeCall(nonNullReceiver, context, iterator); + Call iteratorCallWithNonNullReceiver = callsNonNull.getFirst(); + OverloadResolutionResults 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 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 nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), Name.identifier("next"), Collections.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 hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), Name.identifier("hasNext"), Collections.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 ambiguity, + @NotNull SimpleDiagnosticFactory missing, + @NotNull WritableSlice> call + ) { + OverloadResolutionResults + nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), Name.identifier(name), Collections + .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 nextCall = nextResolutionResults.getResultingCall(); + context.trace.record(call, loopRangeExpression, nextCall); + return nextCall.getResultingDescriptor().getReturnType(); } - return hasNextResolutionResults.getResultingCall().getResultingDescriptor(); + return null; } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 61315d625cd..ab576cb2ad0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -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> 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.emptyList()); - return context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name); + return Pair.create(call, context.replaceBindingTrace(fakeTrace).resolveCallWithGivenName(call, fake, name)); } public static void defineLocalVariablesFromMultiDeclaration( diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java index c87aa6ff0f8..8cc61241088 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/foreach/IteratorForTranslator.java @@ -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 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 resolvedCall = getIteratorFunction(bindingContext(), rangeExpression); + return translateMethodInvocation(range, resolvedCall); } @NotNull private JsExpression translateMethodInvocation(@Nullable JsExpression receiver, - @NotNull CallableDescriptor descriptor) { + @NotNull ResolvedCall resolvedCall) { return CallBuilder.build(context()) + .resolvedCall(resolvedCall) .receiver(receiver) - .descriptor(descriptor) .translate(); } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java index 57a5384f281..e2f99cf91ac 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/BindingUtils.java @@ -227,35 +227,30 @@ public final class BindingUtils { } @NotNull - public static FunctionDescriptor getIteratorFunction(@NotNull BindingContext context, + public static ResolvedCall getIteratorFunction(@NotNull BindingContext context, @NotNull JetExpression rangeExpression) { - FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_ITERATOR, rangeExpression); - assert functionDescriptor != null : + ResolvedCall 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 getNextFunction(@NotNull BindingContext context, @NotNull JetExpression rangeExpression) { - FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_NEXT, rangeExpression); - assert functionDescriptor != null : ErrorReportingUtils + ResolvedCall 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 getHasNextCallable(@NotNull BindingContext context, @NotNull JetExpression rangeExpression) { - CallableDescriptor hasNextDescriptor = context.get(BindingContext.LOOP_RANGE_HAS_NEXT, rangeExpression); - assert hasNextDescriptor != null + ResolvedCall 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