Skip to content

Commit 8843b28

Browse files
committed
Auto merge of #65951 - estebank:type-inference-error, r=nikomatsakis
Point at method call when type annotations are needed - Point at method call instead of whole expression when type annotations are needed. - Suggest use of turbofish on function and methods. Fix #49391, fix #46333, fix #48089. CC #58517, #63502, #63082. Fixes #40015 r? @nikomatsakis
2 parents ff15e96 + da023c0 commit 8843b28

File tree

63 files changed

+470
-135
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+470
-135
lines changed

src/librustc/infer/error_reporting/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ use std::{cmp, fmt};
7070
mod note;
7171

7272
mod need_type_info;
73+
pub use need_type_info::TypeAnnotationNeeded;
7374

7475
pub mod nice_region_error;
7576

src/librustc/infer/error_reporting/need_type_info.rs

+152-25
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
use crate::hir::def::Namespace;
1+
use crate::hir::def::{DefKind, Namespace};
22
use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat};
33
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
44
use crate::infer::InferCtxt;
55
use crate::infer::type_variable::TypeVariableOriginKind;
66
use crate::ty::{self, Ty, Infer, TyVar};
77
use crate::ty::print::Print;
88
use syntax::source_map::DesugaringKind;
9+
use syntax::symbol::kw;
910
use syntax_pos::Span;
1011
use errors::{Applicability, DiagnosticBuilder};
12+
use std::borrow::Cow;
1113

1214
use rustc_error_codes::*;
1315

@@ -19,6 +21,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
1921
found_arg_pattern: Option<&'tcx Pat>,
2022
found_ty: Option<Ty<'tcx>>,
2123
found_closure: Option<&'tcx ExprKind>,
24+
found_method_call: Option<&'tcx Expr>,
2225
}
2326

2427
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
@@ -35,6 +38,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
3538
found_arg_pattern: None,
3639
found_ty: None,
3740
found_closure: None,
41+
found_method_call: None,
3842
}
3943
}
4044

@@ -93,11 +97,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
9397
}
9498

9599
fn visit_expr(&mut self, expr: &'tcx Expr) {
96-
if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
97-
&expr.kind,
98-
self.node_matches_type(expr.hir_id),
99-
) {
100-
self.found_closure = Some(&expr.kind);
100+
if self.node_matches_type(expr.hir_id).is_some() {
101+
match expr.kind {
102+
ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
103+
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
104+
_ => {}
105+
}
101106
}
102107
intravisit::walk_expr(self, expr);
103108
}
@@ -109,6 +114,7 @@ fn closure_return_type_suggestion(
109114
err: &mut DiagnosticBuilder<'_>,
110115
output: &FunctionRetTy,
111116
body: &Body,
117+
descr: &str,
112118
name: &str,
113119
ret: &str,
114120
) {
@@ -132,7 +138,7 @@ fn closure_return_type_suggestion(
132138
suggestion,
133139
Applicability::HasPlaceholders,
134140
);
135-
err.span_label(span, InferCtxt::missing_type_msg(&name));
141+
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr));
136142
}
137143

138144
/// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -147,17 +153,42 @@ fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
147153
.unwrap_or_default()
148154
}
149155

156+
pub enum TypeAnnotationNeeded {
157+
E0282,
158+
E0283,
159+
E0284,
160+
}
161+
162+
impl Into<errors::DiagnosticId> for TypeAnnotationNeeded {
163+
fn into(self) -> errors::DiagnosticId {
164+
syntax::diagnostic_used!(E0282);
165+
syntax::diagnostic_used!(E0283);
166+
syntax::diagnostic_used!(E0284);
167+
errors::DiagnosticId::Error(match self {
168+
Self::E0282 => "E0282".to_string(),
169+
Self::E0283 => "E0283".to_string(),
170+
Self::E0284 => "E0284".to_string(),
171+
})
172+
}
173+
}
174+
150175
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
151176
pub fn extract_type_name(
152177
&self,
153178
ty: Ty<'tcx>,
154179
highlight: Option<ty::print::RegionHighlightMode>,
155-
) -> (String, Option<Span>) {
180+
) -> (String, Option<Span>, Cow<'static, str>) {
156181
if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
157182
let ty_vars = self.type_variables.borrow();
158183
let var_origin = ty_vars.var_origin(ty_vid);
159184
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
160-
return (name.to_string(), Some(var_origin.span));
185+
if name != kw::SelfUpper {
186+
return (
187+
name.to_string(),
188+
Some(var_origin.span),
189+
"type parameter".into(),
190+
);
191+
}
161192
}
162193
}
163194

