From dab77c50daeb563a05b20b31527f731b683cded5 Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Thu, 27 Jun 2024 18:31:29 +0200 Subject: [PATCH 01/10] fix least significant digits of f128 associated constants While the numbers are parsed to the correct value, the decimal numbers in the source were rounded to zero instead of to the nearest, making the literals different from the values shown in the documentation. --- library/core/src/num/f128.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 58ed98c888cc6..048e3cca93d21 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -167,7 +167,7 @@ impl f128 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS #[unstable(feature = "f128", issue = "116909")] - pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128; + pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128; /// Smallest finite `f128` value. /// @@ -175,7 +175,7 @@ impl f128 { /// /// [`MAX`]: f128::MAX #[unstable(feature = "f128", issue = "116909")] - pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128; + pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128; /// Smallest positive normal `f128` value. /// /// Equal to 2[`MIN_EXP`] − 1. @@ -191,7 +191,7 @@ impl f128 { /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS /// [`MAX_EXP`]: f128::MAX_EXP #[unstable(feature = "f128", issue = "116909")] - pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128; + pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128; /// One greater than the minimum possible normal power of 2 exponent. /// From abeb7203e4c979b2446bf0cca0155427f0c46c18 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Thu, 11 Jul 2024 22:36:45 +0000 Subject: [PATCH 02/10] Add regression test for issue 127545 --- .../transforming-option-ref-issue-127545.rs | 8 ++++ ...ransforming-option-ref-issue-127545.stderr | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs index 5ba58e7427581..9125ffeeb066c 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -4,3 +4,11 @@ pub fn foo(arg: Option<&Vec>) -> Option<&[i32]> { arg //~ ERROR 5:5: 5:8: mismatched types [E0308] } + +pub fn bar(arg: Option<&Vec>) -> &[i32] { + arg.unwrap_or(&[]) //~ ERROR 9:19: 9:22: mismatched types [E0308] +} + +pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { + arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index b7c7202113a16..2d4f26c388dbe 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -14,5 +14,45 @@ LL | arg.map(|v| &**v) | ++++++++++++++ error: aborting due to 1 previous error + --> $DIR/transforming-option-ref-issue-127545.rs:9:19 + | +LL | arg.unwrap_or(&[]) + | --------- ^^^ expected `&Vec`, found `&[_; 0]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&[_; 0]` +help: the return type of this call is `&[_; 0]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:9:5 + | +LL | arg.unwrap_or(&[]) + | ^^^^^^^^^^^^^^---^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:13:19 + | +LL | arg.unwrap_or(v) + | --------- ^ expected `&Vec`, found `&[i32]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&'a [i32]` +help: the return type of this call is `&'a [i32]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:13:5 + | +LL | arg.unwrap_or(v) + | ^^^^^^^^^^^^^^-^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. From 5e1cabe98271fc79cd8ebf8e9722df781cad7aa8 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 12 Jul 2024 08:43:28 +0000 Subject: [PATCH 03/10] Add suggestion to use Option::map_or over erroneous Option::unwrap_or --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 11 ++++ .../src/fn_ctxt/suggestions.rs | 65 +++++++++++++++++++ ...ransforming-option-ref-issue-127545.stderr | 10 ++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ab0f356ce91f1..6fdf616f50e09 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -948,6 +948,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, ); + self.suggest_deref_unwrap_or( + &mut err, + error_span, + callee_ty, + call_ident, + expected_ty, + provided_ty, + provided_args[*provided_idx], + is_method, + ); + // Call out where the function is defined self.label_fn_like( &mut err, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5975c52ca46e8..15a1a18daa70a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1429,6 +1429,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } + // Suggest to change `Option<&Vec>::unwrap_or(&[])` to `Option::map_or(&[], |v| v)`. + #[instrument(level = "trace", skip(self, err, provided_expr))] + pub(crate) fn suggest_deref_unwrap_or( + &self, + err: &mut Diag<'_>, + error_span: Span, + callee_ty: Option>, + call_ident: Option, + expected_ty: Ty<'tcx>, + provided_ty: Ty<'tcx>, + provided_expr: &Expr<'tcx>, + is_method: bool, + ) { + if !is_method { + return; + } + let Some(callee_ty) = callee_ty else { + return; + }; + let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else { + return; + }; + if !self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + return; + } + + if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) { + return; + } + + let ty::Ref(_, peeled, _mutability) = provided_ty.kind() else { + return; + }; + + // NOTE: Can we reuse `suggest_deref_or_ref`? + + // Create an dummy type `&[_]` so that both &[] and `&Vec` can coerce to it. + let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind() + && let ty::Infer(_) = elem_ty.kind() + && size.try_eval_target_usize(self.tcx, self.param_env) == Some(0) + { + let slice = Ty::new_slice(self.tcx, *elem_ty); + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice) + } else { + provided_ty + }; + + if !self.can_coerce(expected_ty, dummy_ty) { + return; + } + let (provided_snip, applicability) = + match self.tcx.sess.source_map().span_to_snippet(provided_expr.span) { + Ok(snip) => (snip, Applicability::MachineApplicable), + Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect), + }; + let sugg = &format!("map_or({provided_snip}, |v| v)"); + err.span_suggestion_verbose( + error_span, + "use `Option::map_or` to deref inner value of `Option`", + sugg, + applicability, + ); + return; + } + /// Suggest wrapping the block in square brackets instead of curly braces /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 2d4f26c388dbe..90a7cfdb44962 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -13,7 +13,7 @@ help: try using `.map(|v| &**v)` to convert `Option<&Vec>` to `Option<&[i32 LL | arg.map(|v| &**v) | ++++++++++++++ -error: aborting due to 1 previous error +error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:9:19 | LL | arg.unwrap_or(&[]) @@ -32,6 +32,10 @@ LL | arg.unwrap_or(&[]) | this argument influences the return type of `unwrap_or` note: method defined here --> $SRC_DIR/core/src/option.rs:LL:COL +help: use `Option::map_or` to deref inner value of `Option` + | +LL | arg.map_or(&[], |v| v) + | ~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 @@ -52,6 +56,10 @@ LL | arg.unwrap_or(v) | this argument influences the return type of `unwrap_or` note: method defined here --> $SRC_DIR/core/src/option.rs:LL:COL +help: use `Option::map_or` to deref inner value of `Option` + | +LL | arg.map_or(v, |v| v) + | ~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors From 9c1a9e03d5e001543a21eaff5d616de8cb4e2220 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 13 Jul 2024 00:54:00 +0000 Subject: [PATCH 04/10] add test for Result<&T, _> where T; Deref --- .../transforming-option-ref-issue-127545.rs | 4 ++++ ...ransforming-option-ref-issue-127545.stderr | 22 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs index 9125ffeeb066c..f589e88f68e44 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.rs @@ -12,3 +12,7 @@ pub fn bar(arg: Option<&Vec>) -> &[i32] { pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { arg.unwrap_or(v) //~ ERROR 13:19: 13:20: mismatched types [E0308] } + +pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { + arg.unwrap_or(&[]) //~ ERROR 17:19: 17:22: mismatched types [E0308] +} diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 90a7cfdb44962..0a6d47339d8e8 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -61,6 +61,26 @@ help: use `Option::map_or` to deref inner value of `Option` LL | arg.map_or(v, |v| v) | ~~~~~~~~~~~~~~~~ -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/transforming-option-ref-issue-127545.rs:17:19 + | +LL | arg.unwrap_or(&[]) + | --------- ^^^ expected `&Vec`, found `&[_; 0]` + | | + | arguments to this method are incorrect + | + = note: expected reference `&Vec` + found reference `&[_; 0]` +help: the return type of this call is `&[_; 0]` due to the type of the argument passed + --> $DIR/transforming-option-ref-issue-127545.rs:17:5 + | +LL | arg.unwrap_or(&[]) + | ^^^^^^^^^^^^^^---^ + | | + | this argument influences the return type of `unwrap_or` +note: method defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. From 9c3c278b545d9e03939e3bfcbebb256758b9a8b9 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 13 Jul 2024 01:06:40 +0000 Subject: [PATCH 05/10] Add support for `Result<&T, _>' --- .../src/fn_ctxt/suggestions.rs | 19 +++++++++---------- ...ransforming-option-ref-issue-127545.stderr | 4 ++++ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 15a1a18daa70a..faa6d06ccaf2a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1451,9 +1451,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty::Adt(callee_adt, _) = callee_ty.peel_refs().kind() else { return; }; - if !self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + let adt_name = if self.tcx.is_diagnostic_item(sym::Option, callee_adt.did()) { + "Option" + } else if self.tcx.is_diagnostic_item(sym::Result, callee_adt.did()) { + "Result" + } else { return; - } + }; if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) { return; @@ -1484,14 +1488,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(snip) => (snip, Applicability::MachineApplicable), Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect), }; - let sugg = &format!("map_or({provided_snip}, |v| v)"); - err.span_suggestion_verbose( - error_span, - "use `Option::map_or` to deref inner value of `Option`", - sugg, - applicability, - ); - return; + let sugg = format!("map_or({provided_snip}, |v| v)"); + let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`"); + err.span_suggestion_verbose(error_span, msg, sugg, applicability); } /// Suggest wrapping the block in square brackets instead of curly braces diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 0a6d47339d8e8..1790fc1249ab7 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -80,6 +80,10 @@ LL | arg.unwrap_or(&[]) | this argument influences the return type of `unwrap_or` note: method defined here --> $SRC_DIR/core/src/result.rs:LL:COL +help: use `Result::map_or` to deref inner value of `Result` + | +LL | arg.map_or(&[], |v| v) + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors From bdc9df247841e259c24e95fd81754fb61e332c65 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 13 Jul 2024 01:18:21 +0000 Subject: [PATCH 06/10] Use multipart_suggestion to avoid place holder in span_to_snippet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CO-AUTHORED-BY: Esteban Küber --- .../src/fn_ctxt/suggestions.rs | 20 +++++++++++-------- ...ransforming-option-ref-issue-127545.stderr | 6 +++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index faa6d06ccaf2a..b3b4c5a56fbd3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1459,7 +1459,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - if call_ident.map_or(true, |ident| ident.name != sym::unwrap_or) { + let Some(call_ident) = call_ident else { + return; + }; + if call_ident.name != sym::unwrap_or { return; } @@ -1483,14 +1486,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self.can_coerce(expected_ty, dummy_ty) { return; } - let (provided_snip, applicability) = - match self.tcx.sess.source_map().span_to_snippet(provided_expr.span) { - Ok(snip) => (snip, Applicability::MachineApplicable), - Err(_) => ("/* _ */".to_owned(), Applicability::MaybeIncorrect), - }; - let sugg = format!("map_or({provided_snip}, |v| v)"); let msg = format!("use `{adt_name}::map_or` to deref inner value of `{adt_name}`"); - err.span_suggestion_verbose(error_span, msg, sugg, applicability); + err.multipart_suggestion_verbose( + msg, + vec![ + (call_ident.span, "map_or".to_owned()), + (provided_expr.span.shrink_to_hi(), ", |v| v".to_owned()), + ], + Applicability::MachineApplicable, + ); } /// Suggest wrapping the block in square brackets instead of curly braces diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 1790fc1249ab7..ad423f86ef9e3 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -35,7 +35,7 @@ note: method defined here help: use `Option::map_or` to deref inner value of `Option` | LL | arg.map_or(&[], |v| v) - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ +++++++ error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 @@ -59,7 +59,7 @@ note: method defined here help: use `Option::map_or` to deref inner value of `Option` | LL | arg.map_or(v, |v| v) - | ~~~~~~~~~~~~~~~~ + | ~~~~~~ +++++++ error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:17:19 @@ -83,7 +83,7 @@ note: method defined here help: use `Result::map_or` to deref inner value of `Result` | LL | arg.map_or(&[], |v| v) - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ +++++++ error: aborting due to 4 previous errors From ee86e2d624a61b634c14dd931b7ae2532a6634ff Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:00:42 -0400 Subject: [PATCH 07/10] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/embedded-book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/book b/src/doc/book index f1e49bf7a8ea6..67fa536768013 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc64 +Subproject commit 67fa536768013d9d5a13f3a06790521d511ef711 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 941db8b3df45f..5454de3d12b9c 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 941db8b3df45fd46cd87b50a5c86714b91dcde9c +Subproject commit 5454de3d12b9ccc6375b629cf7ccda8264640aac diff --git a/src/doc/embedded-book b/src/doc/embedded-book index b10c6acaf0f43..019f3928d8b93 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit b10c6acaf0f43481f6600e95d4b5013446e29f7a +Subproject commit 019f3928d8b939ec71b63722dcc2e46330156441 diff --git a/src/doc/reference b/src/doc/reference index 1ae3deebc3ac1..2a7931476643e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 1ae3deebc3ac16e276b6558e01420f8e605def08 +Subproject commit 2a7931476643e2a07bf9796e14bbeee3c9e589b8 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 658c6c27cb975..89aecb6951b77 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 658c6c27cb975b92227936024816986c2d3716fb +Subproject commit 89aecb6951b77bc746da73df8c9f2b2ceaad494a diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index d6e3a32a557db..0c4d55cb59fe4 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit d6e3a32a557db5902e714604def8015d6bb7e0f7 +Subproject commit 0c4d55cb59fe440d1a630e4e5774d043968edb3f From 3051436a3c5e7717c840bf04f6f147223739566b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 15 Jul 2024 10:58:58 -0700 Subject: [PATCH 08/10] Update reference to fix toolstate --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index 2a7931476643e..e2f0bdc403186 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 2a7931476643e2a07bf9796e14bbeee3c9e589b8 +Subproject commit e2f0bdc4031866734661dcdb548184bde1450baf From 317952677ad6a80b3751a075f42ffd2a8d142a84 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 13 Feb 2024 05:24:32 +0800 Subject: [PATCH 09/10] Suggest a borrow when using dbg --- .../src/diagnostics/conflict_errors.rs | 65 +++++++++- tests/ui/borrowck/dbg-issue-120327.rs | 68 ++++++++++ tests/ui/borrowck/dbg-issue-120327.stderr | 117 ++++++++++++++++++ .../dbg-macro-move-semantics.stderr | 4 + 4 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 tests/ui/borrowck/dbg-issue-120327.rs create mode 100644 tests/ui/borrowck/dbg-issue-120327.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1cb74849017ab..c7f6840e401c6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4,7 +4,7 @@ #![allow(rustc::untranslatable_diagnostic)] use either::Either; -use hir::ClosureKind; +use hir::{ClosureKind, Path}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; @@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::VarDebugInfoContents; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, @@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } } - if let Some(pat) = finder.pat { + + self.suggest_ref_for_dbg_args(expr, place, move_span, err); + + // it's useless to suggest inserting `ref` when the span don't comes from local code + if let Some(pat) = finder.pat + && !move_span.is_dummy() + && !self.infcx.tcx.sess.source_map().is_imported(move_span) + { *in_pattern = true; let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; if let Some(pat) = finder.parent_pat { @@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } + // for dbg!(x) which may take ownership, suggest dbg!(&x) instead + // but here we actually do not check whether the macro name is `dbg!` + // so that we may extend the scope a bit larger to cover more cases + fn suggest_ref_for_dbg_args( + &self, + body: &hir::Expr<'_>, + place: &Place<'tcx>, + move_span: Span, + err: &mut Diag<'infcx>, + ) { + let var_info = self.body.var_debug_info.iter().find(|info| match info.value { + VarDebugInfoContents::Place(ref p) => p == place, + _ => false, + }); + let arg_name = if let Some(var_info) = var_info { + var_info.name + } else { + return; + }; + struct MatchArgFinder { + expr_span: Span, + match_arg_span: Option, + arg_name: Symbol, + } + impl Visitor<'_> for MatchArgFinder { + fn visit_expr(&mut self, e: &hir::Expr<'_>) { + // dbg! is expanded into a match pattern, we need to find the right argument span + if let hir::ExprKind::Match(expr, ..) = &e.kind + && let hir::ExprKind::Path(hir::QPath::Resolved( + _, + path @ Path { segments: [seg], .. }, + )) = &expr.kind + && seg.ident.name == self.arg_name + && self.expr_span.source_callsite().contains(expr.span) + { + self.match_arg_span = Some(path.span); + } + hir::intravisit::walk_expr(self, e); + } + } + + let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name }; + finder.visit_expr(body); + if let Some(macro_arg_span) = finder.match_arg_span { + err.span_suggestion_verbose( + macro_arg_span.shrink_to_lo(), + "consider borrowing instead of transferring ownership", + "&", + Applicability::MachineApplicable, + ); + } + } + fn report_use_of_uninitialized( &self, mpi: MovePathIndex, diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs new file mode 100644 index 0000000000000..2de43f634877a --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.rs @@ -0,0 +1,68 @@ +fn s() -> String { + let a = String::new(); + dbg!(a); + return a; //~ ERROR use of moved value: +} + +fn m() -> String { + let a = String::new(); + dbg!(1, 2, a, 1, 2); + return a; //~ ERROR use of moved value: +} + +fn t(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return b; //~ ERROR use of moved value: +} + +fn x(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return a; //~ ERROR use of moved value: +} + +macro_rules! my_dbg { + () => { + eprintln!("[{}:{}:{}]", file!(), line!(), column!()) + }; + ($val:expr $(,)?) => { + match $val { + tmp => { + eprintln!("[{}:{}:{}] {} = {:#?}", + file!(), line!(), column!(), stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($(my_dbg!($val)),+,) + }; +} + +fn test_my_dbg() -> String { + let b: String = "".to_string(); + my_dbg!(b, 1); + return b; //~ ERROR use of moved value: +} + +fn test_not_macro() -> String { + let a = String::new(); + let _b = match a { + tmp => { + eprintln!("dbg: {}", tmp); + tmp + } + }; + return a; //~ ERROR use of moved value: +} + +fn get_expr(_s: String) {} + +fn test() { + let a: String = "".to_string(); + let _res = get_expr(dbg!(a)); + let _l = a.len(); //~ ERROR borrow of moved value +} + +fn main() {} diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr new file mode 100644 index 0000000000000..efacc0c3f1341 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.stderr @@ -0,0 +1,117 @@ +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:4:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a); + | ------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:10:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(1, 2, a, 1, 2); + | ------------------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(1, 2, &a, 1, 2); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:16:12 + | +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a, b); + | ---------- value moved here +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(a, &b); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:22:12 + | +LL | fn x(a: String) -> String { + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let b: String = "".to_string(); +LL | dbg!(a, b); + | ---------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a, b); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:46:12 + | +LL | tmp => { + | --- value moved here +... +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | my_dbg!(b, 1); +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | my_dbg!(&b, 1); + | + +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:57:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _b = match a { +LL | tmp => { + | --- value moved here +... +LL | return a; + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: borrow of moved value: `a` + --> $DIR/dbg-issue-120327.rs:65:14 + | +LL | let a: String = "".to_string(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _res = get_expr(dbg!(a)); + | ------- value moved here +LL | let _l = a.len(); + | ^ value borrowed here after move + | +help: consider borrowing instead of transferring ownership + | +LL | let _res = get_expr(dbg!(&a)); + | + + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index c2b9899e20db3..f515cb62c7cde 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -9,6 +9,10 @@ LL | let _ = dbg!(a); | ^^^^^^^ value used here after move | = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing instead of transferring ownership + | +LL | let _ = dbg!(&a); + | + error: aborting due to 1 previous error From 841b30f63ea1592f40a906ed1400c1999b89b4ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Jul 2024 16:43:18 -0400 Subject: [PATCH 10/10] Make sure trait def ids match before zipping args in note_function_argument_obligation --- .../src/error_reporting/traits/suggestions.rs | 1 + tests/crashes/126416.rs | 20 ----- tests/ui/methods/filter-relevant-fn-bounds.rs | 23 ++++++ .../methods/filter-relevant-fn-bounds.stderr | 74 +++++++++++++++++++ 4 files changed, 98 insertions(+), 20 deletions(-) delete mode 100644 tests/crashes/126416.rs create mode 100644 tests/ui/methods/filter-relevant-fn-bounds.rs create mode 100644 tests/ui/methods/filter-relevant-fn-bounds.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2cf808f962f08..f8843b892db3d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if let Some(where_pred) = where_pred.as_trait_clause() && let Some(failed_pred) = failed_pred.as_trait_clause() + && where_pred.def_id() == failed_pred.def_id() { self.enter_forall(where_pred, |where_pred| { let failed_pred = self.instantiate_binder_with_fresh_vars( diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs deleted file mode 100644 index 9b6c5169d444e..0000000000000 --- a/tests/crashes/126416.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#126416 - -trait Output<'a, T: 'a> { - type Type; -} - -struct Wrapper; - -impl Wrapper { - fn do_something_wrapper(&mut self, _: F) - where - F: for<'a> FnOnce(>::Type), - { - } -} - -fn main() { - let mut wrapper = Wrapper; - wrapper.do_something_wrapper(|value| ()); -} diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs new file mode 100644 index 0000000000000..76ececf7baa71 --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.rs @@ -0,0 +1,23 @@ +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper(self, _: F) + //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + where + F: for<'a> FnOnce(>::Type), + //~^ ERROR the trait bound `F: Output<'_>` is not satisfied + //~| ERROR the trait bound `F: Output<'_>` is not satisfied + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); + //~^ ERROR expected a `FnOnce +} diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr new file mode 100644 index 0000000000000..b737c0ab11fd4 --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr @@ -0,0 +1,74 @@ +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:5 + | +LL | / fn do_something_wrapper(self, _: F) +LL | | +LL | | +LL | | where +LL | | F: for<'a> FnOnce(>::Type), + | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:8 + | +LL | fn do_something_wrapper(self, _: F) + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:20 + | +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + --> $DIR/filter-relevant-fn-bounds.rs:21:34 + | +LL | wrapper.do_something_wrapper(|value| ()); + | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` +help: this trait has no implementations, consider adding one + --> $DIR/filter-relevant-fn-bounds.rs:1:1 + | +LL | trait Output<'a> { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Wrapper::do_something_wrapper` + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | fn do_something_wrapper(self, _: F) + | -------------------- required by a bound in this associated function +... +LL | F: for<'a> FnOnce(>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`.