Fix 'assign to data in an index of' collection suggestions#152216
Fix 'assign to data in an index of' collection suggestions#152216GTimothy wants to merge 5 commits intorust-lang:mainfrom
Conversation
|
rustbot has assigned @JonathanBrouwer. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
8034656 to
2371906
Compare
|
oops, meant to title "Fix 'assign to data in an index of' map suggestions" edit for clarity: for now, these suggestions only apply to BTreeMap and HashMap. rust/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs Lines 657 to 661 in fef627b |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
0fedd40 to
77c2a6e
Compare
This comment has been minimized.
This comment has been minimized.
splits the large triple suggestion into three sets them to MaybeIncorrect automatically determines the required borrowing to use.
77c2a6e to
5d997ef
Compare
|
@JonathanBrouwer, I think this is ready for review. Do I need to change anything? Thanks in advance. |
|
I'll take a look sometime in the next few days :) |
| /// Simplified to counting only | ||
| /// Peels off all references on the type. Returns the number of references | ||
| /// removed. | ||
| fn count_ty_refs<'tcx>(ty: Ty<'tcx>) -> usize { |
There was a problem hiding this comment.
Does it makes sense to put this as a method on Ty?
There was a problem hiding this comment.
Maybe, if counting references could be useful in other places? I did not want to touch too many places in the code base, but since there is https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs, it could fit fine there.
| ref_depth_difference = index_ref_depth - key_ref_depth; //index should | ||
| //be deeper than key | ||
| } else { | ||
| // no type ? |
There was a problem hiding this comment.
Is this else branch even reachable?
Since this runs strictly after type checking I'd expect not.
We can use expr_ty instead of expr_ty_opt in this case
| { | ||
| let index_ref_depth = count_ty_refs(index_ty); | ||
| ref_depth_difference = index_ref_depth - key_ref_depth; //index should | ||
| //be deeper than key |
There was a problem hiding this comment.
Why is this necessarily true?
There was a problem hiding this comment.
It is not, you are right to ask, there is a big issue here I think:
impl<K, Q: ?Sized, V, S> Index<&Q> for HashMap<K, V, S>
where
K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash,
S: BuildHasher,
{
type Output = V;Let look at for example:
#[derive(PartialEq, Eq, Hash)]
struct Bk {
inner: str,
}
impl Borrow<str> for &&&Bk {
fn borrow(&self) -> &str {
&self.inner
}
}
Then with my PR,
let mut map = HashMap::<&&&Bk, String>::new();
map["test"] = "test".to_string();
crashes the compiler, and does not suggest a fix.
here, we have index=&str and key=&&&Bk, with Q=str and K=&&&Bk:
index is a single ref and key is a triple ref => ref_depth_difference is negative
| 0 => String::from("&"), | ||
| n => "*".repeat(n - 1), | ||
| } | ||
| }; |
There was a problem hiding this comment.
This code is duplicated from above, would it be nice to deduplicate it into a function/method?
There was a problem hiding this comment.
Counting the references is common, but the suggestions for the method call branch is only get_mut which only requires one one prefix which saves one String allocations. In hindsight, that may not matter. If so, I can deduplicate.
| | | ||
| LL - map["peter"].clear(); | ||
| LL + if let Some(val) = map.get_mut("peter") { val.clear(); }; | ||
| LL + if let Some(val) = map.get_mut(&"peter") { val.clear(); }; |
There was a problem hiding this comment.
Hmmm this extra reference does not seem to be needed to make the code compile
| | | ||
| LL - map[&0] = 1; | ||
| LL + map.insert(&0, 1); | ||
| LL + map.insert(*&0, 1); |
There was a problem hiding this comment.
That is also not entirely the desired suggestion, would be nice to simplify this to map.insert(0, 1);
|
Reminder, once the PR becomes ready for a review, use |
- properly propose methods depending of the type relationship between the index used and the map key. - use whether key type is copy/clone to orient propositions.
|
thank you @JonathanBrouwer for your remarks. I had made a completely wrong assumptions about the types in questions. |
… and key is ok too for `insert` and `entry`
|
@rustbot ready |
fixes #150001
fixes rust-lang/rust-analyzer#16076
fixes #134917
The issues are threefold and linked:
collectionBTreeMap/HashMap suggests 3 solutions all marked asMachineApplicableThis PR:
MaybeIncorrectI think this solution may not be very elegant, expecially the key typechecking / borrowing part, but it works. I am however very open to any improvement/change :)
edit: edited to replace 'collection' with BTreeMap/HashMap'