@@ -154,14 +154,44 @@ impl Iterator for Ancestors<'_> {
154
154
}
155
155
}
156
156
157
- pub struct NodeItem < T > {
158
- pub node : Node ,
159
- pub item : T ,
157
+ /// Information about the most specialized definition of an associated item.
158
+ pub struct LeafDef {
159
+ /// The associated item described by this `LeafDef`.
160
+ pub item : ty:: AssocItem ,
161
+
162
+ /// The node in the specialization graph containing the definition of `item`.
163
+ pub defining_node : Node ,
164
+
165
+ /// The "top-most" (ie. least specialized) specialization graph node that finalized the
166
+ /// definition of `item`.
167
+ ///
168
+ /// Example:
169
+ ///
170
+ /// ```
171
+ /// trait Tr {
172
+ /// fn assoc(&self);
173
+ /// }
174
+ ///
175
+ /// impl<T> Tr for T {
176
+ /// default fn assoc(&self) {}
177
+ /// }
178
+ ///
179
+ /// impl Tr for u8 {}
180
+ /// ```
181
+ ///
182
+ /// If we start the leaf definition search at `impl Tr for u8`, that impl will be the
183
+ /// `finalizing_node`, while `defining_node` will be the generic impl.
184
+ ///
185
+ /// If the leaf definition search is started at the generic impl, `finalizing_node` will be
186
+ /// `None`, since the most specialized impl we found still allows overriding the method
187
+ /// (doesn't finalize it).
188
+ pub finalizing_node : Option < Node > ,
160
189
}
161
190
162
- impl < T > NodeItem < T > {
163
- pub fn map < U , F : FnOnce ( T ) -> U > ( self , f : F ) -> NodeItem < U > {
164
- NodeItem { node : self . node , item : f ( self . item ) }
191
+ impl LeafDef {
192
+ /// Returns whether this definition is known to not be further specializable.
193
+ pub fn is_final ( & self ) -> bool {
194
+ self . finalizing_node . is_some ( )
165
195
}
166
196
}
167
197
@@ -173,18 +203,36 @@ impl<'tcx> Ancestors<'tcx> {
173
203
tcx : TyCtxt < ' tcx > ,
174
204
trait_item_name : Ident ,
175
205
trait_item_kind : ty:: AssocKind ,
176
- ) -> Option < NodeItem < ty :: AssocItem > > {
206
+ ) -> Option < LeafDef > {
177
207
let trait_def_id = self . trait_def_id ;
208
+ let mut finalizing_node = None ;
209
+
178
210
self . find_map ( |node| {
179
- node. item ( tcx, trait_item_name, trait_item_kind, trait_def_id)
180
- . map ( |item| NodeItem { node, item } )
211
+ if let Some ( item) = node. item ( tcx, trait_item_name, trait_item_kind, trait_def_id) {
212
+ if finalizing_node. is_none ( ) {
213
+ let is_specializable = item. defaultness . is_default ( )
214
+ || tcx. impl_defaultness ( node. def_id ( ) ) . is_default ( ) ;
215
+
216
+ if !is_specializable {
217
+ finalizing_node = Some ( node) ;
218
+ }
219
+ }
220
+
221
+ Some ( LeafDef { item, defining_node : node, finalizing_node } )
222
+ } else {
223
+ // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
224
+ finalizing_node = Some ( node) ;
225
+ None
226
+ }
181
227
} )
182
228
}
183
229
}
184
230
185
231
/// Walk up the specialization ancestors of a given impl, starting with that
186
- /// impl itself. Returns `None` if an error was reported while building the
187
- /// specialization graph.
232
+ /// impl itself.
233
+ ///
234
+ /// Returns `Err` if an error was reported while building the specialization
235
+ /// graph.
188
236
pub fn ancestors (
189
237
tcx : TyCtxt < ' tcx > ,
190
238
trait_def_id : DefId ,
0 commit comments