-
Notifications
You must be signed in to change notification settings - Fork 1.8k
overhaul mut_mut
#15417
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
overhaul mut_mut
#15417
Conversation
rustbot has assigned @samueltardieu. Use |
//~| mut_mut | ||
} | ||
|
||
let mut z = inline!(&mut $(&mut 3u32)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I stopped the lint from firing when inside macros, because the $(&mut 3u32)
thing caused a bad suggestion:
&mut 3u32mut $(&mut u32)
should I try bringing the suggestion back, and if so, how?
"this expression mutably borrows a mutable reference. Consider reborrowing", | ||
"this expression mutably borrows a mutable reference", | ||
|diag| { | ||
diag.span_suggestion(expr.span, "reborrow instead", sugg, applicability); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my experience, not many people know about reborrowing -- maybe the message for the case that recommends it should link to some page that explains it?
Admittedly this is less necessary now that we've got a structured suggestion; people can just search for the term separately if they're interested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An important property of Clippy is that we have an unique position and people learn from Clippy's output. So, they (ideally) come to Clippy with a learner mindset.
With the suggestion, they'll assume that adding &*
is called "reborrowing"
expr.hir_id, | ||
expr.span, | ||
"generally you want to avoid `&mut &mut _` if possible", | ||
"an expression of form `&mut &mut _`", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this message helpful enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'd say that its helpful enough. What do you have in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it now just states the fact, not really explaining why having double &mut
s is bad. But I also can't come up with a concise way to explain why it's bad, probably because I can't really imagine how one would end up with such code – unlike the "&mut expr
where expr
itself has a type &mut T
" case, which can happen because you forget the type of expr
Lintcheck changes for dc534c4
This comment will be updated if you push new changes |
a81c9a6
to
c26eb82
Compare
@cmrschwarz let me know what you think! You can see the change in the diagnostic messages in the |
Just looking at the structured suggestions, this looks exactly like what I hoped for. |
Reviewer unavailable, so rerolling r? clippy |
@blyxyas friendly ping in case this flew under the radar^^ |
No, this hasn't flown through the radar Currently reviewing this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great starting patch!
loop { | ||
if !e.span.eq_ctxt(e2.span) { | ||
return; | ||
} | ||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, next) = e2.kind { | ||
(e, e2) = (e2, next); | ||
many_muts = true; | ||
} else { | ||
break; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you extract these two blocks into a function? The !e.span.eq_ctxt(..
call can be extracted into a closure passed to the function, being that we checking for context changes in types is not really useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean in order to share the peeling logic with the types case? But wouldn't that be impossible, given that we peel ExprKind
s here, but TyKind
s there?
let (mut e, mut e2) = (e, e2); | ||
let mut many_muts = false; | ||
loop { | ||
if !e.span.eq_ctxt(e2.span) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Not a problem, just record-keeping)
One might think that it's an improvement to use SpanData
instead of Span
, so we don't get the SpanData twice per each span (one for e2
being the argument, and once for it being the object that the method is called on).
But being that there aren't almost any occurences of /&mut &mut (&mut)+/
, it's probably better to avoid the cost of getting the two initial spans and pay the price at higher-mut
sites (which aren't very frequent).
expr.hir_id, | ||
expr.span, | ||
"generally you want to avoid `&mut &mut _` if possible", | ||
"an expression of form `&mut &mut _`", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'd say that its helpful enough. What do you have in mind?
This comment has been minimized.
This comment has been minimized.
for some reason this seems to already be the case with exprs, so only do it for tys
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! ❤️
"this expression mutably borrows a mutable reference. Consider reborrowing", | ||
"this expression mutably borrows a mutable reference", | ||
|diag| { | ||
diag.span_suggestion(expr.span, "reborrow instead", sugg, applicability); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An important property of Clippy is that we have an unique position and people learn from Clippy's output. So, they (ideally) come to Clippy with a learner mindset.
With the suggestion, they'll assume that adding &*
is called "reborrowing"
This PR:
_unfixable.rs
, to allow running rustfix on the main file&mut &mut &mut T
Open questions:
&mut
are useless.. but can't really come up with something consice. I very much don't like the one in the docs -- it's a bit too condescending imo.I do realize that the PR ended up being quite wide-scoped, but that's primarily because once I added structured suggestions to one of the lint cases,
ui_test
started complaining about warnings remaining after the rustfix run, which of course had to with the fact that the other two lint cases didn't actually fix the code they linted, only warned. I guessui_test
could be smarter about this, by understanding that if a warning was created without a suggestion, then that warning will still remain in the fixed file. But oh well.changelog: [
mut_mut
]: add structured suggestions, improve docsfixes #13021