Skip to content

Commit 1e5d772

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 109cccb commit 1e5d772

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
@@ -1234,6 +1234,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
12341234
_ => None,
12351235
};
12361236

1237+
let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
12371238
let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
12381239

12391240
if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
@@ -1287,6 +1288,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
12871288
found_trait_ref,
12881289
expected_trait_ref,
12891290
obligation.cause.code(),
1291+
found_node,
12901292
)
12911293
} else {
12921294
let (closure_span, closure_arg_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
@@ -258,6 +258,7 @@ pub trait TypeErrCtxtExt<'tcx> {
258258
found: ty::PolyTraitRef<'tcx>,
259259
expected: ty::PolyTraitRef<'tcx>,
260260
cause: &ObligationCauseCode<'tcx>,
261+
found_node: Option<Node<'_>>,
261262
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
262263

263264
fn note_conflicting_closure_bounds(
@@ -1695,6 +1696,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
16951696
found: ty::PolyTraitRef<'tcx>,
16961697
expected: ty::PolyTraitRef<'tcx>,
16971698
cause: &ObligationCauseCode<'tcx>,
1699+
found_node: Option<Node<'_>>,
16981700
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
16991701
pub(crate) fn build_fn_sig_ty<'tcx>(
17001702
infcx: &InferCtxt<'tcx>,
@@ -1756,6 +1758,75 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
17561758

17571759
self.note_conflicting_closure_bounds(cause, &mut err);
17581760

1761+
let found_args = match found.kind() {
1762+
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
1763+
kind => {
1764+
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
1765+
}
1766+
};
1767+
let expected_args = match expected.kind() {
1768+
ty::FnPtr(f) => f.inputs().skip_binder().iter(),
1769+
kind => {
1770+
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
1771+
}
1772+
};
1773+
1774+
if let Some(found_node) = found_node {
1775+
let fn_decl = match found_node {
1776+
Node::Expr(expr) => match &expr.kind {
1777+
hir::ExprKind::Closure(hir::Closure { fn_decl, .. }) => fn_decl,
1778+
kind => {
1779+
span_bug!(found_span, "expression must be a closure but is {:?}", kind)
1780+
}
1781+
},
1782+
Node::Item(item) => match &item.kind {
1783+
hir::ItemKind::Fn(signature, _generics, _body) => signature.decl,
1784+
kind => {
1785+
span_bug!(found_span, "item must be a function but is {:?}", kind)
1786+
}
1787+
},
1788+
node => {
1789+
span_bug!(found_span, "node must be a expr or item but is {:?}", node)
1790+
}
1791+
};
1792+
1793+
let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span);
1794+
1795+
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
1796+
let mut refs = 0;
1797+
1798+
while let ty::Ref(_, new_ty, _) = ty.kind() {
1799+
ty = *new_ty;
1800+
refs += 1;
1801+
}
1802+
1803+
(ty, refs)
1804+
}
1805+
1806+
for ((found_arg, expected_arg), arg_span) in
1807+
found_args.zip(expected_args).zip(arg_spans)
1808+
{
1809+
let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
1810+
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
1811+
1812+
if found_ty == expected_ty {
1813+
let hint = if found_refs < expected_refs {
1814+
"hint: consider borrowing here:"
1815+
} else if found_refs == expected_refs {
1816+
continue;
1817+
} else {
1818+
"hint: consider removing the borrow:"
1819+
};
1820+
err.span_suggestion_verbose(
1821+
arg_span,
1822+
hint,
1823+
expected_arg.to_string(),
1824+
Applicability::MaybeIncorrect,
1825+
);
1826+
}
1827+
}
1828+
}
1829+
17591830
err
17601831
}
17611832

0 commit comments

Comments
 (0)