changed resolution order: first priority is 'local extensions; members; nonlocal extensions', than by implicit receivers (before was vice versa)

This commit is contained in:
Svetlana Isakova
2012-04-17 14:05:38 +04:00
parent 6ac4169003
commit 4d62fbad2b
4 changed files with 169 additions and 46 deletions
@@ -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<D extends CallableDescriptor> {
private final JetReferenceExpression reference;
private final BasicResolutionContext basicResolutionContext;
private final Predicate<ResolvedCallImpl<D>> visibleStrategy;
private final Collection<Collection<ResolvedCallImpl<D>>> localExtensions = Sets.newLinkedHashSet();
private final Collection<Collection<ResolvedCallImpl<D>>> members = Sets.newLinkedHashSet();
private final Collection<Collection<ResolvedCallImpl<D>>> nonLocalExtensions = Sets.newLinkedHashSet();
private List<ResolutionTask<D>> tasks = null;
public ResolutionTaskHolder(@NotNull JetReferenceExpression reference,
@NotNull BasicResolutionContext basicResolutionContext,
@NotNull Predicate<ResolvedCallImpl<D>> visibleStrategy) {
this.reference = reference;
this.basicResolutionContext = basicResolutionContext;
this.visibleStrategy = visibleStrategy;
}
public void addLocalExtensions(@NotNull Collection<ResolvedCallImpl<D>> candidates) {
if (!candidates.isEmpty()) {
localExtensions.add(candidates);
}
}
public void addMembers(@NotNull Collection<ResolvedCallImpl<D>> candidates) {
if (!candidates.isEmpty()) {
members.add(candidates);
}
}
public void addNonLocalExtensions(@NotNull Collection<ResolvedCallImpl<D>> candidates) {
if (!candidates.isEmpty()) {
nonLocalExtensions.add(candidates);
}
}
public List<ResolutionTask<D>> getTasks() {
if (tasks == null) {
tasks = Lists.newArrayList();
List<Collection<ResolvedCallImpl<D>>> 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<ResolvedCallImpl<D>> visibilityStrategy : Lists.newArrayList(visibleStrategy, Predicates.not(visibleStrategy))) {
for (Collection<ResolvedCallImpl<D>> candidates : candidateList) {
Collection<ResolvedCallImpl<D>> filteredCandidates = Collections2.filter(candidates, visibilityStrategy);
if (!filteredCandidates.isEmpty()) {
tasks.add(new ResolutionTask<D>(filteredCandidates, reference, basicResolutionContext));
}
}
}
}
return tasks;
}
}
@@ -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<ResolutionTask<D>> computePrioritizedTasks(@NotNull BasicResolutionContext context, @NotNull String name,
@NotNull JetReferenceExpression functionReference) {
List<ResolutionTask<D>> 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<ResolvedCallImpl<D>> invisibleStrategy = new Predicate<ResolvedCallImpl<D>>() {
@Override
public boolean apply(@Nullable ResolvedCallImpl<D> call) {
return !visibleStrategy.apply(call);
}
};
doComputeTasks(scope, explicitReceiver, name, result, context, functionReference, visibleStrategy);
doComputeTasks(scope, explicitReceiver, name, result, context, functionReference, invisibleStrategy);
return result;
ResolutionTaskHolder<D> result = new ResolutionTaskHolder<D>(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<ResolutionTask<D>> result,
@NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference,
@NotNull Predicate<ResolvedCallImpl<D>> filterStrategy) {
@NotNull String name, @NotNull ResolutionTaskHolder<D> result,
@NotNull BasicResolutionContext context) {
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext());
DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo();
List<ReceiverDescriptor> 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<D> memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name);
List<ReceiverDescriptor> 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<ResolvedCallImpl<D>> 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.<D>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<D> descriptors, Iterable<ReceiverDescriptor> thisObjects, Iterable<ReceiverDescriptor> receiverParameters, Collection<ResolvedCallImpl<D>> result) {
// Collection<ResolvedCallImpl<D>> 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 <D extends CallableDescriptor> Collection<ResolvedCallImpl<D>> convertWithImpliedThis(JetScope scope, Iterable<ReceiverDescriptor> receiverParameters, Collection<? extends D> descriptors) {
@@ -237,16 +214,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
return false;
}
private void addTask(@NotNull List<ResolutionTask<D>> result,
@NotNull Collection<ResolvedCallImpl<D>> candidates,
@NotNull final BasicResolutionContext context,
@NotNull JetReferenceExpression functionReference,
@NotNull Predicate<ResolvedCallImpl<D>> filterStrategy) {
Collection<ResolvedCallImpl<D>> filteredCandidates = Collections2.filter(candidates, filterStrategy);
if (filteredCandidates.isEmpty()) return;
result.add(new ResolutionTask<D>(filteredCandidates, functionReference, context));
}
@NotNull
protected abstract Collection<D> getNonExtensionsByName(JetScope scope, String name);
@@ -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
@@ -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");
}
}