1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
use crate::mir;
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::InternalSubsts;
use crate::ty::{self, query::TyCtxtAt, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_span::{Span, DUMMY_SP};
impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
// In some situations def_id will have substitutions within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
// encountered.
let substs = InternalSubsts::identity_for_item(self, def_id);
let instance = ty::Instance::new(def_id, substs);
let cid = GlobalId { instance, promoted: None };
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
self.const_eval_global_id(param_env, cid, None)
}
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
/// substitutions and environment are used to resolve the constant. Alternatively if the
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
#[instrument(level = "debug", skip(self))]
pub fn const_eval_resolve(
self,
param_env: ty::ParamEnv<'tcx>,
ct: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
// variables. We reject those here since `resolve_opt_const_arg`
// would fail otherwise.
//
// When trying to evaluate constants containing inference variables,
// use `Infcx::const_eval_resolve` instead.
if ct.substs.has_infer_types_or_consts() {
bug!("did not expect inference variables here");
}
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
}
Ok(None) => Err(ErrorHandled::TooGeneric),
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
}
}
pub fn const_eval_instance(
self,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
}
/// Evaluate a constant.
pub fn const_eval_global_id(
self,
param_env: ty::ParamEnv<'tcx>,
cid: GlobalId<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
let param_env = param_env.with_const();
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
if let Some(span) = span {
self.at(span).eval_to_const_value_raw(inputs)
} else {
self.eval_to_const_value_raw(inputs)
}
}
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
#[inline(always)]
pub fn eval_static_initializer(
self,
def_id: DefId,
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
self.at(DUMMY_SP).eval_static_initializer(def_id)
}
}
impl<'tcx> TyCtxtAt<'tcx> {
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
pub fn eval_static_initializer(
self,
def_id: DefId,
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
trace!("eval_static_initializer: Need to compute {:?}", def_id);
assert!(self.is_static(def_id));
let instance = ty::Instance::mono(*self, def_id);
let gid = GlobalId { instance, promoted: None };
self.eval_to_allocation(gid, ty::ParamEnv::reveal_all())
}
/// Evaluate anything constant-like, returning the allocation of the final memory.
fn eval_to_allocation(
self,
gid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
let param_env = param_env.with_const();
trace!("eval_to_allocation: Need to compute {:?}", gid);
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
}
}
impl<'tcx> TyCtxt<'tcx> {
/// Destructure a type-level constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
pub fn destructure_const(
self,
param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>,
) -> mir::DestructuredConst<'tcx> {
self.try_destructure_const(param_env_and_val).unwrap()
}
/// Destructure a mir constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
pub fn destructure_mir_constant(
self,
param_env: ty::ParamEnv<'tcx>,
constant: mir::ConstantKind<'tcx>,
) -> mir::DestructuredMirConstant<'tcx> {
self.try_destructure_mir_constant(param_env.and(constant)).unwrap()
}
}
|