-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Don't suggest ref
for let
bindings.
#40402
Comments
First, would you prefer to just stop hinting about Second, for the simple case, do you think we should hint something like "consider |
Fixing this requires doing a bit of plumbing. I don't have time to get into every detail so let me just jot down some notes about how the code works today (I was just reading it).
So the most direct fix would be to notice that the pattern is in a let and set the field to Anyway, that's a bit dense, I can try to expand some in a follow-up comments later on. |
Hi. Will take this up. |
I am mostly thinking about the former, that is, the latter is idiomatic use of
That would be great. |
Expanding on my directions. I think that the first step would be to get more familiar with the HIR, which is the primary data structure that the compiler uses to encode the program it is compiling. The HIR reflects a lightly desugared view of Rust syntax (i.e., some constructs -- like One downside of the HIR is that sometimes there are many equivalent ways to write things. In this case, for example, these two are equivalent: let ref x = v[0];
let x = &v[0]; To help later passes that do analysis, therefore, there is a bit of code called the In any case, the summary here is that, at the time we report this error, we are in some code that received a callback from the EUV saying, effectively, " Right now, whenever a move resulted from a pattern -- any kind of pattern -- we report the same suggestion ("add To do this, we're going to want to use the HIR map. In particular, the HIR map allows one to walk upwards from a HIR node to see its parents: if we walk upward from the pattern
Every node in the HIR has a unique id (called its /// Where can patterns ultimately be used?
pub enum PatternSource<'hir> {
MatchExpr(&'hir hir::Expr),
LetDecl(&'hir hir::Local),
}
// Note: this impl already exists... I'm just adding a method
impl<'hir> Map<'hir> {
...
/// Determines whether a pattern is located within a `let` statement or a `match` expression.
///
/// Returns `Some(true)` if `id`
pub fn get_pattern_source(&self, pat: &hir::Pat) -> PatternSource<'hir> {
let result = self.walk_parent_nodes(pat.id, |node| match *node {
NodePat(_) => false, // keep walking as long as we are in a pattern
_ => true, // stop walking once we exit patterns
}).expect("never found a parent for the pattern");
match result {
NodeExpr(ref e) => {
// the enclosing expression must be a `match`
assert!(match e.node { ExprMatch(..) => true, _ => false });
PatternSource::MatchExpr(e)
}
NodeStmt(ref s) => {
// the enclosing statement must be a `let`
match s.node {
StmtDecl(ref decl, _) => {
match decl.kind {
DeclLocal(ref local) => Some(PatternSource::LetDecl(decl)),
_ => span_bug!(s.span, "expected pattern to be in a `let` statement"),
}
}
_ => span_bug!(s.span, "expected pattern to be in a `let` statement"),
}
}
_ => span_bug!(s.span, "pattern in unexpected location {:?}", result)
}
} Anyway, that's roughly how it should look. I think I actually forgot a case or two but we'll figure out as we go. Then the next thing to do would be to call this function from within the borrow checker (which is where the error is being reported). Specifically, I would add a call in the pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>,
move_error_collector: &mut MoveErrorCollector<'tcx>,
move_pat: &hir::Pat,
cmt: mc::cmt<'tcx>) {
let source = bccx.tcx.hir.get_pattern_source(move_pat);
debug!("gather_move_from_pat: move_pat={:?} source={:?}", move_pat, source);
} (The The idea here is just to invoke your code and see if it panics etc. OK, that's enough for now. =) Let's try to get that far... once we get it building, you should be able to inspect the output by running
Then you can skim for that |
@nikomatsakis I tried coding up the I have worked with Rust before, but I don't have much experience with lifetimes, and therefore I'm getting stuck on line 19, where the compiler throws an error saying that |
@cynicaldevil There's no point in cloning HIR nodes. You can always take a reference to them that has lifetime |
@arielb1 Thanks, I solved it at last. Turns out, the whole problem was unrelated to lifetimes, I was actually having trouble extracting a value from a smart pointer, and was using the |
@cynicaldevil sorry I've been unresponsive; been busy traveling around, hopefully better now. =) Everything working out ok? |
@nikomatsakis no worries :) As you can see, I'm blocked because of #41169 now, so I don't know how to proceed further. |
@cynicaldevil I see -- I can leave some comments on that issue to suggest how to resolve it. However, I also think that @gaurikholkar is still actively working on this as well... seems like a shame to duplicate effort. Not sure how far they have gotten. |
Right now, I have written the
it suggests
while for
it suggests
as we are only disabling the ref hint if let is the immediate parent node here I have written UI tests as follows |
Disable ref hint for pattern in let and adding ui tests #40402 A fix to #40402 The `to prevent move, use ref e or ref mut e ` has been disabled. ``` fn main() { let v = vec![String::from("oh no")]; let e = v[0]; } ``` now gives ``` error[E0507]: cannot move out of indexed content --> example.rs:4:13 | 4 | let e = v[0]; | ^^^^ cannot move out of indexed content error: aborting due to previous error ``` I have added ui tests for the same and also modified a compile-fail test.
Consider changing to & for let bindings rust-lang#40402 This is a fix for rust-lang#40402 For the example ``` fn main() { let v = vec![String::from("oh no")]; let e = v[0]; } ``` It gives ``` error[E0507]: cannot move out of indexed content --> ex1.rs:4:13 | 4 | let e = v[0]; | ^^^^ cannot move out of indexed content | = help: consider changing to `&v[0]` error: aborting due to previous error ``` Another alternative is ``` error[E0507]: cannot move out of indexed content --> ex1.rs:4:13 | 4 | let e = v[0]; | ^^^^ consider changing to `&v[0]` error: aborting due to previous error ``` Also refer to rust-lang#41564 for more details. r? @nikomatsakis
This was fixed in #41564 and #41640. Thanks @gaurikholkar! |
UPDATE: There are some initial mentoring instructions below.
suggests
let ref e
is not idiomatic here, so this is misleading (and confusing, frankly)cc @eevee
The text was updated successfully, but these errors were encountered: