Skip to content

Commit 33e11a3

Browse files
committed
Tweak "borrow closure argument" suggestion
Fix rust-lang#45727.
1 parent 19423b5 commit 33e11a3

9 files changed

+127
-47
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
13501350
expected_trait_ref,
13511351
obligation.cause.code(),
13521352
found_node,
1353+
obligation.param_env,
13531354
)
13541355
} else {
13551356
let (closure_span, closure_arg_span, found) = found_did

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

+25-8
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ pub trait TypeErrCtxtExt<'tcx> {
283283
expected: ty::PolyTraitRef<'tcx>,
284284
cause: &ObligationCauseCode<'tcx>,
285285
found_node: Option<Node<'_>>,
286+
param_env: ty::ParamEnv<'tcx>,
286287
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
287288

288289
fn note_conflicting_closure_bounds(
@@ -1978,6 +1979,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
19781979
expected: ty::PolyTraitRef<'tcx>,
19791980
cause: &ObligationCauseCode<'tcx>,
19801981
found_node: Option<Node<'_>>,
1982+
param_env: ty::ParamEnv<'tcx>,
19811983
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
19821984
pub(crate) fn build_fn_sig_ty<'tcx>(
19831985
infcx: &InferCtxt<'tcx>,
@@ -2040,7 +2042,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
20402042
self.note_conflicting_closure_bounds(cause, &mut err);
20412043

20422044
if let Some(found_node) = found_node {
2043-
hint_missing_borrow(span, found, expected, found_node, &mut err);
2045+
hint_missing_borrow(self, param_env, span, found, expected, found_node, &mut err);
20442046
}
20452047

20462048
err
@@ -3747,6 +3749,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
37473749

37483750
/// Add a hint to add a missing borrow or remove an unnecessary one.
37493751
fn hint_missing_borrow<'tcx>(
3752+
infcx: &InferCtxt<'tcx>,
3753+
param_env: ty::ParamEnv<'tcx>,
37503754
span: Span,
37513755
found: Ty<'tcx>,
37523756
expected: Ty<'tcx>,
@@ -3769,7 +3773,7 @@ fn hint_missing_borrow<'tcx>(
37693773
// This could be a variant constructor, for example.
37703774
let Some(fn_decl) = found_node.fn_decl() else { return; };
37713775

3772-
let arg_spans = fn_decl.inputs.iter().map(|ty| ty.span);
3776+
let args = fn_decl.inputs.iter().map(|ty| ty);
37733777

37743778
fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
37753779
let mut refs = 0;
@@ -3785,29 +3789,42 @@ fn hint_missing_borrow<'tcx>(
37853789
let mut to_borrow = Vec::new();
37863790
let mut remove_borrow = Vec::new();
37873791

3788-
for ((found_arg, expected_arg), arg_span) in found_args.zip(expected_args).zip(arg_spans) {
3792+
for ((found_arg, expected_arg), arg) in found_args.zip(expected_args).zip(args) {
37893793
let (found_ty, found_refs) = get_deref_type_and_refs(*found_arg);
37903794
let (expected_ty, expected_refs) = get_deref_type_and_refs(*expected_arg);
37913795

3792-
if found_ty == expected_ty {
3796+
if infcx.can_eq(param_env, found_ty, expected_ty).is_ok() {
37933797
if found_refs < expected_refs {
3794-
to_borrow.push((arg_span, expected_arg.to_string()));
3798+
to_borrow.push((arg.span.shrink_to_lo(), "&".repeat(expected_refs - found_refs)));
37953799
} else if found_refs > expected_refs {
3796-
remove_borrow.push((arg_span, expected_arg.to_string()));
3800+
let mut span = arg.span.shrink_to_lo();
3801+
let mut left = found_refs - expected_refs;
3802+
let mut ty = arg;
3803+
while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
3804+
span = span.with_hi(mut_ty.ty.span.lo());
3805+
ty = mut_ty.ty;
3806+
left -= 1;
3807+
}
3808+
let sugg = if left == 0 {
3809+
(span, String::new())
3810+
} else {
3811+
(arg.span, expected_arg.to_string())
3812+
};
3813+
remove_borrow.push(sugg);
37973814
}
37983815
}
37993816
}
38003817

38013818
if !to_borrow.is_empty() {
3802-
err.multipart_suggestion(
3819+
err.multipart_suggestion_verbose(
38033820
"consider borrowing the argument",
38043821
to_borrow,
38053822
Applicability::MaybeIncorrect,
38063823
);
38073824
}
38083825

38093826
if !remove_borrow.is_empty() {
3810-
err.multipart_suggestion(
3827+
err.multipart_suggestion_verbose(
38113828
"do not borrow the argument",
38123829
remove_borrow,
38133830
Applicability::MaybeIncorrect,

tests/ui/anonymous-higher-ranked-lifetime.stderr

+35-27
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
1616
help: consider borrowing the argument
1717
|
1818
LL | f1(|_: &(), _: &()| {});
19-
| ~~~ ~~~
19+
| + +
2020

2121
error[E0631]: type mismatch in closure arguments
2222
--> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
@@ -35,8 +35,8 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
3535
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2`
3636
help: consider borrowing the argument
3737
|
38-
LL | f2(|_: &'a (), _: &()| {});
39-
| ~~~~~~ ~~~
38+
LL | f2(|_: &(), _: &()| {});
39+
| + +
4040

4141
error[E0631]: type mismatch in closure arguments
4242
--> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
@@ -56,7 +56,7 @@ LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
5656
help: consider borrowing the argument
5757
|
5858
LL | f3(|_: &(), _: &()| {});
59-
| ~~~ ~~~
59+
| + +
6060

6161
error[E0631]: type mismatch in closure arguments
6262
--> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
@@ -75,8 +75,8 @@ LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
7575
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4`
7676
help: consider borrowing the argument
7777
|
78-
LL | f4(|_: &(), _: &'r ()| {});
79-
| ~~~ ~~~~~~
78+
LL | f4(|_: &(), _: &()| {});
79+
| + +
8080

8181
error[E0631]: type mismatch in closure arguments
8282
--> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
@@ -95,17 +95,15 @@ LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
9595
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5`
9696
help: consider borrowing the argument
9797
|
98-
LL | f5(|_: &'r (), _: &'r ()| {});
99-
| ~~~~~~ ~~~~~~
98+
LL | f5(|_: &(), _: &()| {});
99+
| + +
100100

101101
error[E0631]: type mismatch in closure arguments
102102
--> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
103103
|
104104
LL | g1(|_: (), _: ()| {});
105-
| ^^ --------------
106-
| | | |
107-
| | | help: consider borrowing the argument: `&()`
108-
| | found signature defined here
105+
| ^^ -------------- found signature defined here
106+
| |
109107
| expected due to this
110108
|
111109
= note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
@@ -115,15 +113,17 @@ note: required by a bound in `g1`
115113
|
116114
LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {}
117115
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1`
116+
help: consider borrowing the argument
117+
|
118+
LL | g1(|_: &(), _: ()| {});
119+
| +
118120

119121
error[E0631]: type mismatch in closure arguments
120122
--> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
121123
|
122124
LL | g2(|_: (), _: ()| {});
123-
| ^^ --------------
124-
| | | |
125-
| | | help: consider borrowing the argument: `&()`
126-
| | found signature defined here
125+
| ^^ -------------- found signature defined here
126+
| |
127127
| expected due to this
128128
|
129129
= note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _`
@@ -133,15 +133,17 @@ note: required by a bound in `g2`
133133
|
134134
LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
135135
| ^^^^^^^^^^^^^^^^ required by this bound in `g2`
136+
help: consider borrowing the argument
137+
|
138+
LL | g2(|_: &(), _: ()| {});
139+
| +
136140

137141
error[E0631]: type mismatch in closure arguments
138142
--> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
139143
|
140144
LL | g3(|_: (), _: ()| {});
141-
| ^^ --------------
142-
| | | |
143-
| | | help: consider borrowing the argument: `&'s ()`
144-
| | found signature defined here
145+
| ^^ -------------- found signature defined here
146+
| |
145147
| expected due to this
146148
|
147149
= note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _`
@@ -151,15 +153,17 @@ note: required by a bound in `g3`
151153
|
152154
LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {}
153155
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3`
156+
help: consider borrowing the argument
157+
|
158+
LL | g3(|_: &(), _: ()| {});
159+
| +
154160

155161
error[E0631]: type mismatch in closure arguments
156162
--> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
157163
|
158164
LL | g4(|_: (), _: ()| {});
159-
| ^^ --------------
160-
| | | |
161-
| | | help: consider borrowing the argument: `&()`
162-
| | found signature defined here
165+
| ^^ -------------- found signature defined here
166+
| |
163167
| expected due to this
164168
|
165169
= note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _`
@@ -169,6 +173,10 @@ note: required by a bound in `g4`
169173
|
170174
LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
171175
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4`
176+
help: consider borrowing the argument
177+
|
178+
LL | g4(|_: &(), _: ()| {});
179+
| +
172180

173181
error[E0631]: type mismatch in closure arguments
174182
--> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
@@ -188,7 +196,7 @@ LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {}
188196
help: consider borrowing the argument
189197
|
190198
LL | h1(|_: &(), _: (), _: &(), _: ()| {});
191-
| ~~~ ~~~
199+
| + +
192200

193201
error[E0631]: type mismatch in closure arguments
194202
--> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
@@ -207,8 +215,8 @@ LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(),
207215
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2`
208216
help: consider borrowing the argument
209217
|
210-
LL | h2(|_: &(), _: (), _: &'t0 (), _: ()| {});
211-
| ~~~ ~~~~~~~
218+
LL | h2(|_: &(), _: (), _: &(), _: ()| {});
219+
| + +
212220

213221
error: aborting due to 11 previous errors
214222

tests/ui/closures/multiple-fn-bounds.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ error[E0631]: type mismatch in closure arguments
22
--> $DIR/multiple-fn-bounds.rs:10:5
33
|
44
LL | foo(move |x| v);
5-
| ^^^ --------
6-
| | | |
7-
| | | help: do not borrow the argument: `char`
8-
| | found signature defined here
5+
| ^^^ -------- found signature defined here
6+
| |
97
| expected due to this
108
|
119
= note: expected closure signature `fn(char) -> _`
@@ -20,6 +18,10 @@ note: required by a bound in `foo`
2018
|
2119
LL | fn foo<F: Fn(&char) -> bool + Fn(char) -> bool>(f: F) {
2220
| ^^^^^^^^^^^^^^^^ required by this bound in `foo`
21+
help: do not borrow the argument
22+
|
23+
LL | foo(move |char| v);
24+
| ~~~~
2325

2426
error: aborting due to previous error
2527

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// run-rustfix
2+
fn main() {
3+
let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
4+
let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// run-rustfix
2+
fn main() {
3+
let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
4+
let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error[E0631]: type mismatch in closure arguments
2+
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24
3+
|
4+
LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0);
5+
| ^^^^ -------- found signature defined here
6+
| |
7+
| expected due to this
8+
|
9+
= note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
10+
found closure signature `fn(i32) -> _`
11+
note: required by a bound in `find`
12+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
13+
help: consider borrowing the argument
14+
|
15+
LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
16+
| +
17+
18+
error[E0631]: type mismatch in closure arguments
19+
--> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24
20+
|
21+
LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
22+
| ^^^^ ----------- found signature defined here
23+
| |
24+
| expected due to this
25+
|
26+
= note: expected closure signature `for<'a> fn(&'a {integer}) -> _`
27+
found closure signature `for<'a, 'b, 'c> fn(&'a &'b &'c i32) -> _`
28+
note: required by a bound in `find`
29+
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
30+
help: do not borrow the argument
31+
|
32+
LL - let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0);
33+
LL + let _ = (-10..=10).find(|x: &i32| x.signum() == 0);
34+
|
35+
36+
error: aborting due to 2 previous errors
37+
38+
For more information about this error, try `rustc --explain E0631`.

tests/ui/mismatched_types/closure-arg-type-mismatch.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments
22
--> $DIR/closure-arg-type-mismatch.rs:3:14
33
|
44
LL | a.iter().map(|_: (u32, u32)| 45);
5-
| ^^^ ---------------
6-
| | | |
7-
| | | help: consider borrowing the argument: `&(u32, u32)`
8-
| | found signature defined here
5+
| ^^^ --------------- found signature defined here
6+
| |
97
| expected due to this
108
|
119
= note: expected closure signature `fn(&(u32, u32)) -> _`
1210
found closure signature `fn((u32, u32)) -> _`
1311
note: required by a bound in `map`
1412
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
13+
help: consider borrowing the argument
14+
|
15+
LL | a.iter().map(|_: &(u32, u32)| 45);
16+
| +
1517

1618
error[E0631]: type mismatch in closure arguments
1719
--> $DIR/closure-arg-type-mismatch.rs:4:14

tests/ui/mismatched_types/issue-36053-2.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,18 @@ error[E0631]: type mismatch in closure arguments
22
--> $DIR/issue-36053-2.rs:7:32
33
|
44
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
5-
| ^^^^^^ ---------
6-
| | | |
7-
| | | help: consider borrowing the argument: `&&str`
8-
| | found signature defined here
5+
| ^^^^^^ --------- found signature defined here
6+
| |
97
| expected due to this
108
|
119
= note: expected closure signature `for<'a> fn(&'a &str) -> _`
1210
found closure signature `for<'a> fn(&'a str) -> _`
1311
note: required by a bound in `filter`
1412
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
13+
help: consider borrowing the argument
14+
|
15+
LL | once::<&str>("str").fuse().filter(|a: &&str| true).count();
16+
| +
1517

1618
error[E0599]: the method `count` exists for struct `Filter<Fuse<Once<&str>>, [closure@issue-36053-2.rs:7:39]>`, but its trait bounds were not satisfied
1719
--> $DIR/issue-36053-2.rs:7:55

0 commit comments

Comments
 (0)