@@ -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 definition kinds that may 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 {
@@ -1652,8 +1694,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16521694 #[ instrument( level = "debug" , skip( self ) ) ]
16531695 fn visit_segment_args (
16541696 & mut self ,
1655- path : & hir:: Path < ' tcx > ,
1656- index : usize ,
1697+ container : Option < ( DefId , & [ hir:: PathSegment < ' tcx > ] ) > ,
16571698 generic_args : & ' tcx hir:: GenericArgs < ' tcx > ,
16581699 ) {
16591700 if let Some ( ( inputs, output) ) = generic_args. paren_sugar_inputs_output ( ) {
@@ -1669,40 +1710,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16691710 }
16701711 }
16711712
1672- // Figure out if this is an "eligible generic container" that brings along ambient object
1673- // lifetime defaults for trait object types contained in any of the type arguments passed to
1674- // it (any inner generic containers will of course end up shadowing that the default).
1675- let depth = path. segments . len ( ) - index - 1 ;
1676- let container = match ( path. res , depth) {
1677- ( Res :: Def ( DefKind :: AssocTy , def_id) , 1 ) => {
1678- Some ( ( self . tcx . parent ( def_id) , & path. segments [ ..=index] ) )
1679- }
1680- ( Res :: Def ( DefKind :: Variant , def_id) , 0 ) => {
1681- Some ( ( self . tcx . parent ( def_id) , path. segments ) )
1682- }
1683- // FIXME(trait_alias): Arguably, trait aliases are eligible generic containers.
1684- (
1685- Res :: Def (
1686- DefKind :: Struct
1687- | DefKind :: Union
1688- | DefKind :: Enum
1689- | DefKind :: TyAlias
1690- | DefKind :: Trait
1691- | DefKind :: AssocTy ,
1692- def_id,
1693- ) ,
1694- 0 ,
1695- ) => Some ( ( def_id, path. segments ) ) ,
1696- // Note: We don't need to care about definition kinds that may have generics if they
1697- // can only ever appear in positions where we can perform type inference (i.e., bodies).
1698- // FIXME(mgca): @fmease thinks that under (m)GCA we now also need to care about e.g.,
1699- // type-level Consts (GCI) and AssocConsts (maybe also Fns, AssocFns) here
1700- // since they appear outside of bodies (once the feature is more complete).
1701- _ => None ,
1702- } ;
1703-
1704- debug ! ( ?container) ;
1705-
17061713 let object_lifetime_defaults = container. map_or_else ( Vec :: new, |( def_id, segs) | {
17071714 self . compute_ambient_object_lifetime_defaults ( def_id, segs)
17081715 } ) ;
@@ -2143,72 +2150,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
21432150 matches ! ( args. parenthesized, hir:: GenericArgsParentheses :: ReturnTypeNotation )
21442151 } ) =>
21452152 {
2146- // First, ignore a qself that isn't a type or `Self` param. Those are the
2147- // only ones that support `T::Assoc` anyways in HIR lowering.
2148- let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = qself. kind else {
2153+ let Some ( ( bound_vars, assoc_item) ) = self . limited_resolve_type_relative_path (
2154+ ty:: AssocTag :: Fn ,
2155+ qself,
2156+ item_segment,
2157+ false ,
2158+ ) else {
21492159 return ;
21502160 } ;
2151- match path. res {
2152- Res :: Def ( DefKind :: TyParam , _) | Res :: SelfTyParam { trait_ : _ } => {
2153- let mut bounds =
2154- self . for_each_trait_bound_on_res ( path. res ) . filter_map ( |trait_def_id| {
2155- BoundVarContext :: supertrait_hrtb_vars (
2156- self . tcx ,
2157- trait_def_id,
2158- item_segment. ident ,
2159- ty:: AssocTag :: Fn ,
2160- )
2161- } ) ;
2162-
2163- let Some ( ( bound_vars, assoc_item) ) = bounds. next ( ) else {
2164- // This will error in HIR lowering.
2165- self . tcx
2166- . dcx ( )
2167- . span_delayed_bug ( path. span , "no resolution for RTN path" ) ;
2168- return ;
2169- } ;
2170-
2171- // Don't bail if we have identical bounds, which may be collected from
2172- // something like `T: Bound + Bound`, or via elaborating supertraits.
2173- for ( second_vars, second_assoc_item) in bounds {
2174- if second_vars != bound_vars || second_assoc_item != assoc_item {
2175- // This will error in HIR lowering.
2176- self . tcx . dcx ( ) . span_delayed_bug (
2177- path. span ,
2178- "ambiguous resolution for RTN path" ,
2179- ) ;
2180- return ;
2181- }
2182- }
2183-
2184- ( bound_vars, assoc_item. def_id , item_segment)
2185- }
2186- // If we have a self type alias (in an impl), try to resolve an
2187- // associated item from one of the supertraits of the impl's trait.
2188- Res :: SelfTyAlias { alias_to : impl_def_id, is_trait_impl : true , .. } => {
2189- let hir:: ItemKind :: Impl ( hir:: Impl { of_trait : Some ( trait_ref) , .. } ) = self
2190- . tcx
2191- . hir_node_by_def_id ( impl_def_id. expect_local ( ) )
2192- . expect_item ( )
2193- . kind
2194- else {
2195- return ;
2196- } ;
2197- let Some ( trait_def_id) = trait_ref. trait_def_id ( ) else {
2198- return ;
2199- } ;
2200- let Some ( ( bound_vars, assoc_item) ) = BoundVarContext :: supertrait_hrtb_vars (
2201- self . tcx ,
2202- trait_def_id,
2203- item_segment. ident ,
2204- ty:: AssocTag :: Fn ,
2205- ) else {
2206- return ;
2207- } ;
2208- ( bound_vars, assoc_item. def_id , item_segment)
2209- }
2210- _ => return ,
2211- }
2161+ ( bound_vars, assoc_item. def_id , item_segment)
22122162 }
22132163
22142164 _ => return ,
@@ -2247,6 +2197,83 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
22472197 self . record_late_bound_vars ( item_segment. hir_id , existing_bound_vars_saved) ;
22482198 }
22492199
2200+ /// In a limited fashion, try to resolve the given type-relative path of the given kind.
2201+ fn limited_resolve_type_relative_path (
2202+ & self ,
2203+ tag : ty:: AssocTag ,
2204+ qself : & ' tcx hir:: Ty < ' tcx > ,
2205+ segment : & ' tcx hir:: PathSegment < ' tcx > ,
2206+ speculative : bool ,
2207+ ) -> Option < ( Vec < ty:: BoundVariableKind > , & ' tcx ty:: AssocItem ) > {
2208+ // This mimics HIR ty lowering's `lower_assoc_path_shared`.
2209+ // FIXME: Duplicating efforts is not robust or sustainable/maintainable.
2210+ // Ideally, we'd simply obtain the resulting type-dependent defs from
2211+ // HIR ty lowering (not only in FnCtxts but also in ItemCtxts!).
2212+
2213+ // First, ignore a qself that isn't a type or `Self` param. Those are the only ones
2214+ // that support `T::Assoc` anyways in HIR ty lowering at the time of writing.
2215+ let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = qself. kind else {
2216+ return None ;
2217+ } ;
2218+
2219+ match path. res {
2220+ Res :: Def ( DefKind :: TyParam , _) | Res :: SelfTyParam { trait_ : _ } => {
2221+ let mut bounds =
2222+ self . for_each_trait_bound_on_res ( path. res ) . filter_map ( |trait_def_id| {
2223+ BoundVarContext :: supertrait_hrtb_vars (
2224+ self . tcx ,
2225+ trait_def_id,
2226+ segment. ident ,
2227+ tag,
2228+ )
2229+ } ) ;
2230+
2231+ let Some ( ( bound_vars, assoc_item) ) = bounds. next ( ) else {
2232+ if !speculative {
2233+ // This will error in HIR ty lowering.
2234+ self . tcx
2235+ . dcx ( )
2236+ . span_delayed_bug ( path. span , "no resolution for type-relative path" ) ;
2237+ }
2238+ return None ;
2239+ } ;
2240+
2241+ // Don't bail if we have identical bounds, which may be collected from
2242+ // something like `T: Bound + Bound`, or via elaborating supertraits.
2243+ for ( second_vars, second_assoc_item) in bounds {
2244+ if second_vars != bound_vars || second_assoc_item != assoc_item {
2245+ if !speculative {
2246+ // This will error in HIR ty lowering.
2247+ self . tcx . dcx ( ) . span_delayed_bug (
2248+ path. span ,
2249+ "ambiguous resolution for type-relative path" ,
2250+ ) ;
2251+ }
2252+ return None ;
2253+ }
2254+ }
2255+
2256+ Some ( ( bound_vars, assoc_item) )
2257+ }
2258+ // If we have a self type alias (in an impl), try to resolve an
2259+ // associated item from one of the supertraits of the impl's trait.
2260+ Res :: SelfTyAlias { alias_to : impl_def_id, is_trait_impl : true , .. } => {
2261+ let hir:: ItemKind :: Impl ( hir:: Impl { of_trait : Some ( trait_ref) , .. } ) =
2262+ self . tcx . hir_node_by_def_id ( impl_def_id. expect_local ( ) ) . expect_item ( ) . kind
2263+ else {
2264+ return None ;
2265+ } ;
2266+ BoundVarContext :: supertrait_hrtb_vars (
2267+ self . tcx ,
2268+ trait_ref. trait_def_id ( ) ?,
2269+ segment. ident ,
2270+ tag,
2271+ )
2272+ }
2273+ _ => None ,
2274+ }
2275+ }
2276+
22502277 /// Walk the generics of the item for a trait bound whose self type
22512278 /// corresponds to the expected res, and return the trait def id.
22522279 fn for_each_trait_bound_on_res ( & self , expected_res : Res ) -> impl Iterator < Item = DefId > {
0 commit comments