Skip to content

Commit fb9d98c

Browse files
committed
Improve diagnostic when passing arg to closure and missing borrow.
This checks the number of references for the given and expected type and shows hints to the user if the numbers don't match.
1 parent 518263d commit fb9d98c

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
12031203
_ => None,
12041204
};
12051205

1206+
let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
12061207
let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
12071208

12081209
if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
@@ -1256,6 +1257,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
12561257
found_trait_ref,
12571258
expected_trait_ref,
12581259
obligation.cause.code(),
1260+
found_node,
12591261
)
12601262
} else {
12611263
let (closure_span, found) = found_did

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ pub trait TypeErrCtxtExt<'tcx> {
255255
found: ty::PolyTraitRef<'tcx>,
256256
expected: ty::PolyTraitRef<'tcx>,
257257
cause: &ObligationCauseCode<'tcx>,
258+
found_node: Option<Node<'_>>,
258259
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
259260

260261
fn note_conflicting_closure_bounds(
@@ -1592,6 +1593,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
15921593
found: ty::PolyTraitRef<'tcx>,
15931594
expected: ty::PolyTraitRef<'tcx>,
15941595
cause: &ObligationCauseCode<'tcx>,
1596+
found_node: Option<Node<'_>>,
15951597
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
15961598
pub(crate) fn build_fn_sig_ty<'tcx>(
15971599
infcx: &InferCtxt<'tcx>,
@@ -1655,6 +1657,75 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
16551657

16561658
self.note_conflicting_closure_bounds(cause, &mut err);
16571659

1660+
let found_args = match found.kind() {
1661+
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
1662+
kind => {
1663+
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
1664+
}
1665+
};
1666+
let expected_args = match expected.kind() {
1667+
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
1668+
kind => {
1669+
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
1670+
}
1671+
};
1672+
1673+
if let Some(found_node) = found_node {
1674+
let fn_decl = match found_node {
1675+
Node::Expr(expr) => match &expr.kind {
1676+
hir::ExprKind::Closure(hir::Closure { fn_decl, .. }) => fn_decl,
1677+
kind => {
1678+
span_bug!(found_span, "expression must be a closure but is {:?}", kind)
1679+
}
1680+
},
1681+
Node::Item(item) => match &item.kind {
1682+
hir::ItemKind::Fn(signature, _generics, _body) => signature.decl,
1683+
kind => {
1684+
span_bug!(found_span, "item must be a function but is {:?}", kind)
1685+
}
1686+
},
1687+
node => {
1688+
span_bug!(found_span, "node must be a expr or item but is {:?}", node)
1689+
}
1690+
};
1691+
1692+
let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span);
1693+
1694+
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
1695+
let mut refs = 0;
1696+
1697+
while let ty::Ref(_, new_ty, _) = ty.kind() {
1698+
ty = *new_ty;
1699+
refs += 1;
1700+
}
1701+
1702+
(ty, refs)
1703+
}
1704+
1705+
for ((found_arg, expected_arg), arg_span) in
1706+
found_args.zip(expected_args).zip(arg_spans)
1707+
{
1708+
let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
1709+
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
1710+
1711+
if found_ty == expected_ty {
1712+
let hint = if found_refs < expected_refs {
1713+
"hint: consider borrowing here:"
1714+
} else if found_refs == expected_refs {
1715+
continue;
1716+
} else {
1717+
"hint: consider removing the borrow:"
1718+
};
1719+
err.span_suggestion_verbose(
1720+
arg_span,
1721+
hint,
1722+
expected_arg.to_string(),
1723+
Applicability::MaybeIncorrect,
1724+
);
1725+
}
1726+
}
1727+
}
1728+
16581729
err
16591730
}
16601731

0 commit comments

Comments
 (0)