@@ -15,17 +15,18 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
1515 hir_map : & ' a hir:: map:: Map < ' gcx > ,
1616 found_local_pattern : Option < & ' gcx Pat > ,
1717 found_arg_pattern : Option < & ' gcx Pat > ,
18+ found_ty : Option < Ty < ' tcx > > ,
1819}
1920
2021impl < ' a , ' gcx , ' tcx > FindLocalByTypeVisitor < ' a , ' gcx , ' tcx > {
21- fn node_matches_type ( & mut self , hir_id : HirId ) -> bool {
22+ fn node_matches_type ( & mut self , hir_id : HirId ) -> Option < Ty < ' tcx > > {
2223 let ty_opt = self . infcx . in_progress_tables . and_then ( |tables| {
2324 tables. borrow ( ) . node_type_opt ( hir_id)
2425 } ) ;
2526 match ty_opt {
2627 Some ( ty) => {
2728 let ty = self . infcx . resolve_vars_if_possible ( & ty) ;
28- ty. walk ( ) . any ( |inner_ty| {
29+ if ty. walk ( ) . any ( |inner_ty| {
2930 inner_ty == self . target_ty || match ( & inner_ty. sty , & self . target_ty . sty ) {
3031 ( & Infer ( TyVar ( a_vid) ) , & Infer ( TyVar ( b_vid) ) ) => {
3132 self . infcx
@@ -35,9 +36,13 @@ impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
3536 }
3637 _ => false ,
3738 }
38- } )
39+ } ) {
40+ Some ( ty)
41+ } else {
42+ None
43+ }
3944 }
40- None => false ,
45+ None => None ,
4146 }
4247 }
4348}
@@ -48,16 +53,21 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
4853 }
4954
5055 fn visit_local ( & mut self , local : & ' gcx Local ) {
51- if self . found_local_pattern . is_none ( ) && self . node_matches_type ( local. hir_id ) {
56+ if let ( None , Some ( ty ) ) = ( self . found_local_pattern , self . node_matches_type ( local. hir_id ) ) {
5257 self . found_local_pattern = Some ( & * local. pat ) ;
58+ self . found_ty = Some ( ty) ;
5359 }
5460 intravisit:: walk_local ( self , local) ;
5561 }
5662
5763 fn visit_body ( & mut self , body : & ' gcx Body ) {
5864 for argument in & body. arguments {
59- if self . found_arg_pattern . is_none ( ) && self . node_matches_type ( argument. hir_id ) {
65+ if let ( None , Some ( ty) ) = (
66+ self . found_arg_pattern ,
67+ self . node_matches_type ( argument. hir_id ) ,
68+ ) {
6069 self . found_arg_pattern = Some ( & * argument. pat ) ;
70+ self . found_ty = Some ( ty) ;
6171 }
6272 }
6373 intravisit:: walk_body ( self , body) ;
@@ -98,21 +108,68 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
98108 let name = self . extract_type_name ( & ty, None ) ;
99109
100110 let mut err_span = span;
101- let mut labels = vec ! [ ( span, InferCtxt :: missing_type_msg( & name) ) ] ;
102111
103112 let mut local_visitor = FindLocalByTypeVisitor {
104113 infcx : & self ,
105114 target_ty : ty,
106115 hir_map : & self . tcx . hir ( ) ,
107116 found_local_pattern : None ,
108117 found_arg_pattern : None ,
118+ found_ty : None ,
119+ } ;
120+ let ty_to_string = |ty : Ty < ' tcx > | -> String {
121+ let mut s = String :: new ( ) ;
122+ let mut printer = ty:: print:: FmtPrinter :: new ( self . tcx , & mut s, Namespace :: TypeNS ) ;
123+ let ty_vars = self . type_variables . borrow ( ) ;
124+ let getter = move |ty_vid| {
125+ if let TypeVariableOrigin :: TypeParameterDefinition ( _, name) =
126+ * ty_vars. var_origin ( ty_vid) {
127+ return Some ( name. to_string ( ) ) ;
128+ }
129+ None
130+ } ;
131+ printer. name_resolver = Some ( Box :: new ( & getter) ) ;
132+ let _ = ty. print ( printer) ;
133+ s
109134 } ;
110135
111136 if let Some ( body_id) = body_id {
112137 let expr = self . tcx . hir ( ) . expect_expr_by_hir_id ( body_id. hir_id ) ;
113138 local_visitor. visit_expr ( expr) ;
114139 }
115140
141+ // When `name` corresponds to a type argument, show the path of the full type we're
142+ // trying to infer. In the following example, `ty_msg` contains
143+ // " in `std::result::Result<i32, E>`":
144+ // ```
145+ // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
146+ // --> file.rs:L:CC
147+ // |
148+ // L | let b = Ok(4);
149+ // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
150+ // | |
151+ // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
152+ // | the type parameter `E` is specified
153+ // ```
154+ let ( ty_msg, suffix) = match & local_visitor. found_ty {
155+ Some ( ty) if & ty. to_string ( ) != "_" && name == "_" => {
156+ let ty = ty_to_string ( ty) ;
157+ ( format ! ( " for `{}`" , ty) ,
158+ format ! ( "the explicit type `{}`, with the type parameters specified" , ty) )
159+ }
160+ Some ( ty) if & ty. to_string ( ) != "_" && ty. to_string ( ) != name => {
161+ let ty = ty_to_string ( ty) ;
162+ ( format ! ( " for `{}`" , ty) ,
163+ format ! (
164+ "the explicit type `{}`, where the type parameter `{}` is specified" ,
165+ ty,
166+ name,
167+ ) )
168+ }
169+ _ => ( String :: new ( ) , "a type" . to_owned ( ) ) ,
170+ } ;
171+ let mut labels = vec ! [ ( span, InferCtxt :: missing_type_msg( & name) ) ] ;
172+
116173 if let Some ( pattern) = local_visitor. found_arg_pattern {
117174 err_span = pattern. span ;
118175 // We don't want to show the default label for closures.
@@ -128,31 +185,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
128185 // After clearing, it looks something like this:
129186 // ```
130187 // let x = |_| { };
131- // ^ consider giving this closure parameter a type
188+ // ^ consider giving this closure parameter the type `[_; 0]`
189+ // with the type parameter `_` specified
132190 // ```
133191 labels. clear ( ) ;
134- labels. push (
135- ( pattern. span , "consider giving this closure parameter a type" . to_owned ( ) ) ) ;
192+ labels. push ( (
193+ pattern. span ,
194+ format ! ( "consider giving this closure parameter {}" , suffix) ,
195+ ) ) ;
136196 } else if let Some ( pattern) = local_visitor. found_local_pattern {
137197 if let Some ( simple_ident) = pattern. simple_ident ( ) {
138198 match pattern. span . compiler_desugaring_kind ( ) {
139- None => labels. push ( ( pattern. span ,
140- format ! ( "consider giving `{}` a type" , simple_ident) ) ) ,
199+ None => labels. push ( (
200+ pattern. span ,
201+ format ! ( "consider giving `{}` {}" , simple_ident, suffix) ,
202+ ) ) ,
141203 Some ( CompilerDesugaringKind :: ForLoop ) => labels. push ( (
142204 pattern. span ,
143205 "the element type for this iterator is not specified" . to_owned ( ) ,
144206 ) ) ,
145207 _ => { }
146208 }
147209 } else {
148- labels. push ( ( pattern. span , "consider giving the pattern a type" . to_owned ( ) ) ) ;
210+ labels. push ( ( pattern. span , format ! ( "consider giving this pattern {}" , suffix ) ) ) ;
149211 }
150- }
212+ } ;
151213
152- let mut err = struct_span_err ! ( self . tcx. sess,
153- err_span,
154- E0282 ,
155- "type annotations needed" ) ;
214+ let mut err = struct_span_err ! (
215+ self . tcx. sess,
216+ err_span,
217+ E0282 ,
218+ "type annotations needed{}" ,
219+ ty_msg,
220+ ) ;
156221
157222 for ( target_span, label_message) in labels {
158223 err. span_label ( target_span, label_message) ;
0 commit comments