Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/consteval.rs')
-rw-r--r--crates/hir-ty/src/consteval.rs407
1 files changed, 181 insertions, 226 deletions
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 14b9cd203f..18ebe7d7a5 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -1,61 +1,48 @@
//! Constant evaluation details
+#[cfg(test)]
+mod tests;
+
use base_db::Crate;
-use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast};
use hir_def::{
- EnumVariantId, GeneralConstId, HasModule as _, StaticId,
- expr_store::{Body, HygieneId, path::Path},
+ EnumVariantId, GeneralConstId, HasModule, StaticId,
+ expr_store::Body,
hir::{Expr, ExprId},
- resolver::{Resolver, ValueNs},
type_ref::LiteralConstRef,
};
use hir_expand::Lookup;
-use stdx::never;
+use rustc_type_ir::inherent::IntoKind;
use triomphe::Arc;
use crate::{
- Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution,
- TraitEnvironment, Ty, TyBuilder, db::HirDatabase, display::DisplayTarget, generics::Generics,
- infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
+ LifetimeElisionKind, MemoryMap, TraitEnvironment, TyLoweringContext,
+ db::HirDatabase,
+ display::DisplayTarget,
+ infer::InferenceContext,
+ mir::{MirEvalError, MirLowerError},
+ next_solver::{
+ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
+ SolverDefId, Ty, ValueConst,
+ },
};
-use super::mir::{MirEvalError, MirLowerError, interpret_mir, lower_to_mir, pad16};
+use super::mir::{interpret_mir, lower_to_mir, pad16};
-/// Extension trait for [`Const`]
-pub trait ConstExt {
- /// Is a [`Const`] unknown?
- fn is_unknown(&self) -> bool;
+pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> {
+ Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
}
-impl ConstExt for Const {
- fn is_unknown(&self) -> bool {
- match self.data(Interner).value {
- // interned Unknown
- chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
- interned: ConstScalar::Unknown,
- }) => true,
-
- // interned concrete anything else
- chalk_ir::ConstValue::Concrete(..) => false,
-
- _ => {
- tracing::error!(
- "is_unknown was called on a non-concrete constant value! {:?}",
- self
- );
- true
- }
- }
- }
+pub fn unknown_const_as_generic<'db>(ty: Ty<'db>) -> GenericArg<'db> {
+ unknown_const(ty).into()
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ConstEvalError {
- MirLowerError(MirLowerError),
- MirEvalError(MirEvalError),
+pub enum ConstEvalError<'db> {
+ MirLowerError(MirLowerError<'db>),
+ MirEvalError(MirEvalError<'db>),
}
-impl ConstEvalError {
+impl ConstEvalError<'_> {
pub fn pretty_print(
&self,
f: &mut String,
@@ -74,8 +61,8 @@ impl ConstEvalError {
}
}
-impl From<MirLowerError> for ConstEvalError {
- fn from(value: MirLowerError) -> Self {
+impl<'db> From<MirLowerError<'db>> for ConstEvalError<'db> {
+ fn from(value: MirLowerError<'db>) -> Self {
match value {
MirLowerError::ConstEvalError(_, e) => *e,
_ => ConstEvalError::MirLowerError(value),
@@ -83,201 +70,118 @@ impl From<MirLowerError> for ConstEvalError {
}
}
-impl From<MirEvalError> for ConstEvalError {
- fn from(value: MirEvalError) -> Self {
+impl<'db> From<MirEvalError<'db>> for ConstEvalError<'db> {
+ fn from(value: MirEvalError<'db>) -> Self {
ConstEvalError::MirEvalError(value)
}
}
-pub(crate) fn path_to_const<'g>(
- db: &dyn HirDatabase,
- resolver: &Resolver<'_>,
- path: &Path,
- mode: ParamLoweringMode,
- args: impl FnOnce() -> &'g Generics,
- debruijn: DebruijnIndex,
- expected_ty: Ty,
-) -> Option<Const> {
- match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
- Some(ValueNs::GenericParam(p)) => {
- let ty = db.const_param_ty(p);
- let value = match mode {
- ParamLoweringMode::Placeholder => {
- ConstValue::Placeholder(to_placeholder_idx(db, p.into()))
- }
- ParamLoweringMode::Variable => {
- let args = args();
- match args.type_or_const_param_idx(p.into()) {
- Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
- None => {
- never!(
- "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
- args,
- path,
- p
- );
- return None;
- }
- }
- }
- };
- Some(ConstData { ty, value }.intern(Interner))
- }
- Some(ValueNs::ConstId(c)) => Some(intern_const_scalar(
- ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
- expected_ty,
- )),
- // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors.
- _ => None,
- }
-}
-
-pub fn unknown_const(ty: Ty) -> Const {
- ConstData {
- ty,
- value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }),
- }
- .intern(Interner)
-}
-
-pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
- unknown_const(ty).cast(Interner)
-}
-
/// Interns a constant scalar with the given type
-pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const {
- ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) }
- .intern(Interner)
-}
-
-/// Interns a constant scalar with the given type
-pub fn intern_const_ref(
- db: &dyn HirDatabase,
+pub fn intern_const_ref<'a>(
+ db: &'a dyn HirDatabase,
value: &LiteralConstRef,
- ty: Ty,
+ ty: Ty<'a>,
krate: Crate,
-) -> Const {
- let layout = || db.layout_of_ty(ty.clone(), TraitEnvironment::empty(krate));
- let bytes = match value {
+) -> Const<'a> {
+ let interner = DbInterner::new_with(db, Some(krate), None);
+ let layout = db.layout_of_ty(ty, TraitEnvironment::empty(krate));
+ let kind = match value {
LiteralConstRef::Int(i) => {
// FIXME: We should handle failure of layout better.
- let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
- ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
+ let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
+ rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes {
+ memory: i.to_le_bytes()[0..size].into(),
+ memory_map: MemoryMap::default(),
+ },
+ ))
}
LiteralConstRef::UInt(i) => {
- let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16);
- ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default())
- }
- LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()),
- LiteralConstRef::Char(c) => {
- ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default())
+ let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
+ rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes {
+ memory: i.to_le_bytes()[0..size].into(),
+ memory_map: MemoryMap::default(),
+ },
+ ))
}
- LiteralConstRef::Unknown => ConstScalar::Unknown,
+ LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() },
+ )),
+ LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new(
+ ty,
+ ConstBytes {
+ memory: (*c as u32).to_le_bytes().into(),
+ memory_map: MemoryMap::default(),
+ },
+ )),
+ LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
};
- intern_const_scalar(bytes, ty)
+ Const::new(interner, kind)
}
/// Interns a possibly-unknown target usize
-pub fn usize_const(db: &dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const {
+pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const<'db> {
intern_const_ref(
db,
&value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt),
- TyBuilder::usize(),
+ Ty::new_uint(DbInterner::new_with(db, Some(krate), None), rustc_type_ir::UintTy::Usize),
krate,
)
}
-pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
- match &c.data(Interner).value {
- chalk_ir::ConstValue::BoundVar(_) => None,
- chalk_ir::ConstValue::InferenceVar(_) => None,
- chalk_ir::ConstValue::Placeholder(_) => None,
- chalk_ir::ConstValue::Concrete(c) => match &c.interned {
- ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(it, false))),
- ConstScalar::UnevaluatedConst(c, subst) => {
- let ec = db.const_eval(*c, subst.clone(), None).ok()?;
- try_const_usize(db, &ec)
- }
- _ => None,
- },
- }
-}
-
-pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option<i128> {
- match &c.data(Interner).value {
- chalk_ir::ConstValue::BoundVar(_) => None,
- chalk_ir::ConstValue::InferenceVar(_) => None,
- chalk_ir::ConstValue::Placeholder(_) => None,
- chalk_ir::ConstValue::Concrete(c) => match &c.interned {
- ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))),
- ConstScalar::UnevaluatedConst(c, subst) => {
- let ec = db.const_eval(*c, subst.clone(), None).ok()?;
- try_const_isize(db, &ec)
- }
- _ => None,
- },
+pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u128> {
+ match c.kind() {
+ ConstKind::Param(_) => None,
+ ConstKind::Infer(_) => None,
+ ConstKind::Bound(_, _) => None,
+ ConstKind::Placeholder(_) => None,
+ ConstKind::Unevaluated(unevaluated_const) => {
+ let c = match unevaluated_const.def {
+ SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
+ SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
+ _ => unreachable!(),
+ };
+ let subst = unevaluated_const.args;
+ let ec = db.const_eval(c, subst, None).ok()?;
+ try_const_usize(db, ec)
+ }
+ ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))),
+ ConstKind::Error(_) => None,
+ ConstKind::Expr(_) => None,
}
}
-pub(crate) fn const_eval_cycle_result(
- _: &dyn HirDatabase,
- _: GeneralConstId,
- _: Substitution,
- _: Option<Arc<TraitEnvironment>>,
-) -> Result<Const, ConstEvalError> {
- Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
-}
-
-pub(crate) fn const_eval_static_cycle_result(
- _: &dyn HirDatabase,
- _: StaticId,
-) -> Result<Const, ConstEvalError> {
- Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
-}
-
-pub(crate) fn const_eval_discriminant_cycle_result(
- _: &dyn HirDatabase,
- _: EnumVariantId,
-) -> Result<i128, ConstEvalError> {
- Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
-}
-
-pub(crate) fn const_eval_query(
- db: &dyn HirDatabase,
- def: GeneralConstId,
- subst: Substitution,
- trait_env: Option<Arc<TraitEnvironment>>,
-) -> Result<Const, ConstEvalError> {
- let body = match def {
- GeneralConstId::ConstId(c) => {
- db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))?
- }
- GeneralConstId::StaticId(s) => {
- let krate = s.module(db).krate();
- db.monomorphized_mir_body(s.into(), subst, TraitEnvironment::empty(krate))?
+pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option<i128> {
+ match (*c).kind() {
+ ConstKind::Param(_) => None,
+ ConstKind::Infer(_) => None,
+ ConstKind::Bound(_, _) => None,
+ ConstKind::Placeholder(_) => None,
+ ConstKind::Unevaluated(unevaluated_const) => {
+ let c = match unevaluated_const.def {
+ SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
+ SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
+ _ => unreachable!(),
+ };
+ let subst = unevaluated_const.args;
+ let ec = db.const_eval(c, subst, None).ok()?;
+ try_const_isize(db, &ec)
}
- };
- let c = interpret_mir(db, body, false, trait_env)?.0?;
- Ok(c)
-}
-
-pub(crate) fn const_eval_static_query(
- db: &dyn HirDatabase,
- def: StaticId,
-) -> Result<Const, ConstEvalError> {
- let body = db.monomorphized_mir_body(
- def.into(),
- Substitution::empty(Interner),
- db.trait_environment_for_body(def.into()),
- )?;
- let c = interpret_mir(db, body, false, None)?.0?;
- Ok(c)
+ ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))),
+ ConstKind::Error(_) => None,
+ ConstKind::Expr(_) => None,
+ }
}
-pub(crate) fn const_eval_discriminant_variant(
- db: &dyn HirDatabase,
+pub(crate) fn const_eval_discriminant_variant<'db>(
+ db: &'db dyn HirDatabase,
variant_id: EnumVariantId,
-) -> Result<i128, ConstEvalError> {
+) -> Result<i128, ConstEvalError<'db>> {
+ let interner = DbInterner::new_with(db, None, None);
let def = variant_id.into();
let body = db.body(def);
let loc = variant_id.lookup(db);
@@ -299,14 +203,14 @@ pub(crate) fn const_eval_discriminant_variant(
let mir_body = db.monomorphized_mir_body(
def,
- Substitution::empty(Interner),
+ GenericArgs::new_from_iter(interner, []),
db.trait_environment_for_body(def),
)?;
let c = interpret_mir(db, mir_body, false, None)?.0?;
let c = if is_signed {
try_const_isize(db, &c).unwrap()
} else {
- try_const_usize(db, &c).unwrap() as i128
+ try_const_usize(db, c).unwrap() as i128
};
Ok(c)
}
@@ -314,14 +218,8 @@ pub(crate) fn const_eval_discriminant_variant(
// FIXME: Ideally constants in const eval should have separate body (issue #7434), and this function should
// get an `InferenceResult` instead of an `InferenceContext`. And we should remove `ctx.clone().resolve_all()` here
// and make this function private. See the fixme comment on `InferenceContext::resolve_all`.
-pub(crate) fn eval_to_const(
- expr: ExprId,
- mode: ParamLoweringMode,
- ctx: &mut InferenceContext<'_>,
- debruijn: DebruijnIndex,
-) -> Const {
- let db = ctx.db;
- let infer = ctx.clone().resolve_all();
+pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'db>) -> Const<'db> {
+ let infer = ctx.fixme_resolve_all_clone();
fn has_closure(body: &Body, expr: ExprId) -> bool {
if matches!(body[expr], Expr::Closure { .. }) {
return true;
@@ -332,23 +230,80 @@ pub(crate) fn eval_to_const(
}
if has_closure(ctx.body, expr) {
// Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic.
- return unknown_const(infer[expr].clone());
+ return unknown_const(infer[expr]);
}
if let Expr::Path(p) = &ctx.body[expr] {
- let resolver = &ctx.resolver;
- if let Some(c) =
- path_to_const(db, resolver, p, mode, || ctx.generics(), debruijn, infer[expr].clone())
- {
+ let mut ctx = TyLoweringContext::new(
+ ctx.db,
+ &ctx.resolver,
+ ctx.body,
+ ctx.generic_def,
+ LifetimeElisionKind::Infer,
+ );
+ if let Some(c) = ctx.path_to_const(p) {
return c;
}
}
- if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) {
- if let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None) {
- return result;
- }
+ if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr)
+ && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None)
+ {
+ return result;
}
- unknown_const(infer[expr].clone())
+ unknown_const(infer[expr])
}
-#[cfg(test)]
-mod tests;
+pub(crate) fn const_eval_cycle_result<'db>(
+ _: &'db dyn HirDatabase,
+ _: GeneralConstId,
+ _: GenericArgs<'db>,
+ _: Option<Arc<TraitEnvironment<'db>>>,
+) -> Result<Const<'db>, ConstEvalError<'db>> {
+ Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
+}
+
+pub(crate) fn const_eval_static_cycle_result<'db>(
+ _: &'db dyn HirDatabase,
+ _: StaticId,
+) -> Result<Const<'db>, ConstEvalError<'db>> {
+ Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
+}
+
+pub(crate) fn const_eval_discriminant_cycle_result<'db>(
+ _: &'db dyn HirDatabase,
+ _: EnumVariantId,
+) -> Result<i128, ConstEvalError<'db>> {
+ Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
+}
+
+pub(crate) fn const_eval_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: GeneralConstId,
+ subst: GenericArgs<'db>,
+ trait_env: Option<Arc<TraitEnvironment<'db>>>,
+) -> Result<Const<'db>, ConstEvalError<'db>> {
+ let body = match def {
+ GeneralConstId::ConstId(c) => {
+ db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))?
+ }
+ GeneralConstId::StaticId(s) => {
+ let krate = s.module(db).krate();
+ db.monomorphized_mir_body(s.into(), subst, TraitEnvironment::empty(krate))?
+ }
+ };
+ let c = interpret_mir(db, body, false, trait_env)?.0?;
+ Ok(c)
+}
+
+pub(crate) fn const_eval_static_query<'db>(
+ db: &'db dyn HirDatabase,
+ def: StaticId,
+) -> Result<Const<'db>, ConstEvalError<'db>> {
+ let interner = DbInterner::new_with(db, None, None);
+ let body = db.monomorphized_mir_body(
+ def.into(),
+ GenericArgs::new_from_iter(interner, []),
+ db.trait_environment_for_body(def.into()),
+ )?;
+ let c = interpret_mir(db, body, false, None)?.0?;
+ Ok(c)
+}