]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_typeck/src/check/cast.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / cast.rs
index 14550690e63e01e542cfab488bb84b2f480d1679..78849b276d6bfb80f610c574a021f4b7efb91d3a 100644 (file)
@@ -351,7 +351,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 );
                 let mut sugg = None;
                 let mut sugg_mutref = false;
-                if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
+                if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
                     if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
                         if fcx
                             .try_coerce(
@@ -362,10 +362,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                 ),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
+                                None,
                             )
                             .is_ok()
                         {
-                            sugg = Some(format!("&{}*", mutbl.prefix_str()));
+                            sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
                         }
                     } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
                         if expr_mutbl == Mutability::Not
@@ -379,6 +380,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                     ),
                                     self.cast_ty,
                                     AllowTwoPhase::No,
+                                    None,
                                 )
                                 .is_ok()
                         {
@@ -394,10 +396,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                 fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
+                                None,
                             )
                             .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() {
                     if fcx
@@ -409,22 +412,51 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             ),
                             self.cast_ty,
                             AllowTwoPhase::No,
+                            None,
                         )
                         .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 }
                 if sugg_mutref {
                     err.span_label(self.span, "invalid cast");
                     err.span_note(self.expr.span, "this reference is immutable");
                     err.span_note(self.cast_span, "trying to cast to a mutable reference type");
-                } else if let Some(sugg) = sugg {
+                } else if let Some((sugg, remove_cast)) = sugg {
                     err.span_label(self.span, "invalid cast");
-                    err.span_suggestion_verbose(
-                        self.expr.span.shrink_to_lo(),
+
+                    let has_parens = fcx
+                        .tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(self.expr.span)
+                        .map_or(false, |snip| snip.starts_with('('));
+
+                    // Very crude check to see whether the expression must be wrapped
+                    // in parentheses for the suggestion to work (issue #89497).
+                    // Can/should be extended in the future.
+                    let needs_parens = !has_parens
+                        && match self.expr.kind {
+                            hir::ExprKind::Cast(..) => true,
+                            _ => false,
+                        };
+
+                    let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
+                    if needs_parens {
+                        suggestion[0].1 += "(";
+                        suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
+                    }
+                    if remove_cast {
+                        suggestion.push((
+                            self.expr.span.shrink_to_hi().to(self.cast_span),
+                            String::new(),
+                        ));
+                    }
+
+                    err.multipart_suggestion_verbose(
                         "consider borrowing the value",
-                        sugg,
+                        suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else if !matches!(
@@ -434,7 +466,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     let mut label = true;
                     // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
                     if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
-                        if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) {
+                        if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
                             let ty = fcx.resolve_vars_if_possible(self.cast_ty);
                             // Erase regions to avoid panic in `prove_value` when calling
                             // `type_implements_trait`.
@@ -666,6 +698,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             self.expr_ty,
                             fcx.tcx.mk_fn_ptr(f),
                             AllowTwoPhase::No,
+                            None,
                         );
                         if let Err(TypeError::IntrinsicCast) = res {
                             return Err(CastError::IllegalCast);
@@ -829,7 +862,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
                 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
-                fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
+                fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
                     .unwrap_or_else(|_| {
                         bug!(
                         "could not cast from reference to array to pointer to array ({:?} to {:?})",
@@ -861,7 +894,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     }
 
     fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
-        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
+        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
             Ok(_) => Ok(()),
             Err(err) => Err(err),
         }