@@ -17,6 +17,118 @@ use rustc_trait_selection::traits;
1717use super :: ItemCtxt ;
1818use super :: { bad_placeholder_type, is_suggestable_infer_ty} ;
1919
20+ pub ( super ) fn const_param_of ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < DefId > {
21+ use hir:: * ;
22+
23+ // We can just exit here, as `const_param_of` is called for
24+ // all generic arguments, meaning that we would return `None` anyways
25+ // if `const_param_of` is not cached
26+ let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id. as_local ( ) ?) ;
27+
28+ if let Node :: AnonConst ( _) = tcx. hir ( ) . get ( hir_id) {
29+ let parent_node_id = tcx. hir ( ) . get_parent_node ( hir_id) ;
30+ let parent_node = tcx. hir ( ) . get ( parent_node_id) ;
31+
32+ match parent_node {
33+ Node :: Expr ( & Expr {
34+ kind :
35+ ExprKind :: MethodCall ( segment, ..) | ExprKind :: Path ( QPath :: TypeRelative ( _, segment) ) ,
36+ ..
37+ } ) => {
38+ let body_owner = tcx. hir ( ) . get_parent_did ( parent_node_id) ;
39+ let tables = tcx. typeck_tables_of ( body_owner. to_def_id ( ) ) ;
40+ // This may fail in case the method/path does not actually exist.
41+ // As there is no relevant param for `def_id`, we simply return
42+ // `None` here.
43+ let type_dependent_def = tables. type_dependent_def_id ( parent_node_id) ?;
44+ let idx = segment
45+ . args
46+ . and_then ( |args| {
47+ args. args
48+ . iter ( )
49+ . filter ( |arg| arg. is_const ( ) )
50+ . position ( |arg| arg. id ( ) == hir_id)
51+ } )
52+ . unwrap_or_else ( || {
53+ bug ! ( "no arg matching AnonConst in segment" ) ;
54+ } ) ;
55+
56+ tcx. generics_of ( type_dependent_def)
57+ . params
58+ . iter ( )
59+ . filter ( |param| matches ! ( param. kind, ty:: GenericParamDefKind :: Const ) )
60+ . nth ( idx)
61+ . map ( |param| param. def_id )
62+ }
63+
64+ Node :: Ty ( & Ty { kind : TyKind :: Path ( _) , .. } )
65+ | Node :: Expr ( & Expr { kind : ExprKind :: Struct ( ..) , .. } )
66+ | Node :: Expr ( & Expr { kind : ExprKind :: Path ( _) , .. } )
67+ | Node :: TraitRef ( ..) => {
68+ let path = match parent_node {
69+ Node :: Ty ( & Ty { kind : TyKind :: Path ( QPath :: Resolved ( _, path) ) , .. } )
70+ | Node :: TraitRef ( & TraitRef { path, .. } ) => & * path,
71+ Node :: Expr ( & Expr {
72+ kind :
73+ ExprKind :: Path ( QPath :: Resolved ( _, path) )
74+ | ExprKind :: Struct ( & QPath :: Resolved ( _, path) , ..) ,
75+ ..
76+ } ) => {
77+ let body_owner = tcx. hir ( ) . get_parent_did ( parent_node_id) ;
78+ let _tables = tcx. typeck_tables_of ( body_owner. to_def_id ( ) ) ;
79+ & * path
80+ }
81+ _ => span_bug ! ( DUMMY_SP , "unexpected const parent path {:?}" , parent_node) ,
82+ } ;
83+
84+ // We've encountered an `AnonConst` in some path, so we need to
85+ // figure out which generic parameter it corresponds to and return
86+ // the relevant type.
87+
88+ let ( arg_index, segment) = path
89+ . segments
90+ . iter ( )
91+ . filter_map ( |seg| seg. args . map ( |args| ( args. args , seg) ) )
92+ . find_map ( |( args, seg) | {
93+ args. iter ( )
94+ . filter ( |arg| arg. is_const ( ) )
95+ . position ( |arg| arg. id ( ) == hir_id)
96+ . map ( |index| ( index, seg) )
97+ } )
98+ . unwrap_or_else ( || {
99+ bug ! ( "no arg matching AnonConst in path" ) ;
100+ } ) ;
101+
102+ // Try to use the segment resolution if it is valid, otherwise we
103+ // default to the path resolution.
104+ let res = segment. res . filter ( |& r| r != Res :: Err ) . unwrap_or ( path. res ) ;
105+ let generics = match res {
106+ Res :: Def ( DefKind :: Ctor ( ..) , def_id) => {
107+ tcx. generics_of ( tcx. parent ( def_id) . unwrap ( ) )
108+ }
109+ Res :: Def ( _, def_id) => tcx. generics_of ( def_id) ,
110+ res => span_bug ! (
111+ DUMMY_SP ,
112+ "unexpected anon const res {:?} in path: {:?}" ,
113+ res,
114+ path,
115+ ) ,
116+ } ;
117+
118+ generics
119+ . params
120+ . iter ( )
121+ . filter ( |param| matches ! ( param. kind, ty:: GenericParamDefKind :: Const ) )
122+ . nth ( arg_index)
123+ . map ( |param| param. def_id )
124+ }
125+ _ => return None ,
126+ }
127+ } else {
128+ None
129+ }
130+ }
131+
20132pub ( super ) fn type_of ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Ty < ' _ > {
21133 use rustc_hir:: * ;
22134
@@ -187,6 +299,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
187299 }
188300
189301 Node :: AnonConst ( _) => {
302+ if let Some ( param) = tcx. const_param_of ( def_id) {
303+ // We defer to `type_of` of the corresponding parameter
304+ // for generic arguments.
305+ return tcx. type_of ( param) ;
306+ }
307+
190308 let parent_node = tcx. hir ( ) . get ( tcx. hir ( ) . get_parent_node ( hir_id) ) ;
191309 match parent_node {
192310 Node :: Ty ( & Ty { kind : TyKind :: Array ( _, ref constant) , .. } )
@@ -203,94 +321,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
203321 . discr_type ( )
204322 . to_ty ( tcx) ,
205323
206- Node :: Ty ( & Ty { kind : TyKind :: Path ( _) , .. } )
207- | Node :: Expr ( & Expr { kind : ExprKind :: Struct ( ..) | ExprKind :: Path ( _) , .. } )
208- | Node :: TraitRef ( ..) => {
209- let path = match parent_node {
210- Node :: Ty ( & Ty { kind : TyKind :: Path ( QPath :: Resolved ( _, path) ) , .. } )
211- | Node :: Expr ( & Expr {
212- kind :
213- ExprKind :: Path ( QPath :: Resolved ( _, path) )
214- | ExprKind :: Struct ( & QPath :: Resolved ( _, path) , ..) ,
215- ..
216- } )
217- | Node :: TraitRef ( & TraitRef { path, .. } ) => & * path,
218- _ => {
219- return tcx. ty_error_with_message (
220- DUMMY_SP ,
221- & format ! ( "unexpected const parent path {:?}" , parent_node) ,
222- ) ;
223- }
224- } ;
225-
226- // We've encountered an `AnonConst` in some path, so we need to
227- // figure out which generic parameter it corresponds to and return
228- // the relevant type.
229-
230- let ( arg_index, segment) = path
231- . segments
232- . iter ( )
233- . filter_map ( |seg| seg. args . as_ref ( ) . map ( |args| ( args. args , seg) ) )
234- . find_map ( |( args, seg) | {
235- args. iter ( )
236- . filter ( |arg| arg. is_const ( ) )
237- . enumerate ( )
238- . filter ( |( _, arg) | arg. id ( ) == hir_id)
239- . map ( |( index, _) | ( index, seg) )
240- . next ( )
241- } )
242- . unwrap_or_else ( || {
243- bug ! ( "no arg matching AnonConst in path" ) ;
244- } ) ;
245-
246- // Try to use the segment resolution if it is valid, otherwise we
247- // default to the path resolution.
248- let res = segment. res . filter ( |& r| r != Res :: Err ) . unwrap_or ( path. res ) ;
249- let generics = match res {
250- Res :: Def ( DefKind :: Ctor ( ..) , def_id) => {
251- tcx. generics_of ( tcx. parent ( def_id) . unwrap ( ) )
252- }
253- Res :: Def ( _, def_id) => tcx. generics_of ( def_id) ,
254- res => {
255- return tcx. ty_error_with_message (
256- DUMMY_SP ,
257- & format ! (
258- "unexpected anon const res {:?} in path: {:?}" ,
259- res, path,
260- ) ,
261- ) ;
262- }
263- } ;
264-
265- let ty = generics
266- . params
267- . iter ( )
268- . filter ( |param| {
269- if let ty:: GenericParamDefKind :: Const = param. kind {
270- true
271- } else {
272- false
273- }
274- } )
275- . nth ( arg_index)
276- . map ( |param| tcx. type_of ( param. def_id ) ) ;
277-
278- if let Some ( ty) = ty {
279- ty
280- } else {
281- // This is no generic parameter associated with the arg. This is
282- // probably from an extra arg where one is not needed.
283- tcx. ty_error_with_message (
284- DUMMY_SP ,
285- & format ! (
286- "missing generic parameter for `AnonConst`, \
287- parent: {:?}, res: {:?}",
288- parent_node, res
289- ) ,
290- )
291- }
292- }
293-
294324 x => tcx. ty_error_with_message (
295325 DUMMY_SP ,
296326 & format ! ( "unexpected const parent in type_of_def_id(): {:?}" , x) ,
0 commit comments