1 use super::{ErrorHandled, EvalToConstValueResult, GlobalId}; 2 3 use crate::mir; 4 use crate::ty::subst::InternalSubsts; 5 use crate::ty::{self, TyCtxt}; 6 use rustc_hir::def_id::DefId; 7 use rustc_span::Span; 8 9 impl<'tcx> TyCtxt<'tcx> { 10 /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts 11 /// that can't take any generic arguments like statics, const items or enum discriminants. If a 12 /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx>13 pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { 14 // In some situations def_id will have substitutions within scope, but they aren't allowed 15 // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions 16 // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are 17 // encountered. 18 let substs = InternalSubsts::identity_for_item(self, def_id); 19 let instance = ty::Instance::new(def_id, substs); 20 let cid = GlobalId { instance, promoted: None }; 21 let param_env = self.param_env(def_id).with_reveal_all_normalized(self); 22 self.const_eval_global_id(param_env, cid, None) 23 } 24 25 /// Resolves and evaluates a constant. 26 /// 27 /// The constant can be located on a trait like `<A as B>::C`, in which case the given 28 /// substitutions and environment are used to resolve the constant. Alternatively if the 29 /// constant has generic parameters in scope the substitutions are used to evaluate the value of 30 /// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count 31 /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still 32 /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is 33 /// returned. 34 #[instrument(level = "debug", skip(self))] const_eval_resolve( self, param_env: ty::ParamEnv<'tcx>, ct: ty::Unevaluated<'tcx>, span: Option<Span>, ) -> EvalToConstValueResult<'tcx>35 pub fn const_eval_resolve( 36 self, 37 param_env: ty::ParamEnv<'tcx>, 38 ct: ty::Unevaluated<'tcx>, 39 span: Option<Span>, 40 ) -> EvalToConstValueResult<'tcx> { 41 match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) { 42 Ok(Some(instance)) => { 43 let cid = GlobalId { instance, promoted: ct.promoted }; 44 self.const_eval_global_id(param_env, cid, span) 45 } 46 Ok(None) => Err(ErrorHandled::TooGeneric), 47 Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), 48 } 49 } 50 const_eval_instance( self, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, span: Option<Span>, ) -> EvalToConstValueResult<'tcx>51 pub fn const_eval_instance( 52 self, 53 param_env: ty::ParamEnv<'tcx>, 54 instance: ty::Instance<'tcx>, 55 span: Option<Span>, 56 ) -> EvalToConstValueResult<'tcx> { 57 self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) 58 } 59 60 /// Evaluate a constant. const_eval_global_id( self, param_env: ty::ParamEnv<'tcx>, cid: GlobalId<'tcx>, span: Option<Span>, ) -> EvalToConstValueResult<'tcx>61 pub fn const_eval_global_id( 62 self, 63 param_env: ty::ParamEnv<'tcx>, 64 cid: GlobalId<'tcx>, 65 span: Option<Span>, 66 ) -> EvalToConstValueResult<'tcx> { 67 // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should 68 // improve caching of queries. 69 let inputs = self.erase_regions(param_env.and(cid)); 70 if let Some(span) = span { 71 self.at(span).eval_to_const_value_raw(inputs) 72 } else { 73 self.eval_to_const_value_raw(inputs) 74 } 75 } 76 77 /// Evaluate a static's initializer, returning the allocation of the initializer's memory. eval_static_initializer( self, def_id: DefId, ) -> Result<&'tcx mir::Allocation, ErrorHandled>78 pub fn eval_static_initializer( 79 self, 80 def_id: DefId, 81 ) -> Result<&'tcx mir::Allocation, ErrorHandled> { 82 trace!("eval_static_initializer: Need to compute {:?}", def_id); 83 assert!(self.is_static(def_id)); 84 let instance = ty::Instance::mono(self, def_id); 85 let gid = GlobalId { instance, promoted: None }; 86 self.eval_to_allocation(gid, ty::ParamEnv::reveal_all()) 87 } 88 89 /// Evaluate anything constant-like, returning the allocation of the final memory. eval_to_allocation( self, gid: GlobalId<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Result<&'tcx mir::Allocation, ErrorHandled>90 fn eval_to_allocation( 91 self, 92 gid: GlobalId<'tcx>, 93 param_env: ty::ParamEnv<'tcx>, 94 ) -> Result<&'tcx mir::Allocation, ErrorHandled> { 95 trace!("eval_to_allocation: Need to compute {:?}", gid); 96 let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; 97 Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) 98 } 99 } 100