File tree Expand file tree Collapse file tree 7 files changed +65
-11
lines changed
rustc_trait_selection/src/traits Expand file tree Collapse file tree 7 files changed +65
-11
lines changed Original file line number Diff line number Diff line change @@ -1631,6 +1631,10 @@ rustc_queries! {
16311631 query is_dyn_compatible( trait_id: DefId ) -> bool {
16321632 desc { "checking if trait `{}` is dyn-compatible" , tcx. def_path_str( trait_id) }
16331633 }
1634+ query is_dyn_incompatible_final_assoc_fn_query( def_id: DefId ) -> bool {
1635+ desc { "checking if final assoc fn `{}` is dyn-incompatible" , tcx. def_path_str( def_id) }
1636+ feedable
1637+ }
16341638
16351639 /// Gets the ParameterEnvironment for a given item; this environment
16361640 /// will be in "user-facing" mode, meaning that it is suitable for
Original file line number Diff line number Diff line change @@ -333,4 +333,17 @@ impl<'tcx> TyCtxt<'tcx> {
333333 let parent_def_id = self . parent ( fn_def_id) ;
334334 & self . associated_types_for_impl_traits_in_trait_or_impl ( parent_def_id) [ & fn_def_id]
335335 }
336+
337+ /// Returns true if the given final associated function violates the dyn-
338+ /// compatibility and has no `Self: Sized` requirement.
339+ ///
340+ /// Such final associated functions will be excluded from the trait's vtable
341+ /// and could be called from a trait object directly.
342+ pub fn is_dyn_incompatible_final_assoc_fn ( self , def_id : DefId ) -> bool {
343+ matches ! ( self . def_kind( def_id) , DefKind :: AssocFn )
344+ && matches ! ( self . defaultness( def_id) , hir:: Defaultness :: Final )
345+ // Any item that has a `Self: Sized` requisite is non-dispatchable.
346+ && !self . generics_require_sized_self ( def_id)
347+ && self . is_dyn_incompatible_final_assoc_fn_query ( def_id)
348+ }
336349}
Original file line number Diff line number Diff line change @@ -662,6 +662,13 @@ impl<'tcx> TyCtxt<'tcx> {
662662 pub fn feed_delayed_owner ( self , key : LocalDefId , owner : MaybeOwner < ' tcx > ) {
663663 TyCtxtFeed { tcx : self , key } . delayed_owner ( owner) ;
664664 }
665+
666+ pub fn feed_is_dyn_incompatible_final_assoc_fn ( self , key : DefId , value : bool ) {
667+ debug_assert_eq ! ( self . def_kind( key) , DefKind :: AssocFn ) ;
668+ debug_assert ! ( self . defaultness( key) . is_final( ) ) ;
669+
670+ TyCtxtFeed { tcx : self , key } . is_dyn_incompatible_final_assoc_fn_query ( value)
671+ }
665672}
666673
667674impl < ' tcx , KEY : Copy > TyCtxtFeed < ' tcx , KEY > {
Original file line number Diff line number Diff line change @@ -314,11 +314,6 @@ pub fn dyn_compatibility_violations_for_assoc_item(
314314 trait_def_id : DefId ,
315315 item : ty:: AssocItem ,
316316) -> Vec < DynCompatibilityViolation > {
317- // `final` assoc functions don't prevent a trait from being dyn-compatible
318- if tcx. defaultness ( item. def_id ) . is_final ( ) {
319- return Vec :: new ( ) ;
320- }
321-
322317 // Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
323318 if tcx. generics_require_sized_self ( item. def_id ) {
324319 return Vec :: new ( ) ;
@@ -360,7 +355,7 @@ pub fn dyn_compatibility_violations_for_assoc_item(
360355 . collect ( )
361356 }
362357 ty:: AssocKind :: Fn { name, .. } => {
363- virtual_call_violations_for_method ( tcx, trait_def_id, item)
358+ let violations : Vec < _ > = virtual_call_violations_for_method ( tcx, trait_def_id, item)
364359 . into_iter ( )
365360 . map ( |v| {
366361 let node = tcx. hir_get_if_local ( item. def_id ) ;
@@ -377,7 +372,14 @@ pub fn dyn_compatibility_violations_for_assoc_item(
377372
378373 DynCompatibilityViolation :: Method ( name, v, span)
379374 } )
380- . collect ( )
375+ . collect ( ) ;
376+
377+ if tcx. defaultness ( item. def_id ) . is_final ( ) {
378+ tcx. feed_is_dyn_incompatible_final_assoc_fn ( item. def_id , !violations. is_empty ( ) ) ;
379+ Vec :: new ( )
380+ } else {
381+ violations
382+ }
381383 }
382384 ty:: AssocKind :: Type { data } => {
383385 if !tcx. generics_of ( item. def_id ) . is_own_empty ( )
Original file line number Diff line number Diff line change @@ -210,8 +210,8 @@ fn own_existential_vtable_entries_iter(
210210 debug ! ( "own_existential_vtable_entry: trait_method={:?}" , trait_method) ;
211211 let def_id = trait_method. def_id ;
212212
213- // Final methods should not be included in the vtable.
214- if trait_method . defaultness ( tcx ) . is_final ( ) {
213+ // Final methods should not be included in the vtable if they are not dyn-compatible .
214+ if tcx . defaultness ( def_id ) . is_final ( ) && tcx . is_dyn_incompatible_final_assoc_fn ( def_id ) {
215215 return None ;
216216 }
217217
Original file line number Diff line number Diff line change @@ -238,8 +238,10 @@ fn resolve_associated_item<'tcx>(
238238 traits:: ImplSource :: Builtin ( BuiltinImplSource :: Object ( _) , _) => {
239239 let trait_ref = ty:: TraitRef :: from_assoc ( tcx, trait_id, rcvr_args) ;
240240
241- // `final` methods should be called directly.
242- if tcx. defaultness ( trait_item_id) . is_final ( ) {
241+ // `final` methods should be called directly if they are not dyn-compatible.
242+ if tcx. defaultness ( trait_item_id) . is_final ( )
243+ && tcx. is_dyn_incompatible_final_assoc_fn ( trait_item_id)
244+ {
243245 return Ok ( Some ( ty:: Instance :: new_raw ( trait_item_id, rcvr_args) ) ) ;
244246 }
245247
Original file line number Diff line number Diff line change 1+ //@ run-pass
2+
3+ #![ feature( final_associated_functions) ]
4+
5+ trait Tr
6+ where
7+ Self : ' static ,
8+ {
9+ final fn foo ( & self ) -> std:: any:: TypeId {
10+ std:: any:: TypeId :: of :: < Self > ( )
11+ }
12+ }
13+
14+ struct Foo ;
15+ impl Tr for Foo { }
16+
17+ struct Bar ;
18+ impl Tr for Bar { }
19+
20+ fn foo ( t : & dyn Tr ) -> std:: any:: TypeId {
21+ t. foo ( )
22+ }
23+
24+ fn main ( ) {
25+ assert_ne ! ( foo( & Foo ) , foo( & Bar ) ) ;
26+ }
You can’t perform that action at this time.
0 commit comments