Skip to content

Commit 6c3a98e

Browse files
committed
review comments
1 parent 806476c commit 6c3a98e

File tree

1 file changed

+73
-64
lines changed

1 file changed

+73
-64
lines changed

src/librustc/infer/error_reporting/need_type_info.rs

+73-64
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
2424
infcx: &'a InferCtxt<'a, 'tcx>,
2525
target_ty: Ty<'tcx>,
2626
hir_map: &'a hir::map::Map<'tcx>,
27-
) -> FindLocalByTypeVisitor<'a, 'tcx> {
28-
FindLocalByTypeVisitor {
27+
) -> Self {
28+
Self {
2929
infcx,
3030
target_ty,
3131
hir_map,
@@ -101,6 +101,50 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
101101
}
102102
}
103103

104+
/// Suggest giving an appropriate return type to a closure expression.
105+
fn closure_return_type_suggestion(
106+
span: Span,
107+
err: &mut DiagnosticBuilder<'_>,
108+
output: &FunctionRetTy,
109+
body: &Body,
110+
name: &str,
111+
ret: &str,
112+
) {
113+
let (arrow, post) = match output {
114+
FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
115+
_ => ("", ""),
116+
};
117+
let suggestion = match body.value.node {
118+
ExprKind::Block(..) => {
119+
vec![(output.span(), format!("{}{}{}", arrow, ret, post))]
120+
}
121+
_ => {
122+
vec![
123+
(output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
124+
(body.value.span.shrink_to_hi(), " }".to_string()),
125+
]
126+
}
127+
};
128+
err.multipart_suggestion(
129+
"give this closure an explicit return type without `_` placeholders",
130+
suggestion,
131+
Applicability::HasPlaceholders,
132+
);
133+
err.span_label(span, InferCtxt::missing_type_msg(&name));
134+
}
135+
136+
/// Given a closure signature, return a `String` containing a list of all its argument types.
137+
fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
138+
fn_sig.inputs()
139+
.skip_binder()
140+
.iter()
141+
.next()
142+
.map(|args| args.tuple_fields()
143+
.map(|arg| arg.to_string())
144+
.collect::<Vec<_>>().join(", "))
145+
.unwrap_or_default()
146+
}
147+
104148
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
105149
pub fn extract_type_name(
106150
&self,
@@ -160,24 +204,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
160204
span
161205
};
162206

207+
let is_named_and_not_impl_trait = |ty: Ty<'_>| {
208+
&ty.to_string() != "_" &&
209+
// FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
210+
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
211+
};
212+
163213
let ty_msg = match local_visitor.found_ty {
164214
Some(ty::TyS { sty: ty::Closure(def_id, substs), .. }) => {
165215
let fn_sig = substs.closure_sig(*def_id, self.tcx);
166-
let args = fn_sig.inputs()
167-
.skip_binder()
168-
.iter()
169-
.next()
170-
.map(|args| args.tuple_fields()
171-
.map(|arg| arg.to_string())
172-
.collect::<Vec<_>>().join(", "))
173-
.unwrap_or_default();
216+
let args = closure_args(&fn_sig);
174217
let ret = fn_sig.output().skip_binder().to_string();
175218
format!(" for the closure `fn({}) -> {}`", args, ret)
176219
}
177-
Some(ty) if &ty.to_string() != "_" &&
178-
// FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
179-
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) =>
180-
{
220+
Some(ty) if is_named_and_not_impl_trait(ty) => {
181221
let ty = ty_to_string(ty);
182222
format!(" for `{}`", ty)
183223
}
@@ -211,59 +251,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
211251
let ret = fn_sig.output().skip_binder().to_string();
212252

213253
if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure {
214-
let (arrow, post) = match decl.output {
215-
FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
216-
_ => ("", ""),
217-
};
218254
if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) {
219-
let suggestion = match body.value.node {
220-
ExprKind::Block(..) => {
221-
vec![(decl.output.span(), format!("{}{}{}", arrow, ret, post))]
222-
}
223-
_ => {
224-
vec![
225-
(decl.output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
226-
(body.value.span.shrink_to_hi(), " }".to_string()),
227-
]
228-
}
229-
};
230-
err.multipart_suggestion(
231-
"give this closure an explicit return type without `_` placeholders",
232-
suggestion,
233-
Applicability::HasPlaceholders,
255+
closure_return_type_suggestion(
256+
span,
257+
&mut err,
258+
&decl.output,
259+
&body,
260+
&name,
261+
&ret,
234262
);
235-
err.span_label(span, InferCtxt::missing_type_msg(&name));
263+
// We don't want to give the other suggestions when the problem is the
264+
// closure return type.
236265
return err;
237266
}
238267
}
239268

240269
// This shouldn't be reachable, but just in case we leave a reasonable fallback.
241-
let args = fn_sig.inputs()
242-
.skip_binder()
243-
.iter()
244-
.next()
245-
.map(|args| args.tuple_fields()
246-
.map(|arg| arg.to_string())
247-
.collect::<Vec<_>>().join(", "))
248-
.unwrap_or_default();
270+
let args = closure_args(&fn_sig);
249271
// This suggestion is incomplete, as the user will get further type inference
250272
// errors due to the `_` placeholders and the introduction of `Box`, but it does
251273
// nudge them in the right direction.
252274
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
253275
}
254-
Some(ty) if &ty.to_string() != "_" &&
255-
name == "_" &&
256-
// FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
257-
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) =>
258-
{
276+
Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
259277
let ty = ty_to_string(ty);
260278
format!("the explicit type `{}`, with the type parameters specified", ty)
261279
}
262-
Some(ty) if &ty.to_string() != "_" &&
263-
ty.to_string() != name &&
264-
// FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527
265-
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) =>
266-
{
280+
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
267281
let ty = ty_to_string(ty);
268282
format!(
269283
"the explicit type `{}`, where the type parameter `{}` is specified",
@@ -296,25 +310,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
296310
format!("consider giving this closure parameter {}", suffix),
297311
);
298312
} else if let Some(pattern) = local_visitor.found_local_pattern {
299-
if let Some(simple_ident) = pattern.simple_ident() {
313+
let msg = if let Some(simple_ident) = pattern.simple_ident() {
300314
match pattern.span.desugaring_kind() {
301315
None => {
302-
err.span_label(
303-
pattern.span,
304-
format!("consider giving `{}` {}", simple_ident, suffix),
305-
);
316+
format!("consider giving `{}` {}", simple_ident, suffix)
306317
}
307318
Some(DesugaringKind::ForLoop) => {
308-
err.span_label(
309-
pattern.span,
310-
"the element type for this iterator is not specified".to_string(),
311-
);
319+
"the element type for this iterator is not specified".to_string()
312320
}
313-
_ => {}
321+
_ => format!("this needs {}", suffix),
314322
}
315323
} else {
316-
err.span_label(pattern.span, format!("consider giving this pattern {}", suffix));
317-
}
324+
format!("consider giving this pattern {}", suffix)
325+
};
326+
err.span_label(pattern.span, msg);
318327
}
319328
if !err.span.span_labels().iter().any(|span_label| {
320329
span_label.label.is_some() && span_label.span == span

0 commit comments

Comments
 (0)