@@ -900,6 +900,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
900900 self . tcx . parent ( def_id) ,
901901 & path. segments [ ..path. segments . len ( ) - 1 ] ,
902902 ) ) ,
903+ // FIXME(mgca): @fmease thinks we also need to handle AssocConsts here.
903904 _ => None ,
904905 } ;
905906 let object_lifetime_defaults =
@@ -914,17 +915,27 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
914915 }
915916 }
916917 }
917- hir:: QPath :: TypeRelative ( qself, segment) => {
918- // Resolving object lifetime defaults for type-relative paths requires full
919- // type-dependent resolution as performed by HIR ty lowering whose results
920- // we don't have access to (and we'd results for both FnCtxts and ItemCtxts).
921- // FIXME: Figure out if there's a feasible way to obtain the map of
922- // type-dependent definitions.
918+ & hir:: QPath :: TypeRelative ( qself, segment) => {
919+ if let Some ( args) = segment. args {
920+ // FIXME(mgca): @fmease thinks we also need to handle AssocConsts here.
921+ let container = self
922+ . limited_resolve_type_relative_path (
923+ ty:: AssocTag :: Type ,
924+ qself,
925+ segment,
926+ true ,
927+ )
928+ . map ( |( _, assoc_item) | ( assoc_item. def_id , std:: slice:: from_ref ( segment) ) ) ;
929+ self . visit_segment_args ( container, args) ;
930+ }
931+
932+ // For forward compatibility we reject elided object lifetimes in the self type as
933+ // "indeterminate" by passing `None`. `limited_resolve_type_relative_path` is not
934+ // complete compared to HIR ty lowering's `lower_assoc_path_shared`, so we need to
935+ // be conservative. Consider paths like `<dyn Trait>::X` which may resolve in the
936+ // future (under IATs or mGCA (IACs)).
923937 let scope = Scope :: ObjectLifetimeDefault { lifetime : None , s : self . scope } ;
924- self . with ( scope, |this| {
925- this. visit_ty_unambig ( qself) ;
926- this. visit_path_segment ( segment)
927- } ) ;
938+ self . with ( scope, |this| this. visit_ty_unambig ( qself) ) ;
928939 }
929940 hir:: QPath :: LangItem ( ..) => { }
930941 }
@@ -933,7 +944,38 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
933944 fn visit_path ( & mut self , path : & hir:: Path < ' tcx > , hir_id : HirId ) {
934945 for ( index, segment) in path. segments . iter ( ) . enumerate ( ) {
935946 if let Some ( args) = segment. args {
936- self . visit_segment_args ( path, index, args) ;
947+ // Figure out if this is an "eligible generic container" that brings along ambient object
948+ // lifetime defaults for trait object types contained in any of the type arguments passed to
949+ // it (any inner generic containers will of course end up shadowing that the default).
950+ let depth = path. segments . len ( ) - index - 1 ;
951+ let container = match ( path. res , depth) {
952+ ( Res :: Def ( DefKind :: AssocTy , def_id) , 1 ) => {
953+ Some ( ( self . tcx . parent ( def_id) , & path. segments [ ..=index] ) )
954+ }
955+ ( Res :: Def ( DefKind :: Variant , def_id) , 0 ) => {
956+ Some ( ( self . tcx . parent ( def_id) , path. segments ) )
957+ }
958+ // FIXME(trait_alias): Arguably, trait aliases are eligible generic containers.
959+ (
960+ Res :: Def (
961+ DefKind :: Struct
962+ | DefKind :: Union
963+ | DefKind :: Enum
964+ | DefKind :: TyAlias
965+ | DefKind :: Trait
966+ | DefKind :: AssocTy ,
967+ def_id,
968+ ) ,
969+ 0 ,
970+ ) => Some ( ( def_id, path. segments ) ) ,
971+ // Note: We don't need to care about definitions kinds that can have generics if they
972+ // can only ever appear in positions where we can perform type inference (i.e., bodies).
973+ // FIXME(mgca): @fmease thinks that under (m)GCA we now also need to care about e.g.,
974+ // type-level Consts (GCI) and AssocConsts (maybe also Fns, AssocFns) here
975+ // since they appear outside of bodies (once the feature is more complete).
976+ _ => None ,
977+ } ;
978+ self . visit_segment_args ( container, args) ;
937979 }
938980 }
939981 if let Res :: Def ( DefKind :: TyParam | DefKind :: ConstParam , param_def_id) = path. res {
@@ -1653,8 +1695,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16531695 #[ instrument( level = "debug" , skip( self ) ) ]
16541696 fn visit_segment_args (
16551697 & mut self ,
1656- path : & hir:: Path < ' tcx > ,
1657- index : usize ,
1698+ container : Option < ( DefId , & [ hir:: PathSegment < ' tcx > ] ) > ,
16581699 generic_args : & ' tcx hir:: GenericArgs < ' tcx > ,
16591700 ) {
16601701 if let Some ( ( inputs, output) ) = generic_args. paren_sugar_inputs_output ( ) {
@@ -1670,40 +1711,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16701711 }
16711712 }
16721713
1673- // Figure out if this is an "eligible generic container" that brings along ambient object
1674- // lifetime defaults for trait object types contained in any of the type arguments passed to
1675- // it (any inner generic containers will of course end up shadowing that the default).
1676- let depth = path. segments . len ( ) - index - 1 ;
1677- let container = match ( path. res , depth) {
1678- ( Res :: Def ( DefKind :: AssocTy , def_id) , 1 ) => {
1679- Some ( ( self . tcx . parent ( def_id) , & path. segments [ ..=index] ) )
1680- }
1681- ( Res :: Def ( DefKind :: Variant , def_id) , 0 ) => {
1682- Some ( ( self . tcx . parent ( def_id) , path. segments ) )
1683- }
1684- // FIXME(trait_alias): Arguably, trait aliases are eligible generic containers.
1685- (
1686- Res :: Def (
1687- DefKind :: Struct
1688- | DefKind :: Union
1689- | DefKind :: Enum
1690- | DefKind :: TyAlias
1691- | DefKind :: Trait
1692- | DefKind :: AssocTy ,
1693- def_id,
1694- ) ,
1695- 0 ,
1696- ) => Some ( ( def_id, path. segments ) ) ,
1697- // Note: We don't need to care about definitions kinds that can have generics if they
1698- // can only ever appear in positions where we can perform type inference (i.e., bodies).
1699- // FIXME(mgca): @fmease thinks that under (m)GCA we now also need to care about e.g.,
1700- // type-level Consts (GCI) and AssocConsts (maybe also Fns, AssocFns) here
1701- // since they appear outside of bodies (once the feature is more complete).
1702- _ => None ,
1703- } ;
1704-
1705- debug ! ( ?container) ;
1706-
17071714 let object_lifetime_defaults = container. map_or_else ( Vec :: new, |( def_id, segs) | {
17081715 self . compute_ambient_object_lifetime_defaults ( def_id, segs)
17091716 } ) ;
@@ -2149,72 +2156,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
21492156 matches ! ( args. parenthesized, hir:: GenericArgsParentheses :: ReturnTypeNotation )
21502157 } ) =>
21512158 {
2152- // First, ignore a qself that isn't a type or `Self` param. Those are the
2153- // only ones that support `T::Assoc` anyways in HIR lowering.
2154- let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = qself. kind else {
2159+ let Some ( ( bound_vars, assoc_item) ) = self . limited_resolve_type_relative_path (
2160+ ty:: AssocTag :: Fn ,
2161+ qself,
2162+ item_segment,
2163+ false ,
2164+ ) else {
21552165 return ;
21562166 } ;
2157- match path. res {
2158- Res :: Def ( DefKind :: TyParam , _) | Res :: SelfTyParam { trait_ : _ } => {
2159- let mut bounds =
2160- self . for_each_trait_bound_on_res ( path. res ) . filter_map ( |trait_def_id| {
2161- BoundVarContext :: supertrait_hrtb_vars (
2162- self . tcx ,
2163- trait_def_id,
2164- item_segment. ident ,
2165- ty:: AssocTag :: Fn ,
2166- )
2167- } ) ;
2168-
2169- let Some ( ( bound_vars, assoc_item) ) = bounds. next ( ) else {
2170- // This will error in HIR lowering.
2171- self . tcx
2172- . dcx ( )
2173- . span_delayed_bug ( path. span , "no resolution for RTN path" ) ;
2174- return ;
2175- } ;
2176-
2177- // Don't bail if we have identical bounds, which may be collected from
2178- // something like `T: Bound + Bound`, or via elaborating supertraits.
2179- for ( second_vars, second_assoc_item) in bounds {
2180- if second_vars != bound_vars || second_assoc_item != assoc_item {
2181- // This will error in HIR lowering.
2182- self . tcx . dcx ( ) . span_delayed_bug (
2183- path. span ,
2184- "ambiguous resolution for RTN path" ,
2185- ) ;
2186- return ;
2187- }
2188- }
2189-
2190- ( bound_vars, assoc_item. def_id , item_segment)
2191- }
2192- // If we have a self type alias (in an impl), try to resolve an
2193- // associated item from one of the supertraits of the impl's trait.
2194- Res :: SelfTyAlias { alias_to : impl_def_id, is_trait_impl : true , .. } => {
2195- let hir:: ItemKind :: Impl ( hir:: Impl { of_trait : Some ( trait_ref) , .. } ) = self
2196- . tcx
2197- . hir_node_by_def_id ( impl_def_id. expect_local ( ) )
2198- . expect_item ( )
2199- . kind
2200- else {
2201- return ;
2202- } ;
2203- let Some ( trait_def_id) = trait_ref. trait_def_id ( ) else {
2204- return ;
2205- } ;
2206- let Some ( ( bound_vars, assoc_item) ) = BoundVarContext :: supertrait_hrtb_vars (
2207- self . tcx ,
2208- trait_def_id,
2209- item_segment. ident ,
2210- ty:: AssocTag :: Fn ,
2211- ) else {
2212- return ;
2213- } ;
2214- ( bound_vars, assoc_item. def_id , item_segment)
2215- }
2216- _ => return ,
2217- }
2167+ ( bound_vars, assoc_item. def_id , item_segment)
22182168 }
22192169
22202170 _ => return ,
@@ -2253,6 +2203,83 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
22532203 self . record_late_bound_vars ( item_segment. hir_id , existing_bound_vars_saved) ;
22542204 }
22552205
2206+ /// In a limited fashion, try to resolve the given type-relative path of the given kind.
2207+ fn limited_resolve_type_relative_path (
2208+ & self ,
2209+ tag : ty:: AssocTag ,
2210+ qself : & ' tcx hir:: Ty < ' tcx > ,
2211+ segment : & ' tcx hir:: PathSegment < ' tcx > ,
2212+ speculative : bool ,
2213+ ) -> Option < ( Vec < ty:: BoundVariableKind > , & ' tcx ty:: AssocItem ) > {
2214+ // This mimics HIR ty lowering's `lower_assoc_path_shared`.
2215+ // FIXME: Duplicating efforts is not robust or sustainable/maintainable.
2216+ // Ideally, we'd simply obtain the resulting type-dependent defs from
2217+ // HIR ty lowering (not only in FnCtxts but also in ItemCtxts!).
2218+
2219+ // First, ignore a qself that isn't a type or `Self` param. Those are the only ones
2220+ // that support `T::Assoc` anyways in HIR ty lowering at the time of writing.
2221+ let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = qself. kind else {
2222+ return None ;
2223+ } ;
2224+
2225+ match path. res {
2226+ Res :: Def ( DefKind :: TyParam , _) | Res :: SelfTyParam { trait_ : _ } => {
2227+ let mut bounds =
2228+ self . for_each_trait_bound_on_res ( path. res ) . filter_map ( |trait_def_id| {
2229+ BoundVarContext :: supertrait_hrtb_vars (
2230+ self . tcx ,
2231+ trait_def_id,
2232+ segment. ident ,
2233+ tag,
2234+ )
2235+ } ) ;
2236+
2237+ let Some ( ( bound_vars, assoc_item) ) = bounds. next ( ) else {
2238+ if !speculative {
2239+ // This will error in HIR ty lowering.
2240+ self . tcx
2241+ . dcx ( )
2242+ . span_delayed_bug ( path. span , "no resolution for type-relative path" ) ;
2243+ }
2244+ return None ;
2245+ } ;
2246+
2247+ // Don't bail if we have identical bounds, which may be collected from
2248+ // something like `T: Bound + Bound`, or via elaborating supertraits.
2249+ for ( second_vars, second_assoc_item) in bounds {
2250+ if second_vars != bound_vars || second_assoc_item != assoc_item {
2251+ if !speculative {
2252+ // This will error in HIR ty lowering.
2253+ self . tcx . dcx ( ) . span_delayed_bug (
2254+ path. span ,
2255+ "ambiguous resolution for type-relative path" ,
2256+ ) ;
2257+ }
2258+ return None ;
2259+ }
2260+ }
2261+
2262+ Some ( ( bound_vars, assoc_item) )
2263+ }
2264+ // If we have a self type alias (in an impl), try to resolve an
2265+ // associated item from one of the supertraits of the impl's trait.
2266+ Res :: SelfTyAlias { alias_to : impl_def_id, is_trait_impl : true , .. } => {
2267+ let hir:: ItemKind :: Impl ( hir:: Impl { of_trait : Some ( trait_ref) , .. } ) =
2268+ self . tcx . hir_node_by_def_id ( impl_def_id. expect_local ( ) ) . expect_item ( ) . kind
2269+ else {
2270+ return None ;
2271+ } ;
2272+ BoundVarContext :: supertrait_hrtb_vars (
2273+ self . tcx ,
2274+ trait_ref. trait_def_id ( ) ?,
2275+ segment. ident ,
2276+ tag,
2277+ )
2278+ }
2279+ _ => None ,
2280+ }
2281+ }
2282+
22562283 /// Walk the generics of the item for a trait bound whose self type
22572284 /// corresponds to the expected res, and return the trait def id.
22582285 fn for_each_trait_bound_on_res ( & self , expected_res : Res ) -> impl Iterator < Item = DefId > {
0 commit comments