changed resolution order: first priority is 'local extensions; members; nonlocal extensions', than by implicit receivers (before was vice versa)
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user