@@ -25,16 +25,16 @@ use super::{
25
25
26
26
use errors:: DiagnosticBuilder ;
27
27
use fmt_macros:: { Parser , Piece , Position } ;
28
- use hir:: { intravisit, Local , Pat } ;
28
+ use hir:: { self , intravisit, Local , Pat , Body } ;
29
29
use hir:: intravisit:: { Visitor , NestedVisitorMap } ;
30
30
use hir:: map:: NodeExpr ;
31
31
use hir:: def_id:: DefId ;
32
32
use infer:: { self , InferCtxt } ;
33
33
use infer:: type_variable:: TypeVariableOrigin ;
34
34
use rustc:: lint:: builtin:: EXTRA_REQUIREMENT_IN_IMPL ;
35
35
use std:: fmt;
36
- use syntax:: ast;
37
- use ty:: { self , AdtKind , ToPredicate , ToPolyTraitRef , Ty , TyCtxt , TypeFoldable } ;
36
+ use syntax:: ast:: { self , NodeId } ;
37
+ use ty:: { self , AdtKind , ToPredicate , ToPolyTraitRef , Ty , TyCtxt , TypeFoldable , TyInfer , TyVar } ;
38
38
use ty:: error:: ExpectedFound ;
39
39
use ty:: fast_reject;
40
40
use ty:: fold:: TypeFolder ;
@@ -66,37 +66,52 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> {
66
66
struct FindLocalByTypeVisitor < ' a , ' gcx : ' a + ' tcx , ' tcx : ' a > {
67
67
infcx : & ' a InferCtxt < ' a , ' gcx , ' tcx > ,
68
68
target_ty : & ' a Ty < ' tcx > ,
69
- found_pattern : Option < & ' a Pat > ,
69
+ hir_map : & ' a hir:: map:: Map < ' gcx > ,
70
+ found_local_pattern : Option < & ' gcx Pat > ,
71
+ found_arg_pattern : Option < & ' gcx Pat > ,
70
72
}
71
73
72
74
impl < ' a , ' gcx , ' tcx > FindLocalByTypeVisitor < ' a , ' gcx , ' tcx > {
73
- fn is_match ( & self , ty : Ty < ' tcx > ) -> bool {
74
- ty == * self . target_ty || match ( & ty. sty , & self . target_ty . sty ) {
75
- ( & ty:: TyInfer ( ty:: TyVar ( a_vid) ) , & ty:: TyInfer ( ty:: TyVar ( b_vid) ) ) =>
76
- self . infcx . type_variables
77
- . borrow_mut ( )
78
- . sub_unified ( a_vid, b_vid) ,
79
-
75
+ fn node_matches_type ( & mut self , node_id : & ' gcx NodeId ) -> bool {
76
+ match self . infcx . tables . borrow ( ) . node_types . get ( node_id) {
77
+ Some ( & ty) => {
78
+ let ty = self . infcx . resolve_type_vars_if_possible ( & ty) ;
79
+ ty. walk ( ) . any ( |inner_ty| {
80
+ inner_ty == * self . target_ty || match ( & inner_ty. sty , & self . target_ty . sty ) {
81
+ ( & TyInfer ( TyVar ( a_vid) ) , & TyInfer ( TyVar ( b_vid) ) ) => {
82
+ self . infcx
83
+ . type_variables
84
+ . borrow_mut ( )
85
+ . sub_unified ( a_vid, b_vid)
86
+ }
87
+ _ => false ,
88
+ }
89
+ } )
90
+ }
80
91
_ => false ,
81
92
}
82
93
}
83
94
}
84
95
85
- impl < ' a , ' gcx , ' tcx > Visitor < ' a > for FindLocalByTypeVisitor < ' a , ' gcx , ' tcx > {
86
- fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' a > {
87
- NestedVisitorMap :: None
96
+ impl < ' a , ' gcx , ' tcx > Visitor < ' gcx > for FindLocalByTypeVisitor < ' a , ' gcx , ' tcx > {
97
+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' gcx > {
98
+ NestedVisitorMap :: OnlyBodies ( & self . hir_map )
88
99
}
89
100
90
- fn visit_local ( & mut self , local : & ' a Local ) {
91
- if let Some ( & ty) = self . infcx . tables . borrow ( ) . node_types . get ( & local. id ) {
92
- let ty = self . infcx . resolve_type_vars_if_possible ( & ty) ;
93
- let is_match = ty. walk ( ) . any ( |t| self . is_match ( t) ) ;
101
+ fn visit_local ( & mut self , local : & ' gcx Local ) {
102
+ if self . found_local_pattern . is_none ( ) && self . node_matches_type ( & local. id ) {
103
+ self . found_local_pattern = Some ( & * local. pat ) ;
104
+ }
105
+ intravisit:: walk_local ( self , local) ;
106
+ }
94
107
95
- if is_match && self . found_pattern . is_none ( ) {
96
- self . found_pattern = Some ( & * local. pat ) ;
108
+ fn visit_body ( & mut self , body : & ' gcx Body ) {
109
+ for argument in & body. arguments {
110
+ if self . found_arg_pattern . is_none ( ) && self . node_matches_type ( & argument. id ) {
111
+ self . found_arg_pattern = Some ( & * argument. pat ) ;
97
112
}
98
113
}
99
- intravisit:: walk_local ( self , local ) ;
114
+ intravisit:: walk_body ( self , body ) ;
100
115
}
101
116
}
102
117
@@ -721,6 +736,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
721
736
// coherence violation, so we don't report it here.
722
737
723
738
let predicate = self . resolve_type_vars_if_possible ( & obligation. predicate ) ;
739
+ let body_id = hir:: BodyId { node_id : obligation. cause . body_id } ;
740
+ let span = obligation. cause . span ;
724
741
725
742
debug ! ( "maybe_report_ambiguity(predicate={:?}, obligation={:?})" ,
726
743
predicate,
@@ -768,10 +785,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
768
785
self . tcx . lang_items . sized_trait ( )
769
786
. map_or ( false , |sized_id| sized_id == trait_ref. def_id ( ) )
770
787
{
771
- self . need_type_info ( obligation , self_ty) ;
788
+ self . need_type_info ( body_id , span , self_ty) ;
772
789
} else {
773
790
let mut err = struct_span_err ! ( self . tcx. sess,
774
- obligation . cause . span, E0283 ,
791
+ span, E0283 ,
775
792
"type annotations required: \
776
793
cannot resolve `{}`",
777
794
predicate) ;
@@ -785,7 +802,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
785
802
// Same hacky approach as above to avoid deluging user
786
803
// with error messages.
787
804
if !ty. references_error ( ) && !self . tcx . sess . has_errors ( ) {
788
- self . need_type_info ( obligation , ty) ;
805
+ self . need_type_info ( body_id , span , ty) ;
789
806
}
790
807
}
791
808
@@ -796,7 +813,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
796
813
let & SubtypePredicate { a_is_expected : _, a, b } = data. skip_binder ( ) ;
797
814
// both must be type variables, or the other would've been instantiated
798
815
assert ! ( a. is_ty_var( ) && b. is_ty_var( ) ) ;
799
- self . need_type_info ( obligation, a) ;
816
+ self . need_type_info ( hir:: BodyId { node_id : obligation. cause . body_id } ,
817
+ obligation. cause . span ,
818
+ a) ;
800
819
}
801
820
}
802
821
@@ -874,42 +893,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
874
893
}
875
894
}
876
895
877
- fn need_type_info ( & self , obligation : & PredicateObligation < ' tcx > , ty : Ty < ' tcx > ) {
896
+ pub fn need_type_info ( & self , body_id : hir :: BodyId , span : Span , ty : Ty < ' tcx > ) {
878
897
let ty = self . resolve_type_vars_if_possible ( & ty) ;
879
898
let name = self . extract_type_name ( & ty) ;
880
- let ref cause = obligation. cause ;
881
899
882
- let mut err = struct_span_err ! ( self . tcx. sess,
883
- cause. span,
884
- E0282 ,
885
- "type annotations needed" ) ;
886
-
887
- err. span_label ( cause. span , & format ! ( "cannot infer type for `{}`" , name) ) ;
900
+ let mut err_span = span;
901
+ let mut labels = vec ! [ ( span, format!( "cannot infer type for `{}`" , name) ) ] ;
888
902
889
903
let mut local_visitor = FindLocalByTypeVisitor {
890
904
infcx : & self ,
891
905
target_ty : & ty,
892
- found_pattern : None ,
906
+ hir_map : & self . tcx . hir ,
907
+ found_local_pattern : None ,
908
+ found_arg_pattern : None ,
893
909
} ;
894
910
895
911
// #40294: cause.body_id can also be a fn declaration.
896
912
// Currently, if it's anything other than NodeExpr, we just ignore it
897
- match self . tcx . hir . find ( cause . body_id ) {
913
+ match self . tcx . hir . find ( body_id. node_id ) {
898
914
Some ( NodeExpr ( expr) ) => local_visitor. visit_expr ( expr) ,
899
915
_ => ( )
900
916
}
901
917
902
- if let Some ( pattern) = local_visitor. found_pattern {
903
- let pattern_span = pattern. span ;
918
+ if let Some ( pattern) = local_visitor. found_arg_pattern {
919
+ err_span = pattern. span ;
920
+ // We don't want to show the default label for closures.
921
+ //
922
+ // So, before clearing, the output would look something like this:
923
+ // ```
924
+ // let x = |_| { };
925
+ // - ^^^^ cannot infer type for `[_; 0]`
926
+ // |
927
+ // consider giving this closure parameter a type
928
+ // ```
929
+ //
930
+ // After clearing, it looks something like this:
931
+ // ```
932
+ // let x = |_| { };
933
+ // ^ consider giving this closure parameter a type
934
+ // ```
935
+ labels. clear ( ) ;
936
+ labels. push ( ( pattern. span , format ! ( "consider giving this closure parameter a type" ) ) ) ;
937
+ }
938
+
939
+ if let Some ( pattern) = local_visitor. found_local_pattern {
904
940
if let Some ( simple_name) = pattern. simple_name ( ) {
905
- err. span_label ( pattern_span,
906
- & format ! ( "consider giving `{}` a type" ,
907
- simple_name) ) ;
941
+ labels. push ( ( pattern. span , format ! ( "consider giving `{}` a type" , simple_name) ) ) ;
908
942
} else {
909
- err . span_label ( pattern_span , & format ! ( "consider giving a type to pattern" ) ) ;
943
+ labels . push ( ( pattern . span , format ! ( "consider giving the pattern a type" ) ) ) ;
910
944
}
911
945
}
912
946
947
+ let mut err = struct_span_err ! ( self . tcx. sess,
948
+ err_span,
949
+ E0282 ,
950
+ "type annotations needed" ) ;
951
+
952
+ for ( target_span, label_message) in labels {
953
+ err. span_label ( target_span, & label_message) ;
954
+ }
955
+
913
956
err. emit ( ) ;
914
957
}
915
958
0 commit comments