diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_hir_typeck/src/demand.rs | 129 |
1 files changed, 50 insertions, 79 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 16febfc46..24184bdbf 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -2,6 +2,7 @@ use crate::FnCtxt; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; +use rustc_hir::def::CtorKind; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; use rustc_infer::infer::InferOk; @@ -18,6 +19,7 @@ use rustc_trait_selection::traits::ObligationCause; use super::method::probe; +use std::cmp::min; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -30,6 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, error: Option<TypeError<'tcx>>, ) { + if expr_ty == expected { + return; + } + self.annotate_expected_due_to_let_ty(err, expr, error); // Use `||` to give these suggestions a precedence @@ -42,15 +48,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty) || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) - || self.suggest_into(err, expr, expr_ty, expected); + || self.suggest_into(err, expr, expr_ty, expected) + || self.suggest_option_to_bool(err, expr, expr_ty, expected) + || self.suggest_floating_point_literal(err, expr, expected); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); } - // Requires that the two types unify, and prints an error message if - // they don't. + /// Requires that the two types unify, and prints an error message if + /// they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) { e.emit(); @@ -148,7 +156,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(e) => e, }; - self.set_tainted_by_errors(); + self.set_tainted_by_errors(self.tcx.sess.delay_span_bug( + expr.span, + "`TypeError` when attempting coercion but no error emitted", + )); let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); let expr_ty = self.resolve_vars_with_obligations(checked_ty); @@ -395,27 +406,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(path) = variant_path.strip_prefix("std::prelude::") && let Some((_, path)) = path.split_once("::") { - return Some((path.to_string(), variant.ctor_kind, sole_field.name, note_about_variant_field_privacy)); + return Some((path.to_string(), variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy)); } - Some((variant_path, variant.ctor_kind, sole_field.name, note_about_variant_field_privacy)) + Some((variant_path, variant.ctor_kind(), sole_field.name, note_about_variant_field_privacy)) } else { None } }) .collect(); - let suggestions_for = |variant: &_, ctor, field_name| { + let suggestions_for = |variant: &_, ctor_kind, field_name| { let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{ident}: "), None => String::new(), }; - let (open, close) = match ctor { - hir::def::CtorKind::Fn => ("(".to_owned(), ")"), - hir::def::CtorKind::Fictive => (format!(" {{ {field_name}: "), " }"), + let (open, close) = match ctor_kind { + Some(CtorKind::Fn) => ("(".to_owned(), ")"), + None => (format!(" {{ {field_name}: "), " }"), // unit variants don't have fields - hir::def::CtorKind::Const => unreachable!(), + Some(CtorKind::Const) => unreachable!(), }; // Suggest constructor as deep into the block tree as possible. @@ -845,31 +856,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) { - if mutability == hir::Mutability::Mut { + if mutability.is_mut() { // Suppressing this diagnostic, we'll properly print it in `check_expr_assign` return None; } } let sugg_expr = if needs_parens { format!("({src})") } else { src }; - return Some(match mutability { - hir::Mutability::Mut => ( - sp, - "consider mutably borrowing here".to_string(), - format!("{prefix}&mut {sugg_expr}"), - Applicability::MachineApplicable, - false, - false, - ), - hir::Mutability::Not => ( - sp, - "consider borrowing here".to_string(), - format!("{prefix}&{sugg_expr}"), - Applicability::MachineApplicable, - false, - false, - ), - }); + return Some(( + sp, + format!("consider {}borrowing here", mutability.mutably_str()), + format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()), + Applicability::MachineApplicable, + false, + false, + )); } } } @@ -927,51 +928,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Ok(src) = sm.span_to_snippet(sp) { let derefs = "*".repeat(steps); - if let Some((span, src, applicability)) = match mutbl_b { - hir::Mutability::Mut => { - let new_prefix = "&mut ".to_owned() + &derefs; - match mutbl_a { - hir::Mutability::Mut => { - replace_prefix(&src, "&mut ", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(5); - let sp = sp.with_lo(pos).with_hi(pos); - (sp, derefs, Applicability::MachineApplicable) - }) - } - hir::Mutability::Not => { - replace_prefix(&src, "&", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(1); - let sp = sp.with_lo(pos).with_hi(pos); - ( - sp, - format!("mut {derefs}"), - Applicability::Unspecified, - ) - }) - } - } - } - hir::Mutability::Not => { - let new_prefix = "&".to_owned() + &derefs; - match mutbl_a { - hir::Mutability::Mut => { - replace_prefix(&src, "&mut ", &new_prefix).map(|_| { - let lo = sp.lo() + BytePos(1); - let hi = sp.lo() + BytePos(5); - let sp = sp.with_lo(lo).with_hi(hi); - (sp, derefs, Applicability::MachineApplicable) - }) - } - hir::Mutability::Not => { - replace_prefix(&src, "&", &new_prefix).map(|_| { - let pos = sp.lo() + BytePos(1); - let sp = sp.with_lo(pos).with_hi(pos); - (sp, derefs, Applicability::MachineApplicable) - }) - } - } - } - } { + let old_prefix = mutbl_a.ref_prefix_str(); + let new_prefix = mutbl_b.ref_prefix_str().to_owned() + &derefs; + + let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| { + // skip `&` or `&mut ` if both mutabilities are mutable + let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _); + // skip `&` or `&mut ` + let hi = sp.lo() + BytePos(old_prefix.len() as _); + let sp = sp.with_lo(lo).with_hi(hi); + + ( + sp, + format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }), + if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect } + ) + }); + + if let Some((span, src, applicability)) = suggestion { return Some(( span, "consider dereferencing".to_string(), @@ -995,10 +969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the expression has `&`, removing it would fix the error prefix_span = prefix_span.with_hi(inner.span.lo()); expr = inner; - remove += match mutbl { - hir::Mutability::Not => "&", - hir::Mutability::Mut => "&mut ", - }; + remove.push_str(mutbl.ref_prefix_str()); steps -= 1; } else { break; |