@@ -167,26 +198,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
167198
printer.region_highlight_mode = highlight;
168199
}
169200
let _ = ty.print(printer);
170-
(s, None)
201+
(s, None, ty.prefix_string())
171202
}
172203

173204
pub fn need_type_info_err(
174205
&self,
175206
body_id: Option<hir::BodyId>,
176207
span: Span,
177208
ty: Ty<'tcx>,
209+
error_code: TypeAnnotationNeeded,
178210
) -> DiagnosticBuilder<'tcx> {
179211
let ty = self.resolve_vars_if_possible(&ty);
180-
let (name, name_sp) = self.extract_type_name(&ty, None);
212+
let (name, name_sp, descr) = self.extract_type_name(&ty, None);
181213

182214
let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
183215
let ty_to_string = |ty: Ty<'tcx>| -> String {
184216
let mut s = String::new();
185217
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
186218
let ty_vars = self.type_variables.borrow();
187219
let getter = move |ty_vid| {
188-
if let TypeVariableOriginKind::TypeParameterDefinition(name) =
189-
ty_vars.var_origin(ty_vid).kind {
220+
let var_origin = ty_vars.var_origin(ty_vid);
221+
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
190222
return Some(name.to_string());
191223
}
192224
None
@@ -210,6 +242,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
210242
// 3 | let _ = x.sum() as f64;
211243
// | ^^^ cannot infer type for `S`
212244
span
245+
} else if let Some(
246+
ExprKind::MethodCall(_, call_span, _),
247+
) = local_visitor.found_method_call.map(|e| &e.kind) {
248+
// Point at the call instead of the whole expression:
249+
// error[E0284]: type annotations needed
250+
// --> file.rs:2:5
251+
// |
252+
// 2 | vec![Ok(2)].into_iter().collect()?;
253+
// | ^^^^^^^ cannot infer type
254+
// |
255+
// = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
256+
if span.contains(*call_span) {
257+
*call_span
258+
} else {
259+
span
260+
}
213261
} else {
214262
span
215263
};
@@ -247,12 +295,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
247295
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
248296
// | the type parameter `E` is specified
249297
// ```
250-
let mut err = struct_span_err!(
251-
self.tcx.sess,
298+
let error_code = error_code.into();
299+
let mut err = self.tcx.sess.struct_span_err_with_code(
252300
err_span,
253-
E0282,
254-
"type annotations needed{}",
255-
ty_msg,
301+
&format!("type annotations needed{}", ty_msg),
302+
error_code,
256303
);
257304

258305
let suffix = match local_visitor.found_ty {
@@ -267,6 +314,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
267314
&mut err,
268315
&decl.output,
269316
&body,
317+
&descr,
270318
&name,
271319
&ret,
272320
);
@@ -334,6 +382,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
334382
format!("consider giving this pattern {}", suffix)
335383
};
336384
err.span_label(pattern.span, msg);
385+
} else if let Some(e) = local_visitor.found_method_call {
386+
if let ExprKind::MethodCall(segment, ..) = &e.kind {
387+
// Suggest specifiying type params or point out the return type of the call:
388+
//
389+
// error[E0282]: type annotations needed
390+
// --> $DIR/type-annotations-needed-expr.rs:2:39
391+
// |
392+
// LL | let _ = x.into_iter().sum() as f64;
393+
// | ^^^
394+
// | |
395+
// | cannot infer type for `S`
396+
// | help: consider specifying the type argument in
397+
// | the method call: `sum::<S>`
398+
// |
399+
// = note: type must be known at this point
400+
//
401+
// or
402+
//
403+
// error[E0282]: type annotations needed
404+
// --> $DIR/issue-65611.rs:59:20
405+
// |
406+
// LL | let x = buffer.last().unwrap().0.clone();
407+
// | -------^^^^--
408+
// | | |
409+
// | | cannot infer type for `T`
410+
// | this method call resolves to `std::option::Option<&T>`
411+
// |
412+
// = note: type must be known at this point
413+
self.annotate_method_call(segment, e, &mut err);
414+
}
337415
}
338416
// Instead of the following:
339417
// error[E0282]: type annotations needed
@@ -351,37 +429,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
351429
// | ^^^ cannot infer type for `S`
352430
// |
353431
// = note: type must be known at this point
354-
let span = name_sp.unwrap_or(span);
432+
let span = name_sp.unwrap_or(err_span);
355433
if !err.span.span_labels().iter().any(|span_label| {
356434
span_label.label.is_some() && span_label.span == span
357435
}) && local_visitor.found_arg_pattern.is_none()
358436
{ // Avoid multiple labels pointing at `span`.
359-
err.span_label(span, InferCtxt::missing_type_msg(&name));
437+
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr));
360438
}
361439

