From 60d62bee36074d24f4995287ba3b12adf1df0888 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Fri, 1 May 2020 06:36:06 +0800 Subject: [PATCH 1/4] Suggest deref when coercing `ty::Ref` to `ty::RawPtr` with arbitrary mutability --- src/librustc_typeck/check/coercion.rs | 15 ++- src/librustc_typeck/check/demand.rs | 125 ++++++++++++++++-------- src/librustc_typeck/check/mod.rs | 4 +- src/test/ui/issues/issue-32122-1.stderr | 2 +- src/test/ui/issues/issue-32122-2.stderr | 2 +- src/test/ui/issues/issue-71676-1.fixed | 54 ++++++++++ src/test/ui/issues/issue-71676-1.rs | 54 ++++++++++ src/test/ui/issues/issue-71676-1.stderr | 55 +++++++++++ src/test/ui/issues/issue-71676-2.rs | 43 ++++++++ src/test/ui/issues/issue-71676-2.stderr | 16 +++ 10 files changed, 323 insertions(+), 47 deletions(-) create mode 100644 src/test/ui/issues/issue-71676-1.fixed create mode 100644 src/test/ui/issues/issue-71676-1.rs create mode 100644 src/test/ui/issues/issue-71676-1.stderr create mode 100644 src/test/ui/issues/issue-71676-2.rs create mode 100644 src/test/ui/issues/issue-71676-2.stderr diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index e3b16eaaef2a2..c336ec1347949 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -74,7 +74,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; -pub struct Coerce<'a, 'tcx> { +struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, @@ -126,7 +126,7 @@ fn success<'tcx>( } impl<'f, 'tcx> Coerce<'f, 'tcx> { - pub fn new( + fn new( fcx: &'f FnCtxt<'f, 'tcx>, cause: ObligationCause<'tcx>, allow_two_phase: AllowTwoPhase, @@ -134,7 +134,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Coerce { fcx, cause, allow_two_phase, use_lub: false } } - pub fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { if self.use_lub { @@ -831,6 +831,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.probe(|_| coerce.coerce(source, target)).is_ok() } + pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option { + let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); + // We don't ever need two-phase here since we throw out the result of the coercion + let coerce = Coerce::new(self, cause, AllowTwoPhase::No); + coerce + .autoderef(rustc_span::DUMMY_SP, expr_ty) + .find_map(|(ty, steps)| coerce.unify(ty, target).ok().map(|_| steps)) + } + /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 65ef9cad87448..2c4ab40ccd443 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,4 +1,3 @@ -use crate::check::coercion::Coerce; use crate::check::FnCtxt; use rustc_infer::infer::InferOk; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -9,7 +8,6 @@ use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::{is_range_literal, Node}; -use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::sym; @@ -376,7 +374,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, checked_ty: Ty<'tcx>, expected: Ty<'tcx>, - ) -> Option<(Span, &'static str, String)> { + ) -> Option<(Span, &'static str, String, Applicability)> { let sm = self.sess().source_map(); let sp = expr.span; if sm.is_imported(sp) { @@ -395,16 +393,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps(); + let remove_prefix = |s: String, prefix: &str| { + if s.starts_with(prefix) { Some(s[prefix.len()..].to_string()) } else { None } + }; + match (&expr.kind, &expected.kind, &checked_ty.kind) { (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if src.starts_with("b\"") { + if let Some(src) = remove_prefix(src, "b\"") { return Some(( sp, "consider removing the leading `b`", - src[1..].to_string(), + format!("\"{}", src), + Applicability::MachineApplicable, )); } } @@ -413,11 +416,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if src.starts_with('"') { + if let Some(src) = remove_prefix(src, "\"") { return Some(( sp, "consider adding a leading `b`", - format!("b{}", src), + format!("b\"{}", src), + Applicability::MachineApplicable, )); } } @@ -470,7 +474,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sugg_expr = if needs_parens { format!("({})", src) } else { src }; if let Some(sugg) = self.can_use_as_ref(expr) { - return Some(sugg); + return Some(( + sugg.0, + sugg.1, + sugg.2, + Applicability::MachineApplicable, + )); } let field_name = if is_struct_pat_shorthand_field { format!("{}: ", sugg_expr) @@ -495,6 +504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "consider dereferencing here to assign to the mutable \ borrowed piece of memory", format!("*{}", src), + Applicability::MachineApplicable, )); } } @@ -505,11 +515,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, "consider mutably borrowing here", format!("{}&mut {}", field_name, sugg_expr), + Applicability::MachineApplicable, ), hir::Mutability::Not => ( sp, "consider borrowing here", format!("{}&{}", field_name, sugg_expr), + Applicability::MachineApplicable, ), }); } @@ -526,51 +538,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We have `&T`, check if what was expected was `T`. If so, // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { - if let Ok(code) = sm.span_to_snippet(sp) { - if code.starts_with('&') { + if let Ok(src) = sm.span_to_snippet(sp) { + if let Some(src) = remove_prefix(src, "&") { return Some(( sp, "consider removing the borrow", - code[1..].to_string(), + src, + Applicability::MachineApplicable, )); } } return None; } if let Ok(code) = sm.span_to_snippet(expr.span) { - return Some((sp, "consider removing the borrow", code)); + return Some(( + sp, + "consider removing the borrow", + code, + Applicability::MachineApplicable, + )); } } ( _, - &ty::RawPtr(TypeAndMut { ty: _, mutbl: hir::Mutability::Not }), - &ty::Ref(_, _, hir::Mutability::Not), + &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }), + &ty::Ref(_, ty_a, mutbl_a), ) => { - let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); - // We don't ever need two-phase here since we throw out the result of the coercion - let coerce = Coerce::new(self, cause, AllowTwoPhase::No); - - if let Some(steps) = - coerce.autoderef(sp, checked_ty).skip(1).find_map(|(referent_ty, steps)| { - coerce - .unify( - coerce.tcx.mk_ptr(ty::TypeAndMut { - mutbl: hir::Mutability::Not, - ty: referent_ty, - }), - expected, - ) - .ok() - .map(|_| steps) - }) - { - // The pointer type implements `Copy` trait so the suggestion is always valid. - if let Ok(code) = sm.span_to_snippet(sp) { - if code.starts_with('&') { - let derefs = "*".repeat(steps - 1); - let message = "consider dereferencing the reference"; - let suggestion = format!("&{}{}", derefs, code[1..].to_string()); - return Some((sp, message, suggestion)); + if let Some(steps) = self.deref_steps(ty_a, ty_b) { + // Only suggest valid if dereferencing needed. + if steps > 0 { + // The pointer type implements `Copy` trait so the suggestion is always valid. + if let Ok(src) = sm.span_to_snippet(sp) { + let derefs = "*".repeat(steps); + match mutbl_b { + hir::Mutability::Mut => match mutbl_a { + hir::Mutability::Mut => { + if let Some(src) = remove_prefix(src, "&mut ") { + return Some(( + sp, + "consider dereferencing", + format!("&mut {}{}", derefs, src), + Applicability::MachineApplicable, + )); + } + } + hir::Mutability::Not => { + if let Some(src) = remove_prefix(src, "&") { + return Some(( + sp, + "consider dereferencing", + format!("&mut {}{}", derefs, src), + Applicability::Unspecified, + )); + } + } + }, + hir::Mutability::Not => match mutbl_a { + hir::Mutability::Mut => { + if let Some(src) = remove_prefix(src, "&mut ") { + return Some(( + sp, + "consider dereferencing", + format!("&{}{}", derefs, src), + Applicability::MachineApplicable, + )); + } + } + hir::Mutability::Not => { + if let Some(src) = remove_prefix(src, "&") { + return Some(( + sp, + "consider dereferencing", + format!("&{}{}", derefs, src), + Applicability::MachineApplicable, + )); + } + } + }, + } } } } @@ -616,7 +661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { format!("*{}", code) }; - return Some((sp, message, suggestion)); + return Some((sp, message, suggestion, Applicability::MachineApplicable)); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index adbab3d4cb620..68817d3fe0f16 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5036,8 +5036,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) { - if let Some((sp, msg, suggestion)) = self.check_ref(expr, found, expected) { - err.span_suggestion(sp, msg, suggestion, Applicability::MachineApplicable); + if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { + err.span_suggestion(sp, msg, suggestion, applicability); } else if let (ty::FnDef(def_id, ..), true) = (&found.kind, self.suggest_fn_call(err, expr, expected, found)) { diff --git a/src/test/ui/issues/issue-32122-1.stderr b/src/test/ui/issues/issue-32122-1.stderr index 313de275c53ee..dfbd3223efc86 100644 --- a/src/test/ui/issues/issue-32122-1.stderr +++ b/src/test/ui/issues/issue-32122-1.stderr @@ -5,7 +5,7 @@ LL | let _: *const u8 = &a; | --------- ^^ | | | | | expected `u8`, found struct `Foo` - | | help: consider dereferencing the reference: `&*a` + | | help: consider dereferencing: `&*a` | expected due to this | = note: expected raw pointer `*const u8` diff --git a/src/test/ui/issues/issue-32122-2.stderr b/src/test/ui/issues/issue-32122-2.stderr index 959a49507e4f5..2e199e2a19f73 100644 --- a/src/test/ui/issues/issue-32122-2.stderr +++ b/src/test/ui/issues/issue-32122-2.stderr @@ -5,7 +5,7 @@ LL | let _: *const u8 = &a; | --------- ^^ | | | | | expected `u8`, found struct `Emm` - | | help: consider dereferencing the reference: `&***a` + | | help: consider dereferencing: `&***a` | expected due to this | = note: expected raw pointer `*const u8` diff --git a/src/test/ui/issues/issue-71676-1.fixed b/src/test/ui/issues/issue-71676-1.fixed new file mode 100644 index 0000000000000..d2be0db95fb8c --- /dev/null +++ b/src/test/ui/issues/issue-71676-1.fixed @@ -0,0 +1,54 @@ +// run-rustfix +use std::ops::Deref; +use std::ops::DerefMut; +struct Bar(u8); +struct Foo(Bar); +struct Emm(Foo); +impl Deref for Bar{ + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Foo { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Emm { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Bar{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Emm { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +fn main() { + // Suggest dereference with arbitrary mutability + let a = Emm(Foo(Bar(0))); + let _: *const u8 = &***a; //~ ERROR mismatched types + + let mut a = Emm(Foo(Bar(0))); + let _: *mut u8 = &mut ***a; //~ ERROR mismatched types + + let a = Emm(Foo(Bar(0))); + let _: *const u8 = &***a; //~ ERROR mismatched types + + let mut a = Emm(Foo(Bar(0))); + let _: *mut u8 = &mut ***a; //~ ERROR mismatched types + +} diff --git a/src/test/ui/issues/issue-71676-1.rs b/src/test/ui/issues/issue-71676-1.rs new file mode 100644 index 0000000000000..c09ad6dabaa9a --- /dev/null +++ b/src/test/ui/issues/issue-71676-1.rs @@ -0,0 +1,54 @@ +// run-rustfix +use std::ops::Deref; +use std::ops::DerefMut; +struct Bar(u8); +struct Foo(Bar); +struct Emm(Foo); +impl Deref for Bar{ + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Foo { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Emm { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Bar{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Emm { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +fn main() { + // Suggest dereference with arbitrary mutability + let a = Emm(Foo(Bar(0))); + let _: *const u8 = &a; //~ ERROR mismatched types + + let mut a = Emm(Foo(Bar(0))); + let _: *mut u8 = &a; //~ ERROR mismatched types + + let a = Emm(Foo(Bar(0))); + let _: *const u8 = &mut a; //~ ERROR mismatched types + + let mut a = Emm(Foo(Bar(0))); + let _: *mut u8 = &mut a; //~ ERROR mismatched types + +} diff --git a/src/test/ui/issues/issue-71676-1.stderr b/src/test/ui/issues/issue-71676-1.stderr new file mode 100644 index 0000000000000..bbabc2202dc84 --- /dev/null +++ b/src/test/ui/issues/issue-71676-1.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/issue-71676-1.rs:43:24 + | +LL | let _: *const u8 = &a; + | --------- ^^ + | | | + | | expected `u8`, found struct `Emm` + | | help: consider dereferencing: `&***a` + | expected due to this + | + = note: expected raw pointer `*const u8` + found reference `&Emm` + +error[E0308]: mismatched types + --> $DIR/issue-71676-1.rs:46:22 + | +LL | let _: *mut u8 = &a; + | ------- ^^ + | | | + | | types differ in mutability + | | help: consider dereferencing: `&mut ***a` + | expected due to this + | + = note: expected raw pointer `*mut u8` + found reference `&Emm` + +error[E0308]: mismatched types + --> $DIR/issue-71676-1.rs:49:24 + | +LL | let _: *const u8 = &mut a; + | --------- ^^^^^^ + | | | + | | expected `u8`, found struct `Emm` + | | help: consider dereferencing: `&***a` + | expected due to this + | + = note: expected raw pointer `*const u8` + found mutable reference `&mut Emm` + +error[E0308]: mismatched types + --> $DIR/issue-71676-1.rs:52:22 + | +LL | let _: *mut u8 = &mut a; + | ------- ^^^^^^ + | | | + | | expected `u8`, found struct `Emm` + | | help: consider dereferencing: `&mut ***a` + | expected due to this + | + = note: expected raw pointer `*mut u8` + found mutable reference `&mut Emm` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-71676-2.rs b/src/test/ui/issues/issue-71676-2.rs new file mode 100644 index 0000000000000..d11fce567ce51 --- /dev/null +++ b/src/test/ui/issues/issue-71676-2.rs @@ -0,0 +1,43 @@ +use std::ops::Deref; +use std::ops::DerefMut; +struct Bar(u8); +struct Foo(Bar); +struct Emm(Foo); +impl Deref for Bar{ + type Target = u8; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Foo { + type Target = Bar; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl Deref for Emm { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Bar{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Foo { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl DerefMut for Emm { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +fn main() { + // Should not suggest when a is immutable + let a = Emm(Foo(Bar(0))); + let _: *mut u8 = &a; //~ ERROR mismatched types +} diff --git a/src/test/ui/issues/issue-71676-2.stderr b/src/test/ui/issues/issue-71676-2.stderr new file mode 100644 index 0000000000000..273ae9cb4dba8 --- /dev/null +++ b/src/test/ui/issues/issue-71676-2.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/issue-71676-2.rs:42:22 + | +LL | let _: *mut u8 = &a; + | ------- ^^ + | | | + | | types differ in mutability + | | help: consider dereferencing: `&mut ***a` + | expected due to this + | + = note: expected raw pointer `*mut u8` + found reference `&Emm` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 80d04cc1ba610d796c84427622ce17eb2ca9c771 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Fri, 1 May 2020 21:56:10 +0800 Subject: [PATCH 2/4] Add comments for deref_steps() --- src/librustc_typeck/check/coercion.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c336ec1347949..7437c87a25763 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -831,6 +831,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.probe(|_| coerce.coerce(source, target)).is_ok() } + /// Given a type and a target type, this function will calculate and return + /// how many dereference steps needed to achieve `expr_ty <: target`. If + /// it's not possible, return `None`. pub fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option { let cause = self.cause(rustc_span::DUMMY_SP, ObligationCauseCode::ExprAssignable); // We don't ever need two-phase here since we throw out the result of the coercion From 089d4bbfd79c4ae2e735154cff4448ecd5fc4afc Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Fri, 1 May 2020 21:57:19 +0800 Subject: [PATCH 3/4] Suggestion for immutable reference -> mutable pointer should be emitted as `Applicability::Unspecified` --- src/test/ui/issues/issue-71676-2.rs | 1 - src/test/ui/issues/issue-71676-2.stderr | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/ui/issues/issue-71676-2.rs b/src/test/ui/issues/issue-71676-2.rs index d11fce567ce51..f3183899dc523 100644 --- a/src/test/ui/issues/issue-71676-2.rs +++ b/src/test/ui/issues/issue-71676-2.rs @@ -37,7 +37,6 @@ impl DerefMut for Emm { } } fn main() { - // Should not suggest when a is immutable let a = Emm(Foo(Bar(0))); let _: *mut u8 = &a; //~ ERROR mismatched types } diff --git a/src/test/ui/issues/issue-71676-2.stderr b/src/test/ui/issues/issue-71676-2.stderr index 273ae9cb4dba8..ebdd345809af5 100644 --- a/src/test/ui/issues/issue-71676-2.stderr +++ b/src/test/ui/issues/issue-71676-2.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-71676-2.rs:42:22 + --> $DIR/issue-71676-2.rs:41:22 | LL | let _: *mut u8 = &a; | ------- ^^ From 9a212c1625514fdc5588cdfe6f2d58290e73248d Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Fri, 1 May 2020 21:59:09 +0800 Subject: [PATCH 4/4] Replace convenient function `remove_prefix()` with `replace_prefix()` --- src/librustc_typeck/check/demand.rs | 109 ++++++++++++++----------- src/test/ui/issues/issue-71676-1.fixed | 1 - src/test/ui/issues/issue-71676-1.rs | 1 - 3 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 2c4ab40ccd443..9e14efb67a94c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -353,6 +353,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + fn replace_prefix(&self, s: A, old: B, new: C) -> Option + where + A: AsRef, + B: AsRef, + C: AsRef, + { + let s = s.as_ref(); + let old = old.as_ref(); + if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None } + } + /// This function is used to determine potential "simple" improvements or users' errors and /// provide them useful help. For example: /// @@ -393,20 +404,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps(); - let remove_prefix = |s: String, prefix: &str| { - if s.starts_with(prefix) { Some(s[prefix.len()..].to_string()) } else { None } - }; - match (&expr.kind, &expected.kind, &checked_ty.kind) { (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = remove_prefix(src, "b\"") { + if let Some(src) = self.replace_prefix(src, "b\"", "\"") { return Some(( sp, "consider removing the leading `b`", - format!("\"{}", src), + src, Applicability::MachineApplicable, )); } @@ -416,11 +423,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = remove_prefix(src, "\"") { + if let Some(src) = self.replace_prefix(src, "\"", "b\"") { return Some(( sp, "consider adding a leading `b`", - format!("b\"{}", src), + src, Applicability::MachineApplicable, )); } @@ -539,7 +546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = remove_prefix(src, "&") { + if let Some(src) = self.replace_prefix(src, "&", "") { return Some(( sp, "consider removing the borrow", @@ -569,52 +576,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if steps > 0 { // The pointer type implements `Copy` trait so the suggestion is always valid. if let Ok(src) = sm.span_to_snippet(sp) { - let derefs = "*".repeat(steps); - match mutbl_b { - hir::Mutability::Mut => match mutbl_a { - hir::Mutability::Mut => { - if let Some(src) = remove_prefix(src, "&mut ") { - return Some(( - sp, - "consider dereferencing", - format!("&mut {}{}", derefs, src), - Applicability::MachineApplicable, - )); + let derefs = &"*".repeat(steps); + if let Some((src, applicability)) = match mutbl_b { + hir::Mutability::Mut => { + let new_prefix = "&mut ".to_owned() + derefs; + match mutbl_a { + hir::Mutability::Mut => { + if let Some(s) = + self.replace_prefix(src, "&mut ", new_prefix) + { + Some((s, Applicability::MachineApplicable)) + } else { + None + } } - } - hir::Mutability::Not => { - if let Some(src) = remove_prefix(src, "&") { - return Some(( - sp, - "consider dereferencing", - format!("&mut {}{}", derefs, src), - Applicability::Unspecified, - )); + hir::Mutability::Not => { + if let Some(s) = + self.replace_prefix(src, "&", new_prefix) + { + Some((s, Applicability::Unspecified)) + } else { + None + } } } - }, - hir::Mutability::Not => match mutbl_a { - hir::Mutability::Mut => { - if let Some(src) = remove_prefix(src, "&mut ") { - return Some(( - sp, - "consider dereferencing", - format!("&{}{}", derefs, src), - Applicability::MachineApplicable, - )); + } + hir::Mutability::Not => { + let new_prefix = "&".to_owned() + derefs; + match mutbl_a { + hir::Mutability::Mut => { + if let Some(s) = + self.replace_prefix(src, "&mut ", new_prefix) + { + Some((s, Applicability::MachineApplicable)) + } else { + None + } } - } - hir::Mutability::Not => { - if let Some(src) = remove_prefix(src, "&") { - return Some(( - sp, - "consider dereferencing", - format!("&{}{}", derefs, src), - Applicability::MachineApplicable, - )); + hir::Mutability::Not => { + if let Some(s) = + self.replace_prefix(src, "&", new_prefix) + { + Some((s, Applicability::MachineApplicable)) + } else { + None + } } } - }, + } + } { + return Some((sp, "consider dereferencing", src, applicability)); } } } diff --git a/src/test/ui/issues/issue-71676-1.fixed b/src/test/ui/issues/issue-71676-1.fixed index d2be0db95fb8c..cbc0e8c061b82 100644 --- a/src/test/ui/issues/issue-71676-1.fixed +++ b/src/test/ui/issues/issue-71676-1.fixed @@ -50,5 +50,4 @@ fn main() { let mut a = Emm(Foo(Bar(0))); let _: *mut u8 = &mut ***a; //~ ERROR mismatched types - } diff --git a/src/test/ui/issues/issue-71676-1.rs b/src/test/ui/issues/issue-71676-1.rs index c09ad6dabaa9a..6e87c7174c633 100644 --- a/src/test/ui/issues/issue-71676-1.rs +++ b/src/test/ui/issues/issue-71676-1.rs @@ -50,5 +50,4 @@ fn main() { let mut a = Emm(Foo(Bar(0))); let _: *mut u8 = &mut a; //~ ERROR mismatched types - }