changed local extensions priority

local extensions aren't longer chosen before members
This commit is contained in:
Svetlana Isakova
2013-06-07 13:41:57 +04:00
parent 132d74200b
commit 3cf133bff7
20 changed files with 210 additions and 203 deletions
@@ -36,9 +36,7 @@ public class ResolutionTaskHolder<D extends CallableDescriptor, F extends D> {
private final PriorityProvider<ResolutionCandidate<D>> priorityProvider;
private final boolean isSafeCall;
private final Collection<Collection<ResolutionCandidate<D>>> localExtensions = Sets.newLinkedHashSet();
private final Collection<Collection<ResolutionCandidate<D>>> members = Sets.newLinkedHashSet();
private final Collection<Collection<ResolutionCandidate<D>>> nonLocalExtensions = Sets.newLinkedHashSet();
private final Collection<Collection<ResolutionCandidate<D>>> candidatesList = Lists.newArrayList();
private List<ResolutionTask<D, F>> tasks = null;
@@ -59,44 +57,19 @@ public class ResolutionTaskHolder<D extends CallableDescriptor, F extends D> {
return candidates;
}
public void addLocalExtensions(@NotNull Collection<ResolutionCandidate<D>> candidates) {
public void addCandidates(@NotNull Collection<ResolutionCandidate<D>> candidates) {
if (!candidates.isEmpty()) {
localExtensions.add(setIsSafeCall(candidates));
}
}
public void addMembers(@NotNull Collection<ResolutionCandidate<D>> candidates) {
if (!candidates.isEmpty()) {
members.add(setIsSafeCall(candidates));
}
}
public void addNonLocalExtensions(@NotNull Collection<ResolutionCandidate<D>> candidates) {
if (!candidates.isEmpty()) {
nonLocalExtensions.add(setIsSafeCall(candidates));
candidatesList.add(setIsSafeCall(candidates));
}
}
public List<ResolutionTask<D, F>> getTasks() {
if (tasks == null) {
tasks = Lists.newArrayList();
List<Collection<ResolutionCandidate<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(basicCallResolutionContext.call.getExplicitReceiver()) != null) {
candidateList.addAll(members);
candidateList.addAll(localExtensions);
}
else {
candidateList.addAll(localExtensions);
candidateList.addAll(members);
}
candidateList.addAll(nonLocalExtensions);
for (int priority = priorityProvider.getMaxPriority(); priority >= 0; priority--) {
final int finalPriority = priority;
for (Collection<ResolutionCandidate<D>> candidates : candidateList) {
for (Collection<ResolutionCandidate<D>> candidates : candidatesList) {
Collection<ResolutionCandidate<D>> filteredCandidates = Collections2.filter(candidates, new Predicate<ResolutionCandidate<D>>() {
@Override
public boolean apply(@Nullable ResolutionCandidate<D> input) {
@@ -147,29 +147,26 @@ public class TaskPrioritizer {
if (receiver.exists()) {
List<ReceiverValue> variantsForExplicitReceiver = autoCastService.getVariantsForReceiver(receiver);
Collection<ResolutionCandidate<D>> extensionFunctions = convertWithImpliedThis(scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(scope, name));
List<ResolutionCandidate<D>> nonlocals = Lists.newArrayList();
List<ResolutionCandidate<D>> locals = Lists.newArrayList();
//noinspection unchecked,RedundantTypeArguments
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals);
Collection<ResolutionCandidate<D>> members = Lists.newArrayList();
for (ReceiverValue variant : variantsForExplicitReceiver) {
Collection<? extends D> membersForThisVariant = callableDescriptorCollector.getMembersByName(variant.getType(), name);
convertWithReceivers(membersForThisVariant, Collections.singletonList(variant), Collections.singletonList(NO_RECEIVER), members, hasExplicitThisObject);
convertWithReceivers(membersForThisVariant, Collections.singletonList(variant),
Collections.singletonList(NO_RECEIVER), members, hasExplicitThisObject);
}
result.addLocalExtensions(locals);
result.addMembers(members);
result.addCandidates(members);
for (ReceiverValue implicitReceiver : implicitReceivers) {
Collection<? extends D> memberExtensions = callableDescriptorCollector.getNonMembersByName(
implicitReceiver.getType().getMemberScope(), name);
List<ReceiverValue> variantsForImplicitReceiver = autoCastService.getVariantsForReceiver(implicitReceiver);
result.addNonLocalExtensions(convertWithReceivers(memberExtensions, variantsForImplicitReceiver, variantsForExplicitReceiver, hasExplicitThisObject));
result.addCandidates(convertWithReceivers(memberExtensions, variantsForImplicitReceiver,
variantsForExplicitReceiver, hasExplicitThisObject));
}
result.addNonLocalExtensions(nonlocals);
Collection<ResolutionCandidate<D>> extensionFunctions = convertWithImpliedThis(
scope, variantsForExplicitReceiver, callableDescriptorCollector.getNonMembersByName(scope, name));
result.addCandidates(extensionFunctions);
}
else {
Collection<ResolutionCandidate<D>> functions = convertWithImpliedThis(scope, Collections.singletonList(receiver), callableDescriptorCollector
@@ -180,12 +177,12 @@ public class TaskPrioritizer {
//noinspection unchecked,RedundantTypeArguments
TaskPrioritizer.<D>splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
result.addLocalExtensions(locals);
result.addCandidates(locals);
for (ReceiverValue implicitReceiver : implicitReceivers) {
doComputeTasks(scope, implicitReceiver, name, result, context, callableDescriptorCollector);
}
result.addNonLocalExtensions(nonlocals);
result.addCandidates(nonlocals);
}
}
@@ -1,75 +0,0 @@
fun box() : String {
if (!B().test()) return "fail 1";
if (!D().test()) return "fail 2"
if (!F().test()) return "fail 3"
if (!L().test()) return "fail 4"
if (!H().test()) return "fail 5"
if (!N().test()) return "fail 6"
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 E
fun E.foo() = 2
class F {
fun foo() = 1
fun E.bar() = foo()
fun test() = E().bar() == 1
}
class G
fun G.foo() = 2
class H {
fun G.foo() = 1
fun G.bar() = foo()
fun test() = G().bar() == 1
}
class K
class L {
fun K.bar() = foo()
fun test() = K().bar() == 1
}
fun K.foo() = 1
fun L.foo() = 2
class M
class N {
fun foo() = 1
fun M.foo() = 2
fun M.bar() = foo()
fun test() = M().bar() == 1
}
@@ -0,0 +1,9 @@
class A {
fun B.foo() = 2
}
class B {
~A.foo~fun A.foo() = 1
fun A.bar() = `A.foo`foo()
}
@@ -0,0 +1,9 @@
class A
class B {
fun A.bar() = `A.foo`foo()
}
~A.foo~fun A.foo() = 1
fun B.foo() = 2
@@ -0,0 +1,7 @@
class A
class B {
fun foo() = 1
~A.foo~fun A.foo() = 2
fun A.bar() = `A.foo`foo()
}
@@ -0,0 +1,8 @@
class A
fun A.foo() = 2
class B {
~foo~fun A.foo() = 1
fun A.bar() = `foo`foo()
}
@@ -0,0 +1,16 @@
class A {
fun foo() = 1
}
class B {
}
~B.foo~fun B.foo() = 2
fun test(a: A, b: B) {
with (a) {
with (b) {
`B.foo`foo()
}
}
}
fun <T, R> with(receiver: T, f: T.() -> R) : R = receiver.f()
@@ -0,0 +1,12 @@
class A {
}
~extension~fun A.foo() = 1
fun foo() = 2
fun test(a: A) {
with (a) {
`extension`foo()
}
}
fun <T, R> with(receiver: T, f: T.() -> R) : R = receiver.f()
@@ -0,0 +1,8 @@
class A {
fun foo() = 1
fun test() {
fun ~local~foo() = 2
`local`foo()
}
}
@@ -0,0 +1,9 @@
class A {
fun ~member~foo() = 1
fun test() {
this.`member`foo()
}
}
fun A.foo() = 2
@@ -0,0 +1,10 @@
class A {
fun ~member~foo() = 1
fun test() {
this.`member`foo()
}
fun A.foo() = 2
}
@@ -0,0 +1,13 @@
class A {
fun ~member~foo() = 1
}
fun A.foo() = 2
fun test(a: A) {
with (a) {
this.`member`foo()
}
}
fun <T, R> with(receiver: T, f: T.() -> R) : R = receiver.f()
@@ -0,0 +1,8 @@
class A {
fun ~member~foo() = 1
fun test() {
fun A.foo() = 2
this.`member`foo()
}
}
@@ -0,0 +1,9 @@
class A {
~A.foo~fun foo() = 1
}
class B {
fun foo() = 2
fun A.bar() = `A.foo`foo()
}
@@ -0,0 +1,9 @@
class A
class B {
fun foo() = 2
fun A.bar() = `A.foo`foo()
}
~A.foo~fun A.foo() = 1
@@ -1105,11 +1105,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest("compiler/testData/codegen/box/classes/propertyInInitializer.kt");
}
@TestMetadata("resolveOrder.kt")
public void testResolveOrder() throws Exception {
doTest("compiler/testData/codegen/box/classes/resolveOrder.kt");
}
@TestMetadata("rightHandOverride.kt")
public void testRightHandOverride() throws Exception {
doTest("compiler/testData/codegen/box/classes/rightHandOverride.kt");
@@ -162,15 +162,80 @@ public class JetResolveTestGenerated extends AbstractResolveTest {
public void testAllFilesPresentInCandidatesPriority() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/resolve/candidatesPriority"), Pattern.compile("^(.+)\\.resolve$"), true);
}
@TestMetadata("classObjectOuterResolve.resolve")
public void testClassObjectOuterResolve() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/classObjectOuterResolve.resolve");
}
@TestMetadata("preferImplicitThisToNoReceiver.resolve")
public void testPreferImplicitThisToNoReceiver() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/preferImplicitThisToNoReceiver.resolve");
@TestMetadata("closerReceiver1.resolve")
public void testCloserReceiver1() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/closerReceiver1.resolve");
}
@TestMetadata("closerReceiver2.resolve")
public void testCloserReceiver2() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/closerReceiver2.resolve");
}
@TestMetadata("closerReceiver3.resolve")
public void testCloserReceiver3() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/closerReceiver3.resolve");
}
@TestMetadata("closerScope.resolve")
public void testCloserScope() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/closerScope.resolve");
}
@TestMetadata("extensionToCloserReceiverVsMember.resolve")
public void testExtensionToCloserReceiverVsMember() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/extensionToCloserReceiverVsMember.resolve");
}
@TestMetadata("implicitThisVsNoReceiver.resolve")
public void testImplicitThisVsNoReceiver() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/implicitThisVsNoReceiver.resolve");
}
@TestMetadata("implicitThisVsNoReceiver2.resolve")
public void testImplicitThisVsNoReceiver2() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/implicitThisVsNoReceiver2.resolve");
}
@TestMetadata("localVsImplicitThis.resolve")
public void testLocalVsImplicitThis() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/localVsImplicitThis.resolve");
}
@TestMetadata("memberVsExtension1.resolve")
public void testMemberVsExtension1() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/memberVsExtension1.resolve");
}
@TestMetadata("memberVsExtension2.resolve")
public void testMemberVsExtension2() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/memberVsExtension2.resolve");
}
@TestMetadata("memberVsExtension3.resolve")
public void testMemberVsExtension3() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/memberVsExtension3.resolve");
}
@TestMetadata("memberVsLocalExtension.resolve")
public void testMemberVsLocalExtension() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/memberVsLocalExtension.resolve");
}
@TestMetadata("receiverVsThisObject.resolve")
public void testReceiverVsThisObject() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/receiverVsThisObject.resolve");
}
@TestMetadata("receiverVsThisObject2.resolve")
public void testReceiverVsThisObject2() throws Exception {
doTest("compiler/testData/resolve/candidatesPriority/receiverVsThisObject2.resolve");
}
}
@@ -1,75 +0,0 @@
fun box() : String {
if (!B().test()) return "fail 1";
if (!D().test()) return "fail 2"
if (!F().test()) return "fail 3"
if (!L().test()) return "fail 4"
if (!H().test()) return "fail 5"
if (!N().test()) return "fail 6"
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 E
fun E.foo() = 2
class F {
fun foo() = 1
fun E.bar() = foo()
fun test() = E().bar() == 1
}
class G
fun G.foo() = 2
class H {
fun G.foo() = 1
fun G.bar() = foo()
fun test() = G().bar() == 1
}
class K
class L {
fun K.bar() = foo()
fun test() = K().bar() == 1
}
fun K.foo() = 1
fun L.foo() = 2
class M
class N {
fun foo() = 1
fun M.foo() = 2
fun M.bar() = foo()
fun test() = M().bar() == 1
}