@@ -63,78 +63,56 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
6363 err. span_label ( trait_sp, & format ! ( "expected {:?}" , expected) ) ;
6464 let trait_fn_sig = tcx. fn_sig ( trait_def_id) ;
6565
66+ // Check the `trait`'s method's output to look for type parameters that might have
67+ // unconstrained lifetimes. If the method returns a type parameter and the `impl` has a
68+ // borrow as the type parameter being implemented, the lifetimes will not match because
69+ // a new lifetime is being introduced in the `impl` that is not present in the `trait`.
70+ // Because this is confusing as hell the first time you see it, we give a short message
71+ // explaining the situation and proposing constraining the type param with a named lifetime
72+ // so that the `impl` will have one to tie them together.
6673 struct AssocTypeFinder ( FxHashSet < ty:: ParamTy > ) ;
6774 impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for AssocTypeFinder {
6875 fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
6976 debug ! ( "assoc type finder ty {:?} {:?}" , ty, ty. kind) ;
70- match ty. kind {
71- ty:: Param ( param) => {
72- self . 0 . insert ( param) ;
73- }
74- _ => { }
77+ if let ty:: Param ( param) = ty. kind {
78+ self . 0 . insert ( param) ;
7579 }
7680 ty. super_visit_with ( self )
7781 }
7882 }
7983 let mut visitor = AssocTypeFinder ( FxHashSet :: default ( ) ) ;
8084 trait_fn_sig. output ( ) . visit_with ( & mut visitor) ;
81-
8285 if let Some ( id) = tcx. hir ( ) . as_local_hir_id ( trait_def_id) {
8386 let parent_id = tcx. hir ( ) . get_parent_item ( id) ;
8487 let trait_item = tcx. hir ( ) . expect_item ( parent_id) ;
8588 if let hir:: ItemKind :: Trait ( _, _, generics, _, _) = & trait_item. kind {
8689 for param_ty in visitor. 0 {
8790 if let Some ( generic) = generics. get_named ( param_ty. name ) {
8891 err. span_label ( generic. span , & format ! (
89- "in order for `impl` items to be able to implement the method, this \
90- type parameter might need a lifetime restriction like `{}: 'a`",
92+ "for `impl` items to implement the method, this type parameter might \
93+ need a lifetime restriction like `{}: 'a`",
9194 param_ty. name,
9295 ) ) ;
9396 }
9497 }
9598 }
9699 }
97100
98- struct EarlyBoundRegionHighlighter ( FxHashSet < DefId > ) ;
99- impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for EarlyBoundRegionHighlighter {
100- fn visit_region ( & mut self , r : ty:: Region < ' tcx > ) -> bool {
101- match * r {
102- ty:: ReFree ( free) => {
103- self . 0 . insert ( free. scope ) ;
104- }
105- ty:: ReEarlyBound ( bound) => {
106- self . 0 . insert ( bound. def_id ) ;
107- }
108- _ => { }
109- }
110- r. super_visit_with ( self )
111- }
112- }
113-
114- let mut visitor = EarlyBoundRegionHighlighter ( FxHashSet :: default ( ) ) ;
115- expected. visit_with ( & mut visitor) ;
116-
117- let note = !visitor. 0 . is_empty ( ) ;
118-
119- if let Some ( ( expected, found) ) = self
120- . tcx ( )
101+ if let Some ( ( expected, found) ) = tcx
121102 . infer_ctxt ( )
122103 . enter ( |infcx| infcx. expected_found_str_ty ( & ExpectedFound { expected, found } ) )
123104 {
105+ // Highlighted the differences when showing the "expected/found" note.
124106 err. note_expected_found ( & "" , expected, & "" , found) ;
125107 } else {
126108 // This fallback shouldn't be necessary, but let's keep it in just in case.
127109 err. note ( & format ! ( "expected `{:?}`\n found `{:?}`" , expected, found) ) ;
128110 }
129- if note {
130- err. note (
131- "the lifetime requirements from the `trait` could not be fulfilled by the `impl`" ,
132- ) ;
133- err. help (
134- "verify the lifetime relationships in the `trait` and `impl` between the \
135- `self` argument, the other inputs and its output",
136- ) ;
137- }
111+ err. note ( "the lifetime requirements from the `trait` could not be satisfied by the `impl`" ) ;
112+ err. help (
113+ "verify the lifetime relationships in the `trait` and `impl` between the `self` \
114+ argument, the other inputs and its output",
115+ ) ;
138116 err. emit ( ) ;
139117 }
140118}
0 commit comments