11use rustc_data_structures:: fx:: FxIndexSet ;
2+ use rustc_errors:: struct_span_err;
23use rustc_hir as hir;
34use rustc_hir:: def_id:: { DefId , LocalDefId } ;
45use rustc_middle:: ty:: subst:: Subst ;
5- use rustc_middle:: ty:: { self , Binder , Predicate , PredicateKind , ToPredicate , Ty , TyCtxt } ;
6+ use rustc_middle:: ty:: {
7+ self , Binder , Predicate , PredicateKind , ToPredicate , Ty , TyCtxt , TypeFoldable ,
8+ } ;
69use rustc_span:: { sym, Span } ;
710use rustc_trait_selection:: traits;
811
@@ -89,6 +92,7 @@ fn associated_item_from_trait_item_ref(
8992 vis : tcx. visibility ( def_id) ,
9093 defaultness : trait_item_ref. defaultness ,
9194 def_id : def_id. to_def_id ( ) ,
95+ trait_item_def_id : Some ( def_id. to_def_id ( ) ) ,
9296 container : ty:: TraitContainer ( parent_def_id. to_def_id ( ) ) ,
9397 fn_has_self_parameter : has_self,
9498 }
@@ -106,17 +110,119 @@ fn associated_item_from_impl_item_ref(
106110 hir:: AssocItemKind :: Type => ( ty:: AssocKind :: Type , false ) ,
107111 } ;
108112
113+ let trait_item_def_id = impl_item_base_id ( tcx, parent_def_id, impl_item_ref) ;
114+
109115 ty:: AssocItem {
110116 ident : impl_item_ref. ident ,
111117 kind,
112118 vis : tcx. visibility ( def_id) ,
113119 defaultness : impl_item_ref. defaultness ,
114120 def_id : def_id. to_def_id ( ) ,
121+ trait_item_def_id,
115122 container : ty:: ImplContainer ( parent_def_id. to_def_id ( ) ) ,
116123 fn_has_self_parameter : has_self,
117124 }
118125}
119126
127+ fn impl_item_base_id < ' tcx > (
128+ tcx : TyCtxt < ' tcx > ,
129+ parent_def_id : LocalDefId ,
130+ impl_item : & hir:: ImplItemRef ,
131+ ) -> Option < DefId > {
132+ let impl_trait_ref = tcx. impl_trait_ref ( parent_def_id) ?;
133+
134+ // If the trait reference itself is erroneous (so the compilation is going
135+ // to fail), skip checking the items here -- the `impl_item` table in `tcx`
136+ // isn't populated for such impls.
137+ if impl_trait_ref. references_error ( ) {
138+ return None ;
139+ }
140+
141+ // Locate trait items
142+ let associated_items = tcx. associated_items ( impl_trait_ref. def_id ) ;
143+
144+ // Match item against trait
145+ let mut items = associated_items. filter_by_name ( tcx, impl_item. ident , impl_trait_ref. def_id ) ;
146+
147+ let mut trait_item = items. next ( ) ?;
148+
149+ let is_compatible = |ty : & & ty:: AssocItem | match ( ty. kind , & impl_item. kind ) {
150+ ( ty:: AssocKind :: Const , hir:: AssocItemKind :: Const ) => true ,
151+ ( ty:: AssocKind :: Fn , hir:: AssocItemKind :: Fn { .. } ) => true ,
152+ ( ty:: AssocKind :: Type , hir:: AssocItemKind :: Type ) => true ,
153+ _ => false ,
154+ } ;
155+
156+ // If we don't have a compatible item, we'll use the first one whose name matches
157+ // to report an error.
158+ let mut compatible_kind = is_compatible ( & trait_item) ;
159+
160+ if !compatible_kind {
161+ if let Some ( ty_trait_item) = items. find ( is_compatible) {
162+ compatible_kind = true ;
163+ trait_item = ty_trait_item;
164+ }
165+ }
166+
167+ if compatible_kind {
168+ Some ( trait_item. def_id )
169+ } else {
170+ report_mismatch_error ( tcx, trait_item. def_id , impl_trait_ref, impl_item) ;
171+ None
172+ }
173+ }
174+
175+ #[ inline( never) ]
176+ #[ cold]
177+ fn report_mismatch_error < ' tcx > (
178+ tcx : TyCtxt < ' tcx > ,
179+ trait_item_def_id : DefId ,
180+ impl_trait_ref : ty:: TraitRef < ' tcx > ,
181+ impl_item : & hir:: ImplItemRef ,
182+ ) {
183+ let mut err = match impl_item. kind {
184+ hir:: AssocItemKind :: Const => {
185+ // Find associated const definition.
186+ struct_span_err ! (
187+ tcx. sess,
188+ impl_item. span,
189+ E0323 ,
190+ "item `{}` is an associated const, which doesn't match its trait `{}`" ,
191+ impl_item. ident,
192+ impl_trait_ref. print_only_trait_path( )
193+ )
194+ }
195+
196+ hir:: AssocItemKind :: Fn { .. } => {
197+ struct_span_err ! (
198+ tcx. sess,
199+ impl_item. span,
200+ E0324 ,
201+ "item `{}` is an associated method, which doesn't match its trait `{}`" ,
202+ impl_item. ident,
203+ impl_trait_ref. print_only_trait_path( )
204+ )
205+ }
206+
207+ hir:: AssocItemKind :: Type => {
208+ struct_span_err ! (
209+ tcx. sess,
210+ impl_item. span,
211+ E0325 ,
212+ "item `{}` is an associated type, which doesn't match its trait `{}`" ,
213+ impl_item. ident,
214+ impl_trait_ref. print_only_trait_path( )
215+ )
216+ }
217+ } ;
218+
219+ err. span_label ( impl_item. span , "does not match trait" ) ;
220+ if let Some ( trait_span) = tcx. hir ( ) . span_if_local ( trait_item_def_id) {
221+ err. span_label ( trait_span, "item in trait" ) ;
222+ }
223+ err. emit ( ) ;
224+ }
225+
120226fn associated_item ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> ty:: AssocItem {
121227 let id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id. expect_local ( ) ) ;
122228 let parent_id = tcx. hir ( ) . get_parent_item ( id) ;
0 commit comments