@@ -3,9 +3,9 @@ use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
33use crate :: ty:: { self , GenericArgs , ParamEnv , ParamEnvAnd , Ty , TyCtxt , TypeVisitableExt } ;
44use rustc_data_structures:: intern:: Interned ;
55use rustc_error_messages:: MultiSpan ;
6- use rustc_hir as hir;
76use 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 } ;
99use rustc_macros:: HashStable ;
1010use rustc_type_ir:: { self as ir, TypeFlags , WithCachedTypeInfo } ;
1111use tracing:: { debug, instrument} ;
@@ -182,16 +182,52 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
182182 }
183183}
184184
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+
185202impl < ' 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+
186222 /// Literals and const generic parameters are eagerly converted to a constant, everything else
187223 /// becomes `Unevaluated`.
188224 #[ instrument( skip( tcx) , level = "debug" ) ]
189225 pub fn from_anon_const ( tcx : TyCtxt < ' tcx > , def : LocalDefId ) -> Self {
190226 let body_id = match tcx. hir_node_by_def_id ( def) {
191227 hir:: Node :: AnonConst ( ac) => ac. body ,
192- _ => span_bug ! (
228+ node => span_bug ! (
193229 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:?} "
195231 ) ,
196232 } ;
197233
@@ -200,7 +236,7 @@ impl<'tcx> Const<'tcx> {
200236
201237 let ty = tcx. type_of ( def) . no_bound_vars ( ) . expect ( "const parameter types cannot be generic" ) ;
202238
203- match Self :: try_from_lit_or_param ( tcx, ty, expr) {
239+ match Self :: try_from_lit ( tcx, ty, expr) {
204240 Some ( v) => v,
205241 None => ty:: Const :: new_unevaluated (
206242 tcx,
@@ -212,12 +248,36 @@ impl<'tcx> Const<'tcx> {
212248 }
213249 }
214250
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+
215279 #[ 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 > {
221281 // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
222282 // currently have to be wrapped in curly brackets, so it's necessary to special-case.
223283 let expr = match & expr. kind {
@@ -250,34 +310,19 @@ impl<'tcx> Const<'tcx> {
250310 }
251311 }
252312
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 (
259315 _,
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 ) ) ;
280323 }
324+
325+ None
281326 }
282327
283328 #[ inline]
0 commit comments