@@ -154,14 +154,44 @@ impl Iterator for Ancestors<'_> {
154154 }
155155}
156156
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 > ,
160189}
161190
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 ( )
165195 }
166196}
167197
@@ -173,18 +203,36 @@ impl<'tcx> Ancestors<'tcx> {
173203 tcx : TyCtxt < ' tcx > ,
174204 trait_item_name : Ident ,
175205 trait_item_kind : ty:: AssocKind ,
176- ) -> Option < NodeItem < ty :: AssocItem > > {
206+ ) -> Option < LeafDef > {
177207 let trait_def_id = self . trait_def_id ;
208+ let mut finalizing_node = None ;
209+
178210 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+ }
181227 } )
182228 }
183229}
184230
185231/// 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.
188236pub fn ancestors (
189237 tcx : TyCtxt < ' tcx > ,
190238 trait_def_id : DefId ,
0 commit comments