@@ -3,9 +3,9 @@ use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
3
3
use crate :: ty:: { self , GenericArgs , ParamEnv , ParamEnvAnd , Ty , TyCtxt , TypeVisitableExt } ;
4
4
use rustc_data_structures:: intern:: Interned ;
5
5
use rustc_error_messages:: MultiSpan ;
6
- use rustc_hir as hir;
7
6
use rustc_hir:: def:: { DefKind , Res } ;
8
- use rustc_hir:: def_id:: LocalDefId ;
7
+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
8
+ use rustc_hir:: { self as hir, HirId } ;
9
9
use rustc_macros:: HashStable ;
10
10
use rustc_type_ir:: { self as ir, TypeFlags , WithCachedTypeInfo } ;
11
11
use tracing:: { debug, instrument} ;
@@ -182,16 +182,52 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
182
182
}
183
183
}
184
184
185
+ /// In some cases, [`hir::ConstArg`]s that are being used in the type system
186
+ /// through const generics need to have their type "fed" to them
187
+ /// using the query system.
188
+ ///
189
+ /// Use this enum with [`Const::from_const_arg`] to instruct it with the
190
+ /// desired behavior.
191
+ #[ derive( Debug , Clone , Copy ) ]
192
+ pub enum FeedConstTy {
193
+ /// Feed the type.
194
+ ///
195
+ /// The `DefId` belongs to the const param that we are supplying
196
+ /// this (anon) const arg to.
197
+ Param ( DefId ) ,
198
+ /// Don't feed the type.
199
+ No ,
200
+ }
201
+
185
202
impl < ' tcx > Const < ' tcx > {
203
+ /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self).
204
+ #[ instrument( skip( tcx) , level = "debug" ) ]
205
+ #[ allow( irrefutable_let_patterns) ]
206
+ pub fn from_const_arg (
207
+ tcx : TyCtxt < ' tcx > ,
208
+ const_arg : & ' tcx hir:: ConstArg < ' tcx > ,
209
+ feed : FeedConstTy ,
210
+ ) -> Self {
211
+ if let FeedConstTy :: Param ( param_def_id) = feed
212
+ && let hir:: ConstArgKind :: Anon ( anon) = & const_arg. kind
213
+ {
214
+ tcx. feed_anon_const_type ( anon. def_id , tcx. type_of ( param_def_id) ) ;
215
+ }
216
+
217
+ match const_arg. kind {
218
+ hir:: ConstArgKind :: Anon ( anon) => Self :: from_anon_const ( tcx, anon. def_id ) ,
219
+ }
220
+ }
221
+
186
222
/// Literals and const generic parameters are eagerly converted to a constant, everything else
187
223
/// becomes `Unevaluated`.
188
224
#[ instrument( skip( tcx) , level = "debug" ) ]
189
225
pub fn from_anon_const ( tcx : TyCtxt < ' tcx > , def : LocalDefId ) -> Self {
190
226
let body_id = match tcx. hir_node_by_def_id ( def) {
191
227
hir:: Node :: AnonConst ( ac) => ac. body ,
192
- _ => span_bug ! (
228
+ node => span_bug ! (
193
229
tcx. def_span( def. to_def_id( ) ) ,
194
- "from_anon_const can only process anonymous constants"
230
+ "from_anon_const can only process anonymous constants, not {node:?} "
195
231
) ,
196
232
} ;
197
233
@@ -200,7 +236,7 @@ impl<'tcx> Const<'tcx> {
200
236
201
237
let ty = tcx. type_of ( def) . no_bound_vars ( ) . expect ( "const parameter types cannot be generic" ) ;
202
238
203
- match Self :: try_from_lit_or_param ( tcx, ty, expr) {
239
+ match Self :: try_from_lit ( tcx, ty, expr) {
204
240
Some ( v) => v,
205
241
None => ty:: Const :: new_unevaluated (
206
242
tcx,
@@ -212,12 +248,36 @@ impl<'tcx> Const<'tcx> {
212
248
}
213
249
}
214
250
251
+ /// Lower a const param to a [`Const`].
252
+ ///
253
+ /// IMPORTANT: `qpath` must be a const param, otherwise this will panic
254
+ fn from_param ( tcx : TyCtxt < ' tcx > , qpath : hir:: QPath < ' tcx > , hir_id : HirId ) -> Self {
255
+ let hir:: QPath :: Resolved ( _, & hir:: Path { res : Res :: Def ( DefKind :: ConstParam , def_id) , .. } ) =
256
+ qpath
257
+ else {
258
+ span_bug ! ( qpath. span( ) , "non-param {qpath:?} passed to Const::from_param" )
259
+ } ;
260
+
261
+ match tcx. named_bound_var ( hir_id) {
262
+ Some ( rbv:: ResolvedArg :: EarlyBound ( _) ) => {
263
+ // Find the name and index of the const parameter by indexing the generics of
264
+ // the parent item and construct a `ParamConst`.
265
+ let item_def_id = tcx. parent ( def_id) ;
266
+ let generics = tcx. generics_of ( item_def_id) ;
267
+ let index = generics. param_def_id_to_index [ & def_id] ;
268
+ let name = tcx. item_name ( def_id) ;
269
+ ty:: Const :: new_param ( tcx, ty:: ParamConst :: new ( index, name) )
270
+ }
271
+ Some ( rbv:: ResolvedArg :: LateBound ( debruijn, index, _) ) => {
272
+ ty:: Const :: new_bound ( tcx, debruijn, ty:: BoundVar :: from_u32 ( index) )
273
+ }
274
+ Some ( rbv:: ResolvedArg :: Error ( guar) ) => ty:: Const :: new_error ( tcx, guar) ,
275
+ arg => bug ! ( "unexpected bound var resolution for {:?}: {arg:?}" , hir_id) ,
276
+ }
277
+ }
278
+
215
279
#[ instrument( skip( tcx) , level = "debug" ) ]
216
- fn try_from_lit_or_param (
217
- tcx : TyCtxt < ' tcx > ,
218
- ty : Ty < ' tcx > ,
219
- expr : & ' tcx hir:: Expr < ' tcx > ,
220
- ) -> Option < Self > {
280
+ fn try_from_lit ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) -> Option < Self > {
221
281
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
222
282
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
223
283
let expr = match & expr. kind {
@@ -250,34 +310,19 @@ impl<'tcx> Const<'tcx> {
250
310
}
251
311
}
252
312
253
- // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
254
- // does not provide the parents generics to anonymous constants. We still allow generic const
255
- // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
256
- // ever try to instantiate the generic parameters in their bodies.
257
- match expr. kind {
258
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved (
313
+ if let hir:: ExprKind :: Path (
314
+ qpath @ hir:: QPath :: Resolved (
259
315
_,
260
- & hir:: Path { res : Res :: Def ( DefKind :: ConstParam , def_id) , .. } ,
261
- ) ) => {
262
- match tcx. named_bound_var ( expr. hir_id ) {
263
- Some ( rbv:: ResolvedArg :: EarlyBound ( _) ) => {
264
- // Find the name and index of the const parameter by indexing the generics of
265
- // the parent item and construct a `ParamConst`.
266
- let item_def_id = tcx. parent ( def_id) ;
267
- let generics = tcx. generics_of ( item_def_id) ;
268
- let index = generics. param_def_id_to_index [ & def_id] ;
269
- let name = tcx. item_name ( def_id) ;
270
- Some ( ty:: Const :: new_param ( tcx, ty:: ParamConst :: new ( index, name) ) )
271
- }
272
- Some ( rbv:: ResolvedArg :: LateBound ( debruijn, index, _) ) => {
273
- Some ( ty:: Const :: new_bound ( tcx, debruijn, ty:: BoundVar :: from_u32 ( index) ) )
274
- }
275
- Some ( rbv:: ResolvedArg :: Error ( guar) ) => Some ( ty:: Const :: new_error ( tcx, guar) ) ,
276
- arg => bug ! ( "unexpected bound var resolution for {:?}: {arg:?}" , expr. hir_id) ,
277
- }
278
- }
279
- _ => None ,
316
+ & hir:: Path { res : Res :: Def ( DefKind :: ConstParam , _) , .. } ,
317
+ ) ,
318
+ ) = expr. kind
319
+ {
320
+ // FIXME: once ConstArgKind::Path added, uncomment span_bug and delete return
321
+ // span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible")
322
+ return Some ( Self :: from_param ( tcx, qpath, expr. hir_id ) ) ;
280
323
}
324
+
325
+ None
281
326
}
282
327
283
328
#[ inline]
0 commit comments