Skip to content

Commit

Permalink
Auto merge of #112116 - compiler-errors:misc-hir-typeck-mismatch-twea…
Browse files Browse the repository at this point in the history
…ks, r=WaffleLapkin

Misc HIR typeck type mismatch tweaks

These are all intended to improve #112104, but I couldn't get it to actually suggest adding `as_ref` to the LHS of the equality expr without some hacks that I may play around with some more.

Each commit's title should explain what it's doing except for perhaps the last one, which addresses the bogus suggestion on #112104 itself.
  • Loading branch information
bors committed Jun 9, 2023
2 parents 68c8fda + a918822 commit 9c843d9
Show file tree
Hide file tree
Showing 20 changed files with 337 additions and 170 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
hir_typeck_convert_to_str = try converting the passed type into a `&str`
hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
hir_typeck_expected_default_return_type = expected `()` because of default return type
Expand Down
60 changes: 56 additions & 4 deletions compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::MultiSpan;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def::{CtorKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
Expand Down Expand Up @@ -91,6 +91,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
}

/// Really hacky heuristic to remap an `assert_eq!` error to the user
/// expressions provided to the macro.
fn adjust_expr_for_assert_eq_macro(
&self,
found_expr: &mut &'tcx hir::Expr<'tcx>,
expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
) {
let Some(expected_expr) = expected_expr else { return; };

if !found_expr.span.eq_ctxt(expected_expr.span) {
return;
}

if !found_expr
.span
.ctxt()
.outer_expn_data()
.macro_def_id
.is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
{
return;
}

let hir::ExprKind::Unary(
hir::UnOp::Deref,
hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
) = found_expr.kind else { return; };
let hir::ExprKind::Unary(
hir::UnOp::Deref,
hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
) = expected_expr.kind else { return; };

for (path, name, idx, var) in [
(expected_path, "left_val", 0, expected_expr),
(found_path, "right_val", 1, found_expr),
] {
if let hir::QPath::Resolved(_, path) = path
&& let [segment] = path.segments
&& segment.ident.name.as_str() == name
&& let Res::Local(hir_id) = path.res
&& let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
{
*var = macro_arg;
}
}
}

/// 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>) {
Expand Down Expand Up @@ -156,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

pub fn demand_coerce(
&self,
expr: &hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
Expand All @@ -177,10 +227,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
pub fn demand_coerce_diag(
&self,
expr: &hir::Expr<'tcx>,
mut expr: &'tcx hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
allow_two_phase: AllowTwoPhase,
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
let expected = self.resolve_vars_with_obligations(expected);
Expand All @@ -190,6 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(e) => e,
};

self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);

self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
expr.span,
"`TypeError` when attempting coercion but no error emitted",
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,19 @@ pub struct CtorIsPrivate {
pub span: Span,
pub def: String,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
hir_typeck_convert_using_method,
applicability = "machine-applicable",
style = "verbose"
)]
pub struct SuggestConvertViaMethod<'tcx> {
#[suggestion_part(code = "{sugg}")]
pub span: Span,
#[suggestion_part(code = "")]
pub borrow_removal_span: Option<Span>,
pub sugg: &'static str,
pub expected: Ty<'tcx>,
pub found: Ty<'tcx>,
}
12 changes: 11 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// type of the place it is referencing, and not some
// supertype thereof.
let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
self.demand_eqtype(init.span, local_ty, init_ty);
if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) {
self.emit_type_mismatch_suggestions(
&mut diag,
init.peel_drop_temps(),
init_ty,
local_ty,
None,
None,
);
diag.emit();
}
init_ty
} else {
self.check_expr_coercible_to_type(init, local_ty, None)
Expand Down
Loading

0 comments on commit 9c843d9

Please sign in to comment.