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;
|
package org.jetbrains.jet.lang.resolve.calls;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Collections2;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.psi.JetSuperExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
|
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.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
@@ -79,8 +77,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor
|
|||||||
@NotNull
|
@NotNull
|
||||||
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull BasicResolutionContext context, @NotNull String name,
|
public List<ResolutionTask<D>> computePrioritizedTasks(@NotNull BasicResolutionContext context, @NotNull String name,
|
||||||
@NotNull JetReferenceExpression functionReference) {
|
@NotNull JetReferenceExpression functionReference) {
|
||||||
List<ResolutionTask<D>> result = Lists.newArrayList();
|
|
||||||
|
|
||||||
ReceiverDescriptor explicitReceiver = context.call.getExplicitReceiver();
|
ReceiverDescriptor explicitReceiver = context.call.getExplicitReceiver();
|
||||||
final JetScope scope;
|
final JetScope scope;
|
||||||
if (explicitReceiver.exists() && explicitReceiver.getType() instanceof NamespaceType) {
|
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());
|
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,
|
private void doComputeTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver,
|
||||||
@NotNull String name, @NotNull List<ResolutionTask<D>> result,
|
@NotNull String name, @NotNull ResolutionTaskHolder<D> result,
|
||||||
@NotNull BasicResolutionContext context, @NotNull JetReferenceExpression functionReference,
|
@NotNull BasicResolutionContext context) {
|
||||||
@NotNull Predicate<ResolvedCallImpl<D>> filterStrategy) {
|
|
||||||
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext());
|
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, context.trace.getBindingContext());
|
||||||
DataFlowInfo dataFlowInfo = autoCastService.getDataFlowInfo();
|
|
||||||
List<ReceiverDescriptor> implicitReceivers = Lists.newArrayList();
|
List<ReceiverDescriptor> implicitReceivers = Lists.newArrayList();
|
||||||
scope.getImplicitReceiversHierarchy(implicitReceivers);
|
scope.getImplicitReceiversHierarchy(implicitReceivers);
|
||||||
if (receiver.exists()) {
|
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);
|
convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getReceiverSuper(receiver) != null) {
|
result.addLocalExtensions(locals);
|
||||||
// If the call is of the form super.foo(), it can actually be only a member
|
result.addMembers(members);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
||||||
Collection<D> memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name);
|
Collection<D> memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name);
|
||||||
List<ReceiverDescriptor> variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver);
|
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 {
|
else {
|
||||||
Collection<ResolvedCallImpl<D>> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), getNonExtensionsByName(scope, name));
|
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
|
//noinspection unchecked,RedundantTypeArguments
|
||||||
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
|
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
|
||||||
|
|
||||||
addTask(result, locals, context, functionReference, filterStrategy);
|
result.addLocalExtensions(locals);
|
||||||
|
result.addNonLocalExtensions(nonlocals);
|
||||||
|
|
||||||
for (ReceiverDescriptor implicitReceiver : implicitReceivers) {
|
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) {
|
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 thisObject : thisObjects) {
|
||||||
for (ReceiverDescriptor receiverParameter : receiverParameters) {
|
for (ReceiverDescriptor receiverParameter : receiverParameters) {
|
||||||
for (D extension : descriptors) {
|
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) {
|
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;
|
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
|
@NotNull
|
||||||
protected abstract Collection<D> getNonExtensionsByName(JetScope scope, String name);
|
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");
|
blackBoxFile("regressions/kt1538.kt");
|
||||||
System.out.println(generateToText());
|
System.out.println(generateToText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testResolveOrder() throws Exception {
|
||||||
|
blackBoxFile("classes/resolveOrder.jet");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user