Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New assist: Generate IndexMut implementation from Index implementation #15581

Open
kpreid opened this issue Sep 8, 2023 · 8 comments
Open

New assist: Generate IndexMut implementation from Index implementation #15581

kpreid opened this issue Sep 8, 2023 · 8 comments
Assignees
Labels
A-assists C-feature Category: feature request

Comments

@kpreid
Copy link
Contributor

kpreid commented Sep 8, 2023

Given an existing core::ops::Index implementation, this assist would generate a copy of it where

  • Index becomes IndexMut
  • The method signature is updated
  • & in the return value position in the function body (and perhaps other obviously-relevant positions) is replaced with &mut

For an example from the code I'm working on right now,

pub enum Axis { X = 0, Y = 1, Z = 2 }

impl<T> ops::Index<Axis> for [T; 3] {
    type Output = T;

    fn index(&self, index: Axis) -> &Self::Output {
        &self[index as usize]
    }
}

could be used to generate

impl<T> ops::IndexMut<Axis> for [T; 3] {
    fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
        &mut self[index as usize]
    }
}

with no manual changes instead of 6. There might be other ref/mut trait pairs that could be assisted similarly, too.

@kpreid kpreid added the C-feature Category: feature request label Sep 8, 2023
@Veykril
Copy link
Member

Veykril commented Sep 9, 2023

Borrow/BorrowMut, AsRef/AsMut come to mind here as well

@Young-Flash
Copy link
Member

I'd like to have a try

@rustbot claim

@Young-Flash
Copy link
Member

from

impl<T> ops::Index<Axis> for [T; 3] {
    type Output = T;

    fn index(&self, index: Axis) -> &Self::Output {
        &self[index as usize]
    }
}

to generate

impl<T> ops::IndexMut<Axis> for [T; 3] {
    fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
        &mut self[index as usize]
    }
}

this example is simple and easy to achieve, just replace self with mut self, but this 'replace' way isn't generic, given the following example

struct Map {
    data: HashMap<String, i32>   
}

impl Index<String> for Map {
    type Output = i32;

    fn index(&self, key: String) -> &Self::Output {
        self.data.get(&key).unwrap()
    }
}

there should generate

impl IndexMut<String> for Map {
    fn index_mut(&mut self, key: String) -> &mut Self::Output {
        self.data.get_mut(&key).unwrap()
    }
}

there problem here is that the index_mut method body may various, so there isn't a way to deal with it generally. how about just generate index_mut method body with a todo!() ? any suggestion? @Veykril @kpreid

impl IndexMut<String> for Map {
    fn index_mut(&mut self, key: String) -> &mut Self::Output {
        todo!()
    }
}

@kpreid
Copy link
Contributor Author

kpreid commented Nov 3, 2023

I think a good compromise would be to keep the Index body unchanged for IndexMut if no rules can automatically adapt it. It won't compile, but the user will probably know what to do. Placing todo!() would just make the user do the copy and paste themselves, to no particular benefit.

But there should definitely be a rewrite rule for &(...)[...] to &mut (...)[...], and perhaps other common cases. Just because the general problem is impossible doesn't mean the easy cases shouldn't be done; doing the easy cases is what assists are for.

@Young-Flash
Copy link
Member

make a rewrite rule based on rust-analyzer internal api for unpredicable index body seems complicated. I'd like to make a PR which leave the Index body unchanged for IndexMut first, and leave the rest for further consideration.

bors added a commit that referenced this issue Nov 5, 2023
feat: add generate_mut_trait_impl assist

![generate_mut_trait_impl](https://github.com/rust-lang/rust-analyzer/assets/71162630/362a5a93-e109-4ffc-996e-9b6e4f54fcfa)

Generate proper `index_mut` method body refer to `index` method body may impossible due to the unpredicable case (#15581).

Here just leave the `index_mut` method body be same as `index` method body, user can modify it manually to meet their need.
@Veykril
Copy link
Member

Veykril commented Nov 10, 2023

Can this be closed or is there something not yet covered in this issue?

@Young-Flash
Copy link
Member

I think yes, will add other ref/mut trait pair next

@alibektas
Copy link
Member

Can this be closed or is there something not yet covered in this issue?

The PR decided to leave some editing to the user as there wasn't a unified way to create IndexMut from Index. If you ask me we can add a simple routine which checks if Index uses self.array[index as u32] in its index function and if so translate it to &mut self.array.... I will do it so don't close it for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-assists C-feature Category: feature request
Projects
None yet
Development

No branches or pull requests

4 participants