Skip to content

Commit 9c843d9

Browse files
committed
Auto merge of #112116 - compiler-errors:misc-hir-typeck-mismatch-tweaks, 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.
2 parents 68c8fda + a918822 commit 9c843d9

20 files changed

+337
-170
lines changed

compiler/rustc_hir_typeck/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
2525
2626
hir_typeck_convert_to_str = try converting the passed type into a `&str`
2727
28+
hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
29+
2830
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
2931
3032
hir_typeck_expected_default_return_type = expected `()` because of default return type

compiler/rustc_hir_typeck/src/demand.rs

+56-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
33
use rustc_errors::MultiSpan;
44
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
55
use rustc_hir as hir;
6-
use rustc_hir::def::CtorKind;
6+
use rustc_hir::def::{CtorKind, Res};
77
use rustc_hir::intravisit::Visitor;
88
use rustc_hir::lang_items::LangItem;
99
use rustc_hir::{is_range_literal, Node};
@@ -91,6 +91,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9191
self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
9292
}
9393

94+
/// Really hacky heuristic to remap an `assert_eq!` error to the user
95+
/// expressions provided to the macro.
96+
fn adjust_expr_for_assert_eq_macro(
97+
&self,
98+
found_expr: &mut &'tcx hir::Expr<'tcx>,
99+
expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
100+
) {
101+
let Some(expected_expr) = expected_expr else { return; };
102+
103+
if !found_expr.span.eq_ctxt(expected_expr.span) {
104+
return;
105+
}
106+
107+
if !found_expr
108+
.span
109+
.ctxt()
110+
.outer_expn_data()
111+
.macro_def_id
112+
.is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
113+
{
114+
return;
115+
}
116+
117+
let hir::ExprKind::Unary(
118+
hir::UnOp::Deref,
119+
hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
120+
) = found_expr.kind else { return; };
121+
let hir::ExprKind::Unary(
122+
hir::UnOp::Deref,
123+
hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
124+
) = expected_expr.kind else { return; };
125+
126+
for (path, name, idx, var) in [
127+
(expected_path, "left_val", 0, expected_expr),
128+
(found_path, "right_val", 1, found_expr),
129+
] {
130+
if let hir::QPath::Resolved(_, path) = path
131+
&& let [segment] = path.segments
132+
&& segment.ident.name.as_str() == name
133+
&& let Res::Local(hir_id) = path.res
134+
&& let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
135+
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
136+
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind
137+
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
138+
{
139+
*var = macro_arg;
140+
}
141+
}
142+
}
143+
94144
/// Requires that the two types unify, and prints an error message if
95145
/// they don't.
96146
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -156,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
156206

157207
pub fn demand_coerce(
158208
&self,
159-
expr: &hir::Expr<'tcx>,
209+
expr: &'tcx hir::Expr<'tcx>,
160210
checked_ty: Ty<'tcx>,
161211
expected: Ty<'tcx>,
162212
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -177,10 +227,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
177227
#[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
178228
pub fn demand_coerce_diag(
179229
&self,
180-
expr: &hir::Expr<'tcx>,
230+
mut expr: &'tcx hir::Expr<'tcx>,
181231
checked_ty: Ty<'tcx>,
182232
expected: Ty<'tcx>,
183-
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
233+
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
184234
allow_two_phase: AllowTwoPhase,
185235
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
186236
let expected = self.resolve_vars_with_obligations(expected);
@@ -190,6 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
190240
Err(e) => e,
191241
};
192242

243+
self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
244+
193245
self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
194246
expr.span,
195247
"`TypeError` when attempting coercion but no error emitted",

compiler/rustc_hir_typeck/src/errors.rs

+16
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,19 @@ pub struct CtorIsPrivate {
327327
pub span: Span,
328328
pub def: String,
329329
}
330+
331+
#[derive(Subdiagnostic)]
332+
#[multipart_suggestion(
333+
hir_typeck_convert_using_method,
334+
applicability = "machine-applicable",
335+
style = "verbose"
336+
)]
337+
pub struct SuggestConvertViaMethod<'tcx> {
338+
#[suggestion_part(code = "{sugg}")]
339+
pub span: Span,
340+
#[suggestion_part(code = "")]
341+
pub borrow_removal_span: Option<Span>,
342+
pub sugg: &'static str,
343+
pub expected: Ty<'tcx>,
344+
pub found: Ty<'tcx>,
345+
}

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14041404
// type of the place it is referencing, and not some
14051405
// supertype thereof.
14061406
let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
1407-
self.demand_eqtype(init.span, local_ty, init_ty);
1407+
if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) {
1408+
self.emit_type_mismatch_suggestions(
1409+
&mut diag,
1410+
init.peel_drop_temps(),
1411+
init_ty,
1412+
local_ty,
1413+
None,
1414+
None,
1415+
);
1416+
diag.emit();
1417+
}
14081418
init_ty
14091419
} else {
14101420
self.check_expr_coercible_to_type(init, local_ty, None)

0 commit comments

Comments
 (0)