From 4d62fbad2bf3deb296f2f155354eba82b2011bda Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 17 Apr 2012 14:05:38 +0400 Subject: [PATCH] changed resolution order: first priority is 'local extensions; members; nonlocal extensions', than by implicit receivers (before was vice versa) --- .../resolve/calls/ResolutionTaskHolder.java | 99 +++++++++++++++++++ .../lang/resolve/calls/TaskPrioritizer.java | 59 +++-------- .../testData/codegen/classes/resolveOrder.jet | 53 ++++++++++ .../jetbrains/jet/codegen/ClassGenTest.java | 4 + 4 files changed, 169 insertions(+), 46 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTaskHolder.java create mode 100644 compiler/testData/codegen/classes/resolveOrder.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTaskHolder.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTaskHolder.java new file mode 100644 index 00000000000..4b27a266b07 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTaskHolder.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010-2012 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.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.psi.JetReferenceExpression; + +import java.util.Collection; +import java.util.List; + +/** + * @author svtk + */ +public class ResolutionTaskHolder { + private final JetReferenceExpression reference; + private final BasicResolutionContext basicResolutionContext; + private final Predicate> visibleStrategy; + + private final Collection>> localExtensions = Sets.newLinkedHashSet(); + private final Collection>> members = Sets.newLinkedHashSet(); + private final Collection>> nonLocalExtensions = Sets.newLinkedHashSet(); + + private List> tasks = null; + + public ResolutionTaskHolder(@NotNull JetReferenceExpression reference, + @NotNull BasicResolutionContext basicResolutionContext, + @NotNull Predicate> visibleStrategy) { + this.reference = reference; + this.basicResolutionContext = basicResolutionContext; + this.visibleStrategy = visibleStrategy; + } + + public void addLocalExtensions(@NotNull Collection> candidates) { + if (!candidates.isEmpty()) { + localExtensions.add(candidates); + } + } + + public void addMembers(@NotNull Collection> candidates) { + if (!candidates.isEmpty()) { + members.add(candidates); + } + } + + public void addNonLocalExtensions(@NotNull Collection> candidates) { + if (!candidates.isEmpty()) { + nonLocalExtensions.add(candidates); + } + } + + public List> getTasks() { + if (tasks == null) { + tasks = Lists.newArrayList(); + List>> candidateList = Lists.newArrayList(); + // If the call is of the form super.foo(), it can actually be only a member + // But if there's no appropriate member, we would like to report that super cannot be a receiver for an extension + // Thus, put members first + if (TaskPrioritizer.getReceiverSuper(basicResolutionContext.call.getExplicitReceiver()) != null) { + candidateList.addAll(members); + candidateList.addAll(localExtensions); + } + else { + candidateList.addAll(localExtensions); + candidateList.addAll(members); + } + candidateList.addAll(nonLocalExtensions); + + for (Predicate> visibilityStrategy : Lists.newArrayList(visibleStrategy, Predicates.not(visibleStrategy))) { + for (Collection> candidates : candidateList) { + Collection> filteredCandidates = Collections2.filter(candidates, visibilityStrategy); + if (!filteredCandidates.isEmpty()) { + tasks.add(new ResolutionTask(filteredCandidates, reference, basicResolutionContext)); + } + } + } + } + return tasks; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index e439fce52f8..5492bb2c921 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +26,6 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.psi.JetSuperExpression; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; -import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; @@ -79,8 +77,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor @NotNull public List> computePrioritizedTasks(@NotNull BasicResolutionContext context, @NotNull String name, @NotNull JetReferenceExpression functionReference) { - List> result = Lists.newArrayList(); - ReceiverDescriptor explicitReceiver = context.call.getExplicitReceiver(); final JetScope scope; if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) { @@ -100,24 +96,17 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor return Visibilities.isVisible(candidateDescriptor, scope.getContainingDeclaration()); } }; - Predicate> invisibleStrategy = new Predicate>() { - @Override - public boolean apply(@Nullable ResolvedCallImpl call) { - return !visibleStrategy.apply(call); - } - }; - doComputeTasks(scope, explicitReceiver, name, result, context, functionReference, visibleStrategy); - doComputeTasks(scope, explicitReceiver, name, result, context, functionReference, invisibleStrategy); - return result; + ResolutionTaskHolder result = new ResolutionTaskHolder(functionReference, context, visibleStrategy ); + doComputeTasks(scope, explicitReceiver, name, result, context); + + return result.getTasks(); } private void doComputeTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, - @NotNull String name, @NotNull List> result, - @NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference, - @NotNull Predicate> filterStrategy) { + @NotNull String name, @NotNull ResolutionTaskHolder result, + @NotNull BasicResolutionContext context) { AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext()); - DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo(); List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); if (receiver.exists()) { @@ -135,25 +124,16 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members); } - if (getReceiverSuper(receiver) != null) { - // If the call is of the form super.foo(), it can actually be only a member - // But if there's no appropriate member, we would like to report that super cannot be a receiver for an extension - // Thus, put members first - addTask(result, members, context, functionReference, filterStrategy); - addTask(result, locals, context, functionReference, filterStrategy); - } - else { - addTask(result, locals, context, functionReference, filterStrategy); - addTask(result, members, context, functionReference, filterStrategy); - } + result.addLocalExtensions(locals); + result.addMembers(members); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { Collection memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name); List variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver); - addTask(result, convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver), context, functionReference, filterStrategy); + result.addNonLocalExtensions(convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver)); } - addTask(result, nonlocals, context, functionReference, filterStrategy); + result.addNonLocalExtensions(nonlocals); } else { Collection> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name)); @@ -163,13 +143,12 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); - addTask(result, locals, context, functionReference, filterStrategy); + result.addLocalExtensions(locals); + result.addNonLocalExtensions(nonlocals); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { - doComputeTasks(scope, implicitReceiver, name, result, context, functionReference, filterStrategy); + doComputeTasks(scope, implicitReceiver, name, result, context); } - - addTask(result, nonlocals, context, functionReference, filterStrategy); } } @@ -180,7 +159,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor } private void convertWithReceivers(Collection descriptors, Iterable thisObjects, Iterable receiverParameters, Collection> result) { -// Collection> result = Lists.newArrayList(); for (ReceiverDescriptor thisObject : thisObjects) { for (ReceiverDescriptor receiverParameter : receiverParameters) { for (D extension : descriptors) { @@ -191,7 +169,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor } } } -// return result; } public static Collection> convertWithImpliedThis(JetScope scope, Iterable receiverParameters, Collection descriptors) { @@ -237,16 +214,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor return false; } - private void addTask(@NotNull List> result, - @NotNull Collection> candidates, - @NotNull final BasicResolutionContext context, - @NotNull JetReferenceExpression functionReference, - @NotNull Predicate> filterStrategy) { - Collection> filteredCandidates = Collections2.filter(candidates, filterStrategy); - if (filteredCandidates.isEmpty()) return; - result.add(new ResolutionTask(filteredCandidates, functionReference, context)); - } - @NotNull protected abstract Collection getNonExtensionsByName(JetScope scope, String name); diff --git a/compiler/testData/codegen/classes/resolveOrder.jet b/compiler/testData/codegen/classes/resolveOrder.jet new file mode 100644 index 00000000000..563859f6e8e --- /dev/null +++ b/compiler/testData/codegen/classes/resolveOrder.jet @@ -0,0 +1,53 @@ +fun box() : String { + if (!B().test()) return "fail 1"; + if (!D().test()) return "fail 2" + if (!L().test()) return "fail 4" + if (!N().test()) return "fail 5" + return "OK" +} + +class A { + fun foo() = 1 +} + +class B { + fun foo() = 2 + + fun A.bar() = foo() + + fun test() = A().bar() == 1 +} + + +class C { + fun D.foo() = 2 +} + +class D { + fun C.foo() = 1 + + fun C.bar() = foo() + + fun test() = C().bar() == 1 +} + + +class M +fun M.foo() = 2 + +class N { + fun M.foo() = 1 + + fun M.bar() = foo() + + fun test() = M().bar() == 1 +} + +class K +class L { + fun K.bar() = foo() + + fun test() = K().bar() == 1 +} +fun K.foo() = 1 +fun L.foo() = 2 diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 39c5a782e34..e81e633ff92 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -312,4 +312,8 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("regressions/kt1538.kt"); System.out.println(generateToText()); } + + public void testResolveOrder() throws Exception { + blackBoxFile("classes/resolveOrder.jet"); + } }