@@ -29,6 +29,73 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
2929 let parent_node = tcx. hir ( ) . get ( parent_node_id) ;
3030
3131 match parent_node {
32+ // This match arm is for when the def_id appears in a GAT whose
33+ // path can't be resolved without typechecking e.g.
34+ //
35+ // trait Foo {
36+ // type Assoc<const N: usize>;
37+ // fn foo() -> Self::Assoc<3>;
38+ // }
39+ //
40+ // In the above code we would call this query with the def_id of 3 and
41+ // the parent_node we match on would be the hir node for Self::Assoc<3>
42+ //
43+ // `Self::Assoc<3>` cant be resolved without typchecking here as we
44+ // didnt write <Self as Foo>::Assoc<3>. If we did then another match
45+ // arm would handle this.
46+ //
47+ // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
48+ Node :: Ty ( hir_ty @ Ty { kind : TyKind :: Path ( QPath :: TypeRelative ( _, segment) ) , .. } ) => {
49+ // Find the Item containing the associated type so we can create an ItemCtxt.
50+ // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
51+ // ty which is a fully resolved projection.
52+ // For the code example above, this would mean converting Self::Assoc<3>
53+ // into a ty::Projection(<Self as Foo>::Assoc<3>)
54+ let item_hir_id = tcx
55+ . hir ( )
56+ . parent_iter ( hir_id)
57+ . filter ( |( _, node) | matches ! ( node, Node :: Item ( _) ) )
58+ . map ( |( id, _) | id)
59+ . next ( )
60+ . unwrap ( ) ;
61+ let item_did = tcx. hir ( ) . local_def_id ( item_hir_id) . to_def_id ( ) ;
62+ let item_ctxt = & ItemCtxt :: new ( tcx, item_did) as & dyn crate :: astconv:: AstConv < ' _ > ;
63+ let ty = item_ctxt. ast_ty_to_ty ( hir_ty) ;
64+
65+ // Iterate through the generics of the projection to find the one that corresponds to
66+ // the def_id that this query was called with. We filter to only const args here as a
67+ // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
68+ // but it can't hurt to be safe ^^
69+ if let ty:: Projection ( projection) = ty. kind ( ) {
70+ let generics = tcx. generics_of ( projection. item_def_id ) ;
71+
72+ let arg_index = segment
73+ . args
74+ . and_then ( |args| {
75+ args. args
76+ . iter ( )
77+ . filter ( |arg| arg. is_const ( ) )
78+ . position ( |arg| arg. id ( ) == hir_id)
79+ } )
80+ . unwrap_or_else ( || {
81+ bug ! ( "no arg matching AnonConst in segment" ) ;
82+ } ) ;
83+
84+ return generics
85+ . params
86+ . iter ( )
87+ . filter ( |param| matches ! ( param. kind, ty:: GenericParamDefKind :: Const ) )
88+ . nth ( arg_index)
89+ . map ( |param| param. def_id ) ;
90+ }
91+
92+ // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
93+ tcx. sess . delay_span_bug (
94+ tcx. def_span ( def_id) ,
95+ "unexpected non-GAT usage of an anon const" ,
96+ ) ;
97+ return None ;
98+ }
3299 Node :: Expr ( & Expr {
33100 kind :
34101 ExprKind :: MethodCall ( segment, ..) | ExprKind :: Path ( QPath :: TypeRelative ( _, segment) ) ,
0 commit comments