@@ -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) ;
@@ -106,13 +116,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
106116 hir_map : & self . tcx . hir ( ) ,
107117 found_local_pattern : None ,
108118 found_arg_pattern : None ,
119+ found_ty : None ,
109120 } ;
110121
111122 if let Some ( body_id) = body_id {
112123 let expr = self . tcx . hir ( ) . expect_expr_by_hir_id ( body_id. hir_id ) ;
113124 local_visitor. visit_expr ( expr) ;
114125 }
115126
127+ let ty_msg = match local_visitor. found_ty {
128+ Some ( ty) if & ty. to_string ( ) != "_" => format ! ( " for `{}`" , ty) ,
129+ _ => String :: new ( ) ,
130+ } ;
116131 if let Some ( pattern) = local_visitor. found_arg_pattern {
117132 err_span = pattern. span ;
118133 // We don't want to show the default label for closures.
@@ -131,13 +146,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
131146 // ^ consider giving this closure parameter a type
132147 // ```
133148 labels. clear ( ) ;
134- labels. push (
135- ( pattern. span , "consider giving this closure parameter a type" . to_owned ( ) ) ) ;
149+ labels. push ( ( pattern. span , format ! (
150+ "consider giving this closure parameter {}" ,
151+ match local_visitor. found_ty {
152+ Some ( ty) if & ty. to_string( ) != "_" => format!(
153+ "the type `{}` with the type parameter `{}` specified" ,
154+ ty,
155+ name,
156+ ) ,
157+ _ => "a type" . to_owned( ) ,
158+ } ,
159+ ) ) ) ;
136160 } else if let Some ( pattern) = local_visitor. found_local_pattern {
137161 if let Some ( simple_ident) = pattern. simple_ident ( ) {
138162 match pattern. span . compiler_desugaring_kind ( ) {
139- None => labels. push ( ( pattern. span ,
140- format ! ( "consider giving `{}` a type" , simple_ident) ) ) ,
163+ None => labels. push ( (
164+ pattern. span ,
165+ format ! (
166+ "consider giving `{}` {}" ,
167+ simple_ident,
168+ match local_visitor. found_ty {
169+ Some ( ty) if & ty. to_string( ) != "_" => format!(
170+ "the type `{}` with the type parameter `{}` specified" ,
171+ ty,
172+ name,
173+ ) ,
174+ _ => "a type" . to_owned( ) ,
175+ } ,
176+ ) ,
177+ ) ) ,
141178 Some ( CompilerDesugaringKind :: ForLoop ) => labels. push ( (
142179 pattern. span ,
143180 "the element type for this iterator is not specified" . to_owned ( ) ,
@@ -147,12 +184,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
147184 } else {
148185 labels. push ( ( pattern. span , "consider giving the pattern a type" . to_owned ( ) ) ) ;
149186 }
150- }
187+ } ;
151188
152- let mut err = struct_span_err ! ( self . tcx. sess,
153- err_span,
154- E0282 ,
155- "type annotations needed" ) ;
189+ let mut err = struct_span_err ! (
190+ self . tcx. sess,
191+ err_span,
192+ E0282 ,
193+ "type annotations needed{}" ,
194+ ty_msg,
195+ ) ;
156196
157197 for ( target_span, label_message) in labels {
158198 err. span_label ( target_span, label_message) ;
0 commit comments