about summary refs log tree commit diff
path: root/compiler/rustc_borrowck/src/diagnostics
AgeCommit message (Collapse)AuthorLines
2024-04-15Just use type_dependent_def_id to figure out what the method is for an exprMichael Goulet-26/+20
2024-04-14Consolidate two copies of ty_kind_suggestionMichael Goulet-63/+2
2024-04-13Auto merge of #122603 - estebank:clone-o-rama, r=lcnrbors-62/+481
Detect borrow checker errors where `.clone()` would be an appropriate user action When a value is moved twice, suggest cloning the earlier move: ``` error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait --> $DIR/union-move.rs:49:18 | LL | move_out(x.f1_nocopy); | ^^^^^^^^^^^ | | | cannot move out of here | move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait | help: consider cloning the value if the performance cost is acceptable | LL | move_out(x.f1_nocopy.clone()); | ++++++++ ``` When a value is borrowed by an `fn` call, consider if cloning the result of the call would be reasonable, and suggest cloning that, instead of the argument: ``` error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:53:14 | LL | let a = AffineU32(1); | - binding `a` declared here LL | let x = bat(&a); | -- borrow of `a` occurs here LL | drop(a); | ^ move out of `a` occurs here LL | drop(x); | - borrow later used here | help: consider cloning the value if the performance cost is acceptable | LL | let x = bat(&a).clone(); | ++++++++ ``` otherwise, suggest cloning the argument: ``` error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:59:14 | LL | let a = ClonableAffineU32(1); | - binding `a` declared here LL | let x = foo(&a); | -- borrow of `a` occurs here LL | drop(a); | ^ move out of `a` occurs here LL | drop(x); | - borrow later used here | help: consider cloning the value if the performance cost is acceptable | LL - let x = foo(&a); LL + let x = foo(a.clone()); | ``` This suggestion doesn't attempt to square out the types between what's cloned and what the `fn` expects, to allow the user to make a determination on whether to change the `fn` call or `fn` definition themselves. Special case move errors caused by `FnOnce`: ``` error[E0382]: use of moved value: `blk` --> $DIR/once-cant-call-twice-on-heap.rs:8:5 | LL | fn foo<F:FnOnce()>(blk: F) { | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | note: `FnOnce` closures can only be called once --> $DIR/once-cant-call-twice-on-heap.rs:6:10 | LL | fn foo<F:FnOnce()>(blk: F) { | ^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | blk(); | ----- this value implements `FnOnce`, which causes it to be moved when called ``` Account for redundant `.clone()` calls in resulting suggestions: ``` error[E0507]: cannot move out of dereference of `S` --> $DIR/needs-clone-through-deref.rs:15:18 | LL | for _ in self.clone().into_iter() {} | ^^^^^^^^^^^^ ----------- value moved due to this method call | | | move occurs because value has type `Vec<usize>`, which does not implement the `Copy` trait | note: `into_iter` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | LL | for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {} | ++++++++++++++++++++++++++++++ ~ ``` We use the presence of `&mut` values in a move error as a proxy for the user caring about side effects, so we don't emit a clone suggestion in that case: ``` error[E0505]: cannot move out of `s` because it is borrowed --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 | LL | let mut s = "hello".to_string(); | ----- binding `s` declared here LL | let rs = &mut s; | ------ borrow of `s` occurs here ... LL | f[s] = 10; | ^ move out of `s` occurs here ... LL | use_mut(rs); | -- borrow later used here ``` We properly account for `foo += foo;` errors where we *don't* suggest `foo.clone() += foo;`, instead suggesting `foo += foo.clone();`. --- Each commit can be reviewed in isolation. There are some "cleanup" commits, but kept them separate in order to show *why* specific changes were being made, and their effect on tests' output. Fix #49693, CC #64167.
2024-04-12review commentsEsteban Küber-8/+36
Added comments and reworded messages
2024-04-12Better account for more cases involving closuresEsteban Küber-14/+36
2024-04-12Fix rebaseEsteban Küber-2/+2
2024-04-12Rollup merge of #123599 - matthiaskrgr:rm, r=cjgillotMatthias Krüger-1/+1
remove some things that do not need to be
2024-04-11Rollup merge of #123523 - estebank:issue-123414, r=BoxyUwUMatthias Krüger-35/+54
Account for trait/impl difference when suggesting changing argument from ref to mut ref Do not ICE when encountering a lifetime error involving an argument with an immutable reference of a method that differs from the trait definition. Fix #123414.
2024-04-11remove some things that do not need to beMatthias Krüger-1/+1
2024-04-11Mention when the type of the moved value doesn't implement `Clone`Esteban Küber-2/+13
2024-04-11Account for move error in the spread operator on struct literalsEsteban Küber-11/+107
We attempt to suggest an appropriate clone for move errors on expressions like `S { ..s }` where a field isn't `Copy`. If we can't suggest, we still don't emit the incorrect suggestion of `S { ..s }.clone()`. ``` error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait --> $DIR/borrowck-struct-update-with-dtor.rs:28:19 | LL | let _s2 = S { a: 2, ..s0 }; | ^^^^^^^^^^^^^^^^ | | | cannot move out of here | move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait | help: clone the value from the field instead of using the spread operator syntax | LL | let _s2 = S { a: 2, c: s0.c.clone(), ..s0 }; | +++++++++++++++++ ``` ``` error[E0509]: cannot move out of type `S<()>`, which implements the `Drop` trait --> $DIR/borrowck-struct-update-with-dtor.rs:20:19 | LL | let _s2 = S { a: 2, ..s0 }; | ^^^^^^^^^^^^^^^^ | | | cannot move out of here | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait | note: `B` doesn't implement `Copy` or `Clone` --> $DIR/borrowck-struct-update-with-dtor.rs:4:1 | LL | struct B; | ^^^^^^^^ help: if `B` implemented `Clone`, you could clone the value from the field instead of using the spread operator syntax | LL | let _s2 = S { a: 2, b: s0.b.clone(), ..s0 }; | +++++++++++++++++ ```
2024-04-11Better account for `FnOnce` in move errorsEsteban Küber-7/+72
``` error[E0382]: use of moved value: `blk` --> $DIR/once-cant-call-twice-on-heap.rs:8:5 | LL | fn foo<F:FnOnce()>(blk: F) { | --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait LL | blk(); | ----- `blk` moved due to this call LL | blk(); | ^^^ value used here after move | note: `FnOnce` closures can only be called once --> $DIR/once-cant-call-twice-on-heap.rs:6:10 | LL | fn foo<F:FnOnce()>(blk: F) { | ^^^^^^^^ `F` is made to be an `FnOnce` closure here LL | blk(); | ----- this value implements `FnOnce`, which causes it to be moved when called ```
2024-04-11Account for assign binops in clone suggestionsEsteban Küber-2/+32
Explicitly look for `expr += other_expr;` and avoid suggesting `expr.clone() += other_expr;`, instead suggesting `expr += other_expr.clone();`.
2024-04-11When possible, suggest cloning the result of a call instead of an argumentEsteban Küber-13/+92
``` error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/variance-issue-20533.rs:28:14 | LL | let a = AffineU32(1); | - binding `a` declared here LL | let x = foo(&a); | -- borrow of `a` occurs here LL | drop(a); | ^ move out of `a` occurs here LL | drop(x); | - borrow later used here | help: consider cloning the value if the performance cost is acceptable | LL | let x = foo(&a).clone(); | ++++++++ ```
2024-04-11Do not recomment cloning explicit `&mut` expressionsEsteban Küber-0/+5
2024-04-11Fix accuracy of `T: Clone` check in suggestionEsteban Küber-0/+1
2024-04-11Remove unnecessary argument from `suggest_cloning`Esteban Küber-21/+9
2024-04-11Silence redundant clone suggestionEsteban Küber-0/+5
2024-04-11More move error suggestions to cloneEsteban Küber-0/+4
``` error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure --> $DIR/issue-87456-point-to-closure.rs:10:28 | LL | let val = String::new(); | --- captured outer variable LL | LL | take_mut(|| { | -- captured by this `FnMut` closure LL | LL | let _foo: String = val; | ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here | LL | let _foo: String = &val; | + help: consider cloning the value if the performance cost is acceptable | LL | let _foo: String = val.clone(); | ++++++++ ```
2024-04-11Suggest `.clone()` in some move errorsEsteban Küber-0/+10
``` error[E0507]: cannot move out of `*x` which is behind a shared reference --> $DIR/borrowck-fn-in-const-a.rs:6:16 | LL | return *x | ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait | help: consider cloning the value if the performance cost is acceptable | LL - return *x LL + return x.clone() | ```
2024-04-11Account for unops when suggesting cloningEsteban Küber-19/+24
2024-04-11Suggest `.clone()` when moved while borrowedEsteban Küber-17/+56
2024-04-11Account for `.clone()` when suggesting `<T as Clone>::clone`Esteban Küber-2/+33
2024-04-11Rollup merge of #123704 - estebank:diag-changes, r=compiler-errorsMatthias Krüger-26/+70
Tweak value suggestions in `borrowck` and `hir_analysis` Unify the output of `suggest_assign_value` and `ty_kind_suggestion`. Ideally we'd make these a single function, but doing so would likely require modify the crate dependency tree.
2024-04-10Handle more cases of "values to suggest" given a typeEsteban Küber-3/+16
Add handling for `String`, `Box`, `Option` and `Result`.
2024-04-10Handle more cases of value suggestionsEsteban Küber-18/+51
2024-04-10Use trait solver to answer questions instead of manually writing a trait solverOli Scherer-79/+22
2024-04-09Tweak value suggestions in `borrowck` and `hir_analysis`Esteban Küber-10/+8
Unify the output of `suggest_assign_value` and `ty_kind_suggestion`. Ideally we'd make these a single function, but doing so would likely require modify the crate dependency tree.
2024-04-06Account for trait/impl difference when suggesting changing argument from ref ↵Esteban Küber-35/+54
to mut ref Do not ICE when encountering a lifetime error involving an argument with an immutable reference of a method that differs from the trait definition. Fix #123414.
2024-04-05Provide suggestion to dereference closure tail if appropriateEsteban Küber-4/+210
When encoutnering a case like ```rust //@ run-rustfix use std::collections::HashMap; fn main() { let vs = vec![0, 0, 1, 1, 3, 4, 5, 6, 3, 3, 3]; let mut counts = HashMap::new(); for num in vs { let count = counts.entry(num).or_insert(0); *count += 1; } let _ = counts.iter().max_by_key(|(_, v)| v); ``` produce the following suggestion ``` error: lifetime may not live long enough --> $DIR/return-value-lifetime-error.rs:13:47 | LL | let _ = counts.iter().max_by_key(|(_, v)| v); | ------- ^ returning this value requires that `'1` must outlive `'2` | | | | | return type of closure is &'2 &i32 | has type `&'1 (&i32, &i32)` | help: dereference the return value | LL | let _ = counts.iter().max_by_key(|(_, v)| **v); | ++ ``` Fix #50195.
2024-03-30Stop calling visitors VMichael Goulet-3/+12
2024-03-29Rollup merge of #123188 - klensy:clippy-me2, r=NilstriebMatthias Krüger-10/+10
compiler: fix few unused_peekable and needless_pass_by_ref_mut clippy lints This fixes few instances of `unused_peekable` and `needless_pass_by_ref_mut`. While i expected to fix more warnings, `needless_pass_by_ref_mut` produced too much for one PR, so i stopped here. Better reviewed commit by commit, as fixes splitted by chunks.
2024-03-28and few moreklensy-10/+10
maybe bug here? warning: this argument is a mutable reference, but not used mutably --> compiler\rustc_borrowck\src\diagnostics\conflict_errors.rs:3857:35 | 3857 | pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diag<'_>) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&MirBorrowckCtxt<'_, 'tcx>` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut warning: this argument is a mutable reference, but not used mutably --> compiler\rustc_borrowck\src\type_check\liveness\trace.rs:601:17 | 601 | typeck: &mut TypeChecker<'_, 'tcx>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&TypeChecker<'_, 'tcx>` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
2024-03-27Implement `mut ref`/`mut ref mut`Jules Bertholet-10/+9
2024-03-26Rollup merge of #122589 - wutchzone:121547, r=compiler-errorsMatthias Krüger-3/+13
Fix diagnostics for async block cloning Closes #121547 r? diagnostics
2024-03-23Simplify an iterator search in borrowck diagJosh Stone-11/+9
Rather than `.into_iter().rev().find_position(...)`, this case can simply call `.iter().rposition(...)`.
2024-03-23Fix typosDaniel Sedlak-3/+3
2024-03-23Fix diagnostics for async block cloningDaniel Sedlak-0/+10
2024-03-23Rollup merge of #122780 - GuillaumeGomez:rename-hir-local, r=oli-obkMatthias Krüger-6/+6
Rename `hir::Local` into `hir::LetStmt` Follow-up of #122776. As discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Improve.20naming.20of.20.60ExprKind.3A.3ALet.60.3F). I made this change into a separate PR because I'm less sure about this change as is. For example, we have `visit_local` and `LocalSource` items. Is it fine to keep these two as is (I supposed it is but I prefer to ask) or not? Having `Node::Local(LetStmt)` makes things more explicit but is it going too far? r? ```@oli-obk```
2024-03-22Rename `hir::Node::Local` into `hir::Node::LetStmt`Guillaume Gomez-3/+3
2024-03-22Rename `hir::Local` into `hir::LetStmt`Guillaume Gomez-5/+5
2024-03-22Make RawPtr take Ty and Mutbl separatelyMichael Goulet-5/+5
2024-03-22Programmatically convert some of the pat ctorsMichael Goulet-1/+1
2024-03-20Split item bounds and item super predicatesMichael Goulet-1/+1
2024-03-19Fix incorrect mutable suggestion information for binding in ref pattern.surechen-13/+24
For ref pattern in func param, the mutability suggestion has to apply to the binding. For example: `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)` fixes #122415
2024-03-17Move `suggest_hoisting_call_outside_loop` out of `suggest_cloning`Esteban Küber-6/+3
2024-03-17Move `Visitor` impl out to the `mod` levelEsteban Küber-22/+22
2024-03-17Point at `continue` and `break` that might be in the wrong placeEsteban Küber-33/+130
Sometimes move errors are because of a misplaced `continue`, but we didn't surface that anywhere. Now when there are more than one set of nested loops we show them out and point at the `continue` and `break` expressions within that might need to go elsewhere. ``` error[E0382]: use of moved value: `foo` --> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18 | LL | for foo in foos { | --- | | | this reinitialization might get skipped | move occurs because `foo` has type `String`, which does not implement the `Copy` trait ... LL | for bar in &bars { | ---------------- inside of this loop ... LL | baz.push(foo); | --- value moved here, in previous iteration of loop ... LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17 | LL | for foo in foos { | --------------- ... LL | for bar in &bars { | ---------------- ... LL | continue; | ^^^^^^^^ this `continue` advances the loop at line 33 help: consider moving the expression out of the loop so it is only moved once | LL ~ let mut value = baz.push(foo); LL ~ for bar in &bars { LL | ... LL | if foo == *bar { LL ~ value; | help: consider cloning the value if the performance cost is acceptable | LL | baz.push(foo.clone()); | ++++++++ ``` Fix #92531.
2024-03-17Detect when move of `!Copy` value occurs within `loop` and should likely not ↵Esteban Küber-2/+160
be cloned When encountering a move error on a value within a loop of any kind, identify if the moved value belongs to a call expression that should not be cloned and avoid the semantically incorrect suggestion. Also try to suggest moving the call expression outside of the loop instead. ``` error[E0382]: use of moved value: `vec` --> $DIR/recreating-value-in-loop-condition.rs:6:33 | LL | let vec = vec!["one", "two", "three"]; | --- move occurs because `vec` has type `Vec<&str>`, which does not implement the `Copy` trait LL | while let Some(item) = iter(vec).next() { | ----------------------------^^^-------- | | | | | value moved here, in previous iteration of loop | inside of this loop | note: consider changing this parameter type in function `iter` to borrow instead if owning the value isn't necessary --> $DIR/recreating-value-in-loop-condition.rs:1:17 | LL | fn iter<T>(vec: Vec<T>) -> impl Iterator<Item = T> { | ---- ^^^^^^ this parameter takes ownership of the value | | | in this function help: consider moving the expression out of the loop so it is only moved once | LL ~ let mut value = iter(vec); LL ~ while let Some(item) = value.next() { | ``` We use the presence of a `break` in the loop that would be affected by the moved value as a heuristic for "shouldn't be cloned". Fix #121466.
2024-03-15Rollup merge of #122254 - estebank:issue-48677, r=oli-obkMatthias Krüger-15/+121
Detect calls to .clone() on T: !Clone types on borrowck errors When encountering a lifetime error on a type that *holds* a type that doesn't implement `Clone`, explore the item's body for potential calls to `.clone()` that are only cloning the reference `&T` instead of `T` because `T: !Clone`. If we find this, suggest `T: Clone`. ``` error[E0502]: cannot borrow `*list` as mutable because it is also borrowed as immutable --> $DIR/clone-on-ref.rs:7:5 | LL | for v in list.iter() { | ---- immutable borrow occurs here LL | cloned_items.push(v.clone()) | ------- this call doesn't do anything, the result is still `&T` because `T` doesn't implement `Clone` LL | } LL | list.push(T::default()); | ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | LL | drop(cloned_items); | ------------ immutable borrow later used here | help: consider further restricting this bound | LL | fn foo<T: Default + Clone>(list: &mut Vec<T>) { | +++++++ ``` ``` error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/clone-on-ref.rs:23:10 | LL | fn qux(x: A) { | - binding `x` declared here LL | let a = &x; | -- borrow of `x` occurs here LL | let b = a.clone(); | ------- this call doesn't do anything, the result is still `&A` because `A` doesn't implement `Clone` LL | drop(x); | ^ move out of `x` occurs here LL | LL | println!("{b:?}"); | ----- borrow later used here | help: consider annotating `A` with `#[derive(Clone)]` | LL + #[derive(Clone)] LL | struct A; | ``` Fix #48677.