362440
err
363441
}
364442

443+
/// If the `FnSig` for the method call can be found and type arguments are identified as
444+
/// needed, suggest annotating the call, otherwise point out the resulting type of the call.
445+
fn annotate_method_call(
446+
&self,
447+
segment: &hir::ptr::P<hir::PathSegment>,
448+
e: &Expr,
449+
err: &mut DiagnosticBuilder<'_>,
450+
) {
451+
if let (Ok(snippet), Some(tables), None) = (
452+
self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
453+
self.in_progress_tables,
454+
&segment.args,
455+
) {
456+
let borrow = tables.borrow();
457+
if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) {
458+
let generics = self.tcx.generics_of(did);
459+
if !generics.params.is_empty() {
460+
err.span_suggestion(
461+
segment.ident.span,
462+
&format!(
463+
"consider specifying the type argument{} in the method call",
464+
if generics.params.len() > 1 {
465+
"s"
466+
} else {
467+
""
468+
},
469+
),
470+
format!("{}::<{}>", snippet, generics.params.iter()
471+
.map(|p| p.name.to_string())
472+
.collect::<Vec<String>>()
473+
.join(", ")),
474+
Applicability::HasPlaceholders,
475+
);
476+
} else {
477+
let sig = self.tcx.fn_sig(did);
478+
let bound_output = sig.output();
479+
let output = bound_output.skip_binder();
480+
err.span_label(e.span, &format!("this method call resolves to `{:?}`", output));
481+
let kind = &output.kind;
482+
if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind {
483+
if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
484+
err.span_label(span, &format!("`{:?}` defined here", output));
485+
}
486+
}
487+
}
488+
}
489+
}
490+
}
491+
365492
pub fn need_type_info_err_in_generator(
366493
&self,
367494
kind: hir::GeneratorKind,
368495
span: Span,
369496
ty: Ty<'tcx>,
370497
) -> DiagnosticBuilder<'tcx> {
371498
let ty = self.resolve_vars_if_possible(&ty);
372-
let name = self.extract_type_name(&ty, None).0;
499+
let (name, _, descr) = self.extract_type_name(&ty, None);
373500
let mut err = struct_span_err!(
374501
self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind,
375502
);
376-
err.span_label(span, InferCtxt::missing_type_msg(&name));
503+
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr));
377504
err
378505
}
379506

380-
fn missing_type_msg(type_name: &str) -> String {
507+
fn missing_type_msg(type_name: &str, descr: &str) -> Cow<'static, str>{
381508
if type_name == "_" {
382-
"cannot infer type".to_owned()
509+
"cannot infer type".into()
383510
} else {
384-
format!("cannot infer type for `{}`", type_name)
511+
format!("cannot infer type for {} `{}`", descr, type_name).into()
385512
}
386513
}
387514
}

0 commit comments

Comments
 (0)