Stream: t-compiler

Topic: Why Needs is propagated to a receiver in check_method_call?


Vlad (Jan 30 2020 at 17:26, on Zulip):

If method call is in Needs::MutPlace context (e.g. *(foo.bar()) = 1;), Needs::MutPlace is propagated to receiver expression foo (see check_method_call).
But then, if autoref to &mut occurs, such Needs (effectively) overwritten in convert_place_derefs_to_mutable. So why Needs is propagated to a receiver in check_method_call? It looks like it just shouldn't.

I made an example when such propagation leads to using index_mut when it does not need and to false-positive E0596.

Setup:

struct S;
impl S {
    // Note `&self`, not `&mut self`!
    fn foo(&self) -> &'static mut i32 {
        Box::leak(Box::new(1))
    }
}

struct Indexable;

impl std::ops::Index<u8> for Indexable {
    type Output = S;

    fn index(&self, index: u8) -> &Self::Output {
        println!("non mut");
        Box::leak(Box::new(S))
    }
}
impl std::ops::IndexMut<u8> for Indexable {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        println!("mut");
        Box::leak(Box::new(S))
    }
}

This code uses index_mut (why?)

fn main() {
    let a = &mut Indexable;
    *(a[0].foo()) = 1;
}

This code produces E0596 (but looks it shouldn't)

fn main() {
    let a = &Indexable;
    *(a[0].foo()) = 1;
}

This can be compiled if write

fn main() {
    let a = &Indexable;
    *((&a[0]).foo()) = 1;
}
Vlad (Feb 17 2020 at 09:03, on Zulip):

@nikomatsakis

Last update: Jun 07 2020 at 10:30UTC