Skip to content

Implicit borrows and typeclasses interact inconsistently #2796

Closed
@msullivan

Description

@msullivan

The interaction between implicit borrows and typeclasses is currently problematic and inconsistent.

Suppose we have the following interface, an implementation of it for vector slices, and a function that is parameterized over the typeclass:

iface iterable<A> {
    fn iterate(blk: fn(A) -> bool);
}

impl vec/&<A> of iterable<A> for &[const A] {
    fn iterate(f: fn(A) -> bool) {
        vec::each(self, f);
    }
}

fn print<A, T: iterable<A>>(x: T) {
    for x.iterate() |x| { log(error, x); }
}

The following code works since x will be implicitly borrowed

fn main() {
    let x = ~[1,2,3];
    for x.iterate() |x| { log(error, x) }
}

This is because add_candidates_from_scope in method.rs uses can_mk_assignty when matching against impls, which will do a borrow to convert x to a slice.

However, the following code does not work:

fn main() {
    let x = ~[1,2,3];
    print(x);
}

It will fail to find an implementation of iterable for [int]/~. This is because lookup_vtable in vtable.rs uses mk_subty when matching against impls. I think that lookup_vtable basically has to use subtyping and not type assignability: typeclass constraints need not correspond to just the type of an argument expression that we can perform a borrow on.

To make matters worse, we can't work around this by just writing impls for ~[A], since then the first example would fail with an error about multiple methods in scope.

I think probably the right thing to do is to not do implicit borrows on method calls, but I'm not sure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions