Skip to content

Commit 8ac3ffe

Browse files
committed
move ConstKind to typeir and move inherent impls to Const
1 parent 9227ff2 commit 8ac3ffe

File tree

9 files changed

+413
-222
lines changed

9 files changed

+413
-222
lines changed

compiler/rustc_middle/src/ty/consts.rs

+152-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::middle::resolve_bound_vars as rbv;
2-
use crate::mir::interpret::LitToConstInput;
3-
use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
2+
use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar};
3+
use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
44
use rustc_data_structures::intern::Interned;
55
use rustc_error_messages::MultiSpan;
66
use rustc_hir as hir;
@@ -14,9 +14,13 @@ mod valtree;
1414

1515
pub use int::*;
1616
pub use kind::*;
17+
use rustc_span::ErrorGuaranteed;
1718
use rustc_span::DUMMY_SP;
19+
use rustc_target::abi::Size;
1820
pub use valtree::*;
1921

22+
use super::sty::ConstKind;
23+
2024
/// Use this rather than `ConstData`, whenever possible.
2125
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
2226
#[rustc_pass_by_value]
@@ -32,6 +36,16 @@ pub struct ConstData<'tcx> {
3236
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
3337
static_assert_size!(ConstData<'_>, 40);
3438

39+
enum EvalMode {
40+
Typeck,
41+
Mir,
42+
}
43+
44+
enum EvalResult<'tcx> {
45+
ValTree(ty::ValTree<'tcx>),
46+
ConstVal(ConstValue<'tcx>),
47+
}
48+
3549
impl<'tcx> Const<'tcx> {
3650
#[inline]
3751
pub fn ty(self) -> Ty<'tcx> {
@@ -293,12 +307,12 @@ impl<'tcx> Const<'tcx> {
293307
assert_eq!(self.ty(), ty);
294308
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
295309
// if `ty` does not depend on generic parameters, use an empty param_env
296-
self.kind().eval(tcx, param_env).try_to_bits(size)
310+
self.eval(tcx, param_env).try_to_bits(size)
297311
}
298312

299313
#[inline]
300314
pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
301-
self.kind().eval(tcx, param_env).try_to_bool()
315+
self.eval(tcx, param_env).try_to_bool()
302316
}
303317

304318
#[inline]
@@ -307,14 +321,14 @@ impl<'tcx> Const<'tcx> {
307321
tcx: TyCtxt<'tcx>,
308322
param_env: ParamEnv<'tcx>,
309323
) -> Option<u64> {
310-
self.kind().eval(tcx, param_env).try_to_target_usize(tcx)
324+
self.eval(tcx, param_env).try_to_target_usize(tcx)
311325
}
312326

313327
#[inline]
314328
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
315329
/// unevaluated constant.
316330
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
317-
if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
331+
if let Some(val) = self.try_eval_for_typeck(tcx, param_env) {
318332
match val {
319333
Ok(val) => ty::Const::new_value(tcx, val, self.ty()),
320334
Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
@@ -339,6 +353,138 @@ impl<'tcx> Const<'tcx> {
339353
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
340354
}
341355

356+
#[inline]
357+
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
358+
/// return `None`.
359+
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
360+
pub fn try_eval_for_mir(
361+
self,
362+
tcx: TyCtxt<'tcx>,
363+
param_env: ParamEnv<'tcx>,
364+
) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
365+
match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
366+
Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
367+
Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
368+
Some(Err(e)) => Some(Err(e)),
369+
None => None,
370+
}
371+
}
372+
373+
#[inline]
374+
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
375+
/// return `None`.
376+
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
377+
pub fn try_eval_for_typeck(
378+
self,
379+
tcx: TyCtxt<'tcx>,
380+
param_env: ParamEnv<'tcx>,
381+
) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
382+
match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
383+
Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
384+
Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
385+
Some(Err(e)) => Some(Err(e)),
386+
None => None,
387+
}
388+
}
389+
390+
#[inline]
391+
fn try_eval_inner(
392+
self,
393+
tcx: TyCtxt<'tcx>,
394+
param_env: ParamEnv<'tcx>,
395+
eval_mode: EvalMode,
396+
) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
397+
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
398+
if let ConstKind::Unevaluated(unevaluated) = self.kind() {
399+
use crate::mir::interpret::ErrorHandled;
400+
401+
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
402+
// also does later, but we want to do it before checking for
403+
// inference variables.
404+
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
405+
// so that we don't try to invoke this query with
406+
// any region variables.
407+
408+
// HACK(eddyb) when the query key would contain inference variables,
409+
// attempt using identity substs and `ParamEnv` instead, that will succeed
410+
// when the expression doesn't depend on any parameters.
411+
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
412+
// we can call `infcx.const_eval_resolve` which handles inference variables.
413+
let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
414+
tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
415+
def: unevaluated.def,
416+
substs: InternalSubsts::identity_for_item(tcx, unevaluated.def),
417+
})
418+
} else {
419+
tcx.erase_regions(param_env)
420+
.with_reveal_all_normalized(tcx)
421+
.and(tcx.erase_regions(unevaluated))
422+
};
423+
424+
// FIXME(eddyb) maybe the `const_eval_*` methods should take
425+
// `ty::ParamEnvAnd` instead of having them separate.
426+
let (param_env, unevaluated) = param_env_and.into_parts();
427+
// try to resolve e.g. associated constants to their definition on an impl, and then
428+
// evaluate the const.
429+
match eval_mode {
430+
EvalMode::Typeck => {
431+
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
432+
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
433+
// and we use the original type, so nothing from `substs`
434+
// (which may be identity substs, see above),
435+
// can leak through `val` into the const we return.
436+
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
437+
Err(ErrorHandled::TooGeneric) => None,
438+
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
439+
}
440+
}
441+
EvalMode::Mir => {
442+
match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) {
443+
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
444+
// and we use the original type, so nothing from `substs`
445+
// (which may be identity substs, see above),
446+
// can leak through `val` into the const we return.
447+
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
448+
Err(ErrorHandled::TooGeneric) => None,
449+
Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
450+
}
451+
}
452+
}
453+
} else {
454+
None
455+
}
456+
}
457+
458+
#[inline]
459+
pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
460+
if let ConstKind::Value(val) = self.kind() { Some(val) } else { None }
461+
}
462+
463+
#[inline]
464+
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
465+
self.try_to_value()?.try_to_scalar()
466+
}
467+
468+
#[inline]
469+
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
470+
self.try_to_value()?.try_to_scalar_int()
471+
}
472+
473+
#[inline]
474+
pub fn try_to_bits(self, size: Size) -> Option<u128> {
475+
self.try_to_scalar_int()?.to_bits(size).ok()
476+
}
477+
478+
#[inline]
479+
pub fn try_to_bool(self) -> Option<bool> {
480+
self.try_to_scalar_int()?.try_into().ok()
481+
}
482+
483+
#[inline]
484+
pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
485+
self.try_to_value()?.try_to_target_usize(tcx)
486+
}
487+
342488
pub fn is_ct_infer(self) -> bool {
343489
matches!(self.kind(), ty::ConstKind::Infer(_))
344490
}

0 commit comments

Comments
 (0)