summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_typeck/src/demand.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_typeck/src/demand.rs')
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs129
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;