Merge pull request #20814 from ChayimFriedman2/mir-ns
internal: Migrate MIR to next solver
This commit is contained in:
commit
bfb0892525
53 changed files with 2505 additions and 2516 deletions
|
|
@ -788,6 +788,7 @@ dependencies = [
|
|||
"intern",
|
||||
"itertools",
|
||||
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"macros",
|
||||
"oorandom",
|
||||
"petgraph",
|
||||
"project-model",
|
||||
|
|
@ -1329,6 +1330,16 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mbe"
|
||||
version = "0.0.0"
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ debug = 2
|
|||
|
||||
[workspace.dependencies]
|
||||
# local crates
|
||||
macros = { path = "./crates/macros", version = "0.0.0" }
|
||||
base-db = { path = "./crates/base-db", version = "0.0.0" }
|
||||
cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] }
|
||||
hir = { path = "./crates/hir", version = "0.0.0" }
|
||||
|
|
|
|||
|
|
@ -349,6 +349,7 @@ bitflags::bitflags! {
|
|||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||
pub struct ImplFlags: u8 {
|
||||
const NEGATIVE = 1 << 1;
|
||||
const DEFAULT = 1 << 2;
|
||||
const UNSAFE = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
|
@ -374,6 +375,9 @@ impl ImplSignature {
|
|||
if src.value.excl_token().is_some() {
|
||||
flags.insert(ImplFlags::NEGATIVE);
|
||||
}
|
||||
if src.value.default_token().is_some() {
|
||||
flags.insert(ImplFlags::DEFAULT);
|
||||
}
|
||||
|
||||
let (store, source_map, self_ty, target_trait, generic_params) =
|
||||
crate::expr_store::lower::lower_impl(db, loc.container, src, id);
|
||||
|
|
@ -389,6 +393,16 @@ impl ImplSignature {
|
|||
Arc::new(source_map),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_negative(&self) -> bool {
|
||||
self.flags.contains(ImplFlags::NEGATIVE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_default(&self) -> bool {
|
||||
self.flags.contains(ImplFlags::DEFAULT)
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ tracing-tree.workspace = true
|
|||
|
||||
# local deps
|
||||
stdx.workspace = true
|
||||
macros.workspace = true
|
||||
intern.workspace = true
|
||||
hir-def.workspace = true
|
||||
hir-expand.workspace = true
|
||||
|
|
|
|||
|
|
@ -130,11 +130,14 @@ impl<D> TyBuilder<D> {
|
|||
}
|
||||
|
||||
pub fn fill_with_unknown(self) -> Self {
|
||||
let interner = DbInterner::conjure();
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
|
||||
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||
ParamKind::Const(ty) => {
|
||||
unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
|
||||
}
|
||||
ParamKind::Lifetime => error_lifetime().cast(Interner),
|
||||
});
|
||||
this.vec.extend(filler.casted(Interner));
|
||||
|
|
@ -219,13 +222,16 @@ impl TyBuilder<()> {
|
|||
}
|
||||
|
||||
pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
|
||||
let interner = DbInterner::conjure();
|
||||
let params = generics(db, def.into());
|
||||
Substitution::from_iter(
|
||||
Interner,
|
||||
params.iter_id().map(|id| match id {
|
||||
GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
|
||||
GenericParamId::ConstParamId(id) => {
|
||||
unknown_const_as_generic(db.const_param_ty(id)).cast(Interner)
|
||||
unknown_const_as_generic(db.const_param_ty_ns(id))
|
||||
.to_chalk(interner)
|
||||
.cast(Interner)
|
||||
}
|
||||
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
|
||||
}),
|
||||
|
|
@ -267,6 +273,7 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
db: &dyn HirDatabase,
|
||||
mut fallback: impl FnMut() -> Ty,
|
||||
) -> Self {
|
||||
let interner = DbInterner::conjure();
|
||||
// Note that we're building ADT, so we never have parent generic parameters.
|
||||
let defaults = db.generic_defaults(self.data.into());
|
||||
|
||||
|
|
@ -287,7 +294,9 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
// The defaults may be missing if no param has default, so fill that.
|
||||
let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x {
|
||||
ParamKind::Type => fallback().cast(Interner),
|
||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||
ParamKind::Const(ty) => {
|
||||
unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner)
|
||||
}
|
||||
ParamKind::Lifetime => error_lifetime().cast(Interner),
|
||||
});
|
||||
self.vec.extend(filler.casted(Interner));
|
||||
|
|
|
|||
|
|
@ -1,59 +1,88 @@
|
|||
//! 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::{HygieneId, path::Path},
|
||||
hir::Expr,
|
||||
EnumVariantId, GeneralConstId,
|
||||
expr_store::{Body, HygieneId, path::Path},
|
||||
hir::{Expr, ExprId},
|
||||
resolver::{Resolver, ValueNs},
|
||||
type_ref::LiteralConstRef,
|
||||
};
|
||||
use hir_def::{HasModule, StaticId};
|
||||
use hir_expand::Lookup;
|
||||
use rustc_type_ir::{UnevaluatedConst, inherent::IntoKind};
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution,
|
||||
TraitEnvironment, Ty, TyBuilder,
|
||||
MemoryMap, TraitEnvironment,
|
||||
db::HirDatabase,
|
||||
display::DisplayTarget,
|
||||
generics::Generics,
|
||||
lower::ParamLoweringMode,
|
||||
next_solver::{DbInterner, mapping::ChalkToNextSolver},
|
||||
to_placeholder_idx,
|
||||
infer::InferenceContext,
|
||||
mir::{MirEvalError, MirLowerError},
|
||||
next_solver::{
|
||||
Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
|
||||
ParamConst, SolverDefId, Ty, ValueConst,
|
||||
},
|
||||
};
|
||||
|
||||
use super::mir::{MirEvalError, MirLowerError, interpret_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;
|
||||
}
|
||||
|
||||
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(crate) fn path_to_const<'a, 'g>(
|
||||
db: &'a dyn HirDatabase,
|
||||
resolver: &Resolver<'a>,
|
||||
path: &Path,
|
||||
args: impl FnOnce() -> &'g Generics,
|
||||
_expected_ty: Ty<'a>,
|
||||
) -> Option<Const<'a>> {
|
||||
let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
|
||||
match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
|
||||
Some(ValueNs::GenericParam(p)) => {
|
||||
let args = args();
|
||||
match args
|
||||
.type_or_const_param(p.into())
|
||||
.and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone())))
|
||||
{
|
||||
Some((idx, _param)) => {
|
||||
Some(Const::new_param(interner, ParamConst { index: idx as u32, id: p }))
|
||||
}
|
||||
None => {
|
||||
never!(
|
||||
"Generic list doesn't contain this param: {:?}, {:?}, {:?}",
|
||||
args,
|
||||
path,
|
||||
p
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ValueNs::ConstId(c)) => {
|
||||
let args = GenericArgs::new_from_iter(interner, []);
|
||||
Some(Const::new(
|
||||
interner,
|
||||
rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
|
||||
SolverDefId::ConstId(c),
|
||||
args,
|
||||
)),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> {
|
||||
Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
|
||||
}
|
||||
|
||||
pub fn unknown_const_as_generic<'db>(ty: Ty<'db>) -> GenericArg<'db> {
|
||||
unknown_const(ty).into()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ConstEvalError<'db> {
|
||||
MirLowerError(MirLowerError<'db>),
|
||||
|
|
@ -94,195 +123,112 @@ impl<'db> From<MirEvalError<'db>> for ConstEvalError<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
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 args = args();
|
||||
let value = match mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
let idx = args.type_or_const_param_idx(p.into()).unwrap();
|
||||
ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32))
|
||||
}
|
||||
ParamLoweringMode::Variable => 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 {
|
||||
) -> Const<'a> {
|
||||
let interner = DbInterner::new_with(db, Some(krate), None);
|
||||
let layout = || db.layout_of_ty(ty.to_nextsolver(interner), TraitEnvironment::empty(krate));
|
||||
let bytes = match value {
|
||||
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())
|
||||
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::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())
|
||||
}
|
||||
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_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 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_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)
|
||||
}
|
||||
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_cycle_result<'db>(
|
||||
_: &'db dyn HirDatabase,
|
||||
_: GeneralConstId,
|
||||
_: Substitution,
|
||||
_: Option<Arc<TraitEnvironment<'db>>>,
|
||||
) -> Result<Const, ConstEvalError<'db>> {
|
||||
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_static_cycle_result<'db>(
|
||||
_: &'db dyn HirDatabase,
|
||||
_: StaticId,
|
||||
) -> Result<Const, 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: Substitution,
|
||||
trait_env: Option<Arc<TraitEnvironment<'db>>>,
|
||||
) -> Result<Const, 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, ConstEvalError<'db>> {
|
||||
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)
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_discriminant_variant<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
variant_id: EnumVariantId,
|
||||
) -> 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);
|
||||
|
|
@ -304,17 +250,101 @@ pub(crate) fn const_eval_discriminant_variant<'db>(
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
// 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<'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;
|
||||
}
|
||||
let mut r = false;
|
||||
body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx));
|
||||
r
|
||||
}
|
||||
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]);
|
||||
}
|
||||
if let Expr::Path(p) = &ctx.body[expr] {
|
||||
let resolver = &ctx.resolver;
|
||||
if let Some(c) = path_to_const(ctx.db, resolver, p, || ctx.generics(), infer[expr]) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
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])
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
use base_db::RootQueryDb;
|
||||
use chalk_ir::Substitution;
|
||||
use hir_def::db::DefDatabase;
|
||||
use hir_expand::EditionedFileId;
|
||||
use rustc_apfloat::{
|
||||
Float,
|
||||
ieee::{Half as f16, Quad as f128},
|
||||
};
|
||||
use rustc_type_ir::inherent::IntoKind;
|
||||
use test_fixture::WithFixture;
|
||||
use test_utils::skip_slow_tests;
|
||||
|
||||
use crate::{
|
||||
Const, ConstScalar, Interner, MemoryMap, consteval::try_const_usize, db::HirDatabase,
|
||||
display::DisplayTarget, mir::pad16, setup_tracing, test_db::TestDB,
|
||||
MemoryMap,
|
||||
consteval::try_const_usize,
|
||||
db::HirDatabase,
|
||||
display::DisplayTarget,
|
||||
mir::pad16,
|
||||
next_solver::{Const, ConstBytes, ConstKind, DbInterner, GenericArgs},
|
||||
setup_tracing,
|
||||
test_db::TestDB,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -88,14 +94,12 @@ fn check_answer(
|
|||
panic!("Error in evaluating goal: {err}");
|
||||
}
|
||||
};
|
||||
match &r.data(Interner).value {
|
||||
chalk_ir::ConstValue::Concrete(c) => match &c.interned {
|
||||
ConstScalar::Bytes(b, mm) => {
|
||||
check(b, mm);
|
||||
}
|
||||
x => panic!("Expected number but found {x:?}"),
|
||||
},
|
||||
_ => panic!("result of const eval wasn't a concrete const"),
|
||||
match r.kind() {
|
||||
ConstKind::Value(value) => {
|
||||
let ConstBytes { memory, memory_map } = value.value.inner();
|
||||
check(memory, memory_map);
|
||||
}
|
||||
_ => panic!("Expected number but found {r:?}"),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -117,8 +121,9 @@ fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String {
|
|||
err
|
||||
}
|
||||
|
||||
fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const, ConstEvalError<'_>> {
|
||||
fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const<'_>, ConstEvalError<'_>> {
|
||||
let _tracing = setup_tracing();
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let module_id = db.module_for_file(file_id.file_id(db));
|
||||
let def_map = module_id.def_map(db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
|
|
@ -137,7 +142,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result<Const, ConstEvalEr
|
|||
_ => None,
|
||||
})
|
||||
.expect("No const named GOAL found in the test");
|
||||
db.const_eval(const_id.into(), Substitution::empty(Interner), None)
|
||||
db.const_eval(const_id.into(), GenericArgs::new_from_iter(interner, []), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2508,7 +2513,7 @@ fn enums() {
|
|||
);
|
||||
crate::attach_db(&db, || {
|
||||
let r = eval_goal(&db, file_id).unwrap();
|
||||
assert_eq!(try_const_usize(&db, &r), Some(1));
|
||||
assert_eq!(try_const_usize(&db, r), Some(1));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
185
src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs
Normal file
185
src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
//! Constant evaluation details
|
||||
|
||||
use base_db::Crate;
|
||||
use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast};
|
||||
use hir_def::{
|
||||
expr_store::{HygieneId, path::Path},
|
||||
resolver::{Resolver, ValueNs},
|
||||
type_ref::LiteralConstRef,
|
||||
};
|
||||
use stdx::never;
|
||||
|
||||
use crate::{
|
||||
Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution,
|
||||
TraitEnvironment, Ty, TyBuilder,
|
||||
db::HirDatabase,
|
||||
generics::Generics,
|
||||
lower::ParamLoweringMode,
|
||||
next_solver::{
|
||||
DbInterner,
|
||||
mapping::{ChalkToNextSolver, NextSolverToChalk},
|
||||
},
|
||||
to_placeholder_idx,
|
||||
};
|
||||
|
||||
use super::mir::pad16;
|
||||
|
||||
/// Extension trait for [`Const`]
|
||||
pub trait ConstExt {
|
||||
/// Is a [`Const`] unknown?
|
||||
fn is_unknown(&self) -> bool;
|
||||
}
|
||||
|
||||
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 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 args = args();
|
||||
let value = match mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
let idx = args.type_or_const_param_idx(p.into()).unwrap();
|
||||
ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32))
|
||||
}
|
||||
ParamLoweringMode::Variable => 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,
|
||||
value: &LiteralConstRef,
|
||||
ty: Ty,
|
||||
krate: Crate,
|
||||
) -> Const {
|
||||
let interner = DbInterner::new_with(db, Some(krate), None);
|
||||
let layout = || db.layout_of_ty(ty.to_nextsolver(interner), TraitEnvironment::empty(krate));
|
||||
let bytes = 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())
|
||||
}
|
||||
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())
|
||||
}
|
||||
LiteralConstRef::Unknown => ConstScalar::Unknown,
|
||||
};
|
||||
intern_const_scalar(bytes, ty)
|
||||
}
|
||||
|
||||
/// Interns a possibly-unknown target usize
|
||||
pub fn usize_const(db: &dyn HirDatabase, value: Option<u128>, krate: Crate) -> Const {
|
||||
intern_const_ref(
|
||||
db,
|
||||
&value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt),
|
||||
TyBuilder::usize(),
|
||||
krate,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
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.to_nextsolver(interner), None).ok()?;
|
||||
try_const_usize(db, &ec.to_chalk(interner))
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option<i128> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
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.to_nextsolver(interner), None).ok()?;
|
||||
try_const_isize(db, &ec.to_chalk(interner))
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
//! Constant evaluation details
|
||||
// FIXME(next-solver): this should get removed as things get moved to rustc_type_ir from chalk_ir
|
||||
#![allow(unused)]
|
||||
|
||||
use base_db::Crate;
|
||||
use hir_def::{
|
||||
EnumVariantId, GeneralConstId,
|
||||
expr_store::{Body, HygieneId, path::Path},
|
||||
hir::{Expr, ExprId},
|
||||
resolver::{Resolver, ValueNs},
|
||||
type_ref::LiteralConstRef,
|
||||
};
|
||||
use hir_expand::Lookup;
|
||||
use rustc_type_ir::{
|
||||
UnevaluatedConst,
|
||||
inherent::{IntoKind, SliceLike},
|
||||
};
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
ConstScalar, Interner, MemoryMap, Substitution, TraitEnvironment,
|
||||
consteval::ConstEvalError,
|
||||
db::HirDatabase,
|
||||
generics::Generics,
|
||||
infer::InferenceContext,
|
||||
next_solver::{
|
||||
Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
|
||||
ParamConst, SolverDefId, Ty, ValueConst,
|
||||
mapping::{ChalkToNextSolver, NextSolverToChalk, convert_binder_to_early_binder},
|
||||
},
|
||||
};
|
||||
|
||||
use super::mir::{interpret_mir, lower_to_mir, pad16};
|
||||
|
||||
pub(crate) fn path_to_const<'a, 'g>(
|
||||
db: &'a dyn HirDatabase,
|
||||
resolver: &Resolver<'a>,
|
||||
path: &Path,
|
||||
args: impl FnOnce() -> &'g Generics,
|
||||
expected_ty: Ty<'a>,
|
||||
) -> Option<Const<'a>> {
|
||||
let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
|
||||
match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) {
|
||||
Some(ValueNs::GenericParam(p)) => {
|
||||
let args = args();
|
||||
match args
|
||||
.type_or_const_param(p.into())
|
||||
.and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone())))
|
||||
{
|
||||
Some((idx, _param)) => {
|
||||
Some(Const::new_param(interner, ParamConst { index: idx as u32, id: p }))
|
||||
}
|
||||
None => {
|
||||
never!(
|
||||
"Generic list doesn't contain this param: {:?}, {:?}, {:?}",
|
||||
args,
|
||||
path,
|
||||
p
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ValueNs::ConstId(c)) => {
|
||||
let args = GenericArgs::new_from_iter(interner, []);
|
||||
Some(Const::new(
|
||||
interner,
|
||||
rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(
|
||||
SolverDefId::ConstId(c),
|
||||
args,
|
||||
)),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unknown_const<'db>(ty: Ty<'db>) -> Const<'db> {
|
||||
Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed))
|
||||
}
|
||||
|
||||
pub fn unknown_const_as_generic<'db>(ty: Ty<'db>) -> GenericArg<'db> {
|
||||
unknown_const(ty).into()
|
||||
}
|
||||
|
||||
/// Interns a constant scalar with the given type
|
||||
pub fn intern_const_ref<'a>(
|
||||
db: &'a dyn HirDatabase,
|
||||
value: &LiteralConstRef,
|
||||
ty: Ty<'a>,
|
||||
krate: Crate,
|
||||
) -> 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);
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()),
|
||||
))
|
||||
}
|
||||
LiteralConstRef::UInt(i) => {
|
||||
let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16);
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()),
|
||||
))
|
||||
}
|
||||
LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes(Box::new([*b as u8]), MemoryMap::default()),
|
||||
)),
|
||||
LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
ty,
|
||||
ConstBytes((*c as u32).to_le_bytes().into(), MemoryMap::default()),
|
||||
)),
|
||||
LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed),
|
||||
};
|
||||
Const::new(interner, kind)
|
||||
}
|
||||
|
||||
/// Interns a possibly-unknown target usize
|
||||
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),
|
||||
Ty::new_uint(DbInterner::new_with(db, Some(krate), None), rustc_type_ir::UintTy::Usize),
|
||||
krate,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u128> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
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.to_chalk(interner);
|
||||
let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner);
|
||||
try_const_usize(db, ec)
|
||||
}
|
||||
ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().0, false))),
|
||||
ConstKind::Error(_) => None,
|
||||
ConstKind::Expr(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option<i128> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
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.to_chalk(interner);
|
||||
let ec = db.const_eval(c, subst, None).ok()?.to_nextsolver(interner);
|
||||
try_const_isize(db, &ec)
|
||||
}
|
||||
ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().0, true))),
|
||||
ConstKind::Error(_) => None,
|
||||
ConstKind::Expr(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_discriminant_variant<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
variant_id: EnumVariantId,
|
||||
) -> 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);
|
||||
if matches!(body[body.body_expr], Expr::Missing) {
|
||||
let prev_idx = loc.index.checked_sub(1);
|
||||
let value = match prev_idx {
|
||||
Some(prev_idx) => {
|
||||
1 + db.const_eval_discriminant(
|
||||
loc.parent.enum_variants(db).variants[prev_idx as usize].0,
|
||||
)?
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
let repr = db.enum_signature(loc.parent).repr;
|
||||
let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed());
|
||||
|
||||
let mir_body = db.monomorphized_mir_body(
|
||||
def,
|
||||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def),
|
||||
)?;
|
||||
let c = interpret_mir(db, mir_body, false, None)?.0?;
|
||||
let c = c.to_nextsolver(interner);
|
||||
let c = if is_signed {
|
||||
try_const_isize(db, &c).unwrap()
|
||||
} else {
|
||||
try_const_usize(db, c).unwrap() as i128
|
||||
};
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
// 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<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'db>) -> Const<'db> {
|
||||
let interner = DbInterner::new_with(ctx.db, None, None);
|
||||
let infer = ctx.fixme_resolve_all_clone();
|
||||
fn has_closure(body: &Body, expr: ExprId) -> bool {
|
||||
if matches!(body[expr], Expr::Closure { .. }) {
|
||||
return true;
|
||||
}
|
||||
let mut r = false;
|
||||
body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx));
|
||||
r
|
||||
}
|
||||
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]);
|
||||
}
|
||||
if let Expr::Path(p) = &ctx.body[expr] {
|
||||
let resolver = &ctx.resolver;
|
||||
if let Some(c) = path_to_const(ctx.db, resolver, p, || ctx.generics(), infer[expr]) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
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.to_nextsolver(interner);
|
||||
}
|
||||
unknown_const(infer[expr])
|
||||
}
|
||||
|
|
@ -16,8 +16,8 @@ use smallvec::SmallVec;
|
|||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty,
|
||||
TyDefId, ValueTyDefId, chalk_db,
|
||||
Binders, ImplTraitId, ImplTraits, InferenceResult, TraitEnvironment, Ty, TyDefId, ValueTyDefId,
|
||||
chalk_db,
|
||||
consteval::ConstEvalError,
|
||||
dyn_compatibility::DynCompatibilityViolation,
|
||||
layout::{Layout, LayoutError},
|
||||
|
|
@ -37,50 +37,56 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
|
|||
|
||||
#[salsa::invoke(crate::mir::mir_body_query)]
|
||||
#[salsa::cycle(cycle_result = crate::mir::mir_body_cycle_result)]
|
||||
fn mir_body<'db>(&'db self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError<'db>>;
|
||||
fn mir_body<'db>(
|
||||
&'db self,
|
||||
def: DefWithBodyId,
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::mir::mir_body_for_closure_query)]
|
||||
fn mir_body_for_closure<'db>(
|
||||
&'db self,
|
||||
def: InternedClosureId,
|
||||
) -> Result<Arc<MirBody>, MirLowerError<'db>>;
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::mir::monomorphized_mir_body_query)]
|
||||
#[salsa::cycle(cycle_result = crate::mir::monomorphized_mir_body_cycle_result)]
|
||||
fn monomorphized_mir_body<'db>(
|
||||
&'db self,
|
||||
def: DefWithBodyId,
|
||||
subst: Substitution,
|
||||
subst: crate::next_solver::GenericArgs<'db>,
|
||||
env: Arc<TraitEnvironment<'db>>,
|
||||
) -> Result<Arc<MirBody>, MirLowerError<'db>>;
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)]
|
||||
fn monomorphized_mir_body_for_closure<'db>(
|
||||
&'db self,
|
||||
def: InternedClosureId,
|
||||
subst: Substitution,
|
||||
subst: crate::next_solver::GenericArgs<'db>,
|
||||
env: Arc<TraitEnvironment<'db>>,
|
||||
) -> Result<Arc<MirBody>, MirLowerError<'db>>;
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::mir::borrowck_query)]
|
||||
#[salsa::lru(2024)]
|
||||
fn borrowck<'db>(
|
||||
&'db self,
|
||||
def: DefWithBodyId,
|
||||
) -> Result<Arc<[BorrowckResult]>, MirLowerError<'db>>;
|
||||
) -> Result<Arc<[BorrowckResult<'db>]>, MirLowerError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||
#[salsa::cycle(cycle_result = crate::consteval::const_eval_cycle_result)]
|
||||
fn const_eval<'db>(
|
||||
&'db self,
|
||||
def: GeneralConstId,
|
||||
subst: Substitution,
|
||||
subst: crate::next_solver::GenericArgs<'db>,
|
||||
trait_env: Option<Arc<TraitEnvironment<'db>>>,
|
||||
) -> Result<Const, ConstEvalError<'db>>;
|
||||
) -> Result<crate::next_solver::Const<'db>, ConstEvalError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_static_query)]
|
||||
#[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)]
|
||||
fn const_eval_static<'db>(&'db self, def: StaticId) -> Result<Const, ConstEvalError<'db>>;
|
||||
fn const_eval_static<'db>(
|
||||
&'db self,
|
||||
def: StaticId,
|
||||
) -> Result<crate::next_solver::Const<'db>, ConstEvalError<'db>>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_discriminant_variant)]
|
||||
#[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)]
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ use crate::{
|
|||
AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar,
|
||||
ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
|
||||
LifetimeOutlives, MemoryMap, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
|
||||
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval_nextsolver,
|
||||
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval,
|
||||
db::{HirDatabase, InternedClosure},
|
||||
from_assoc_type_id, from_placeholder_idx,
|
||||
generics::generics,
|
||||
|
|
@ -750,8 +750,8 @@ impl<'db> HirDisplay for crate::next_solver::Const<'db> {
|
|||
}
|
||||
rustc_type_ir::ConstKind::Value(const_bytes) => render_const_scalar_ns(
|
||||
f,
|
||||
&const_bytes.value.inner().0,
|
||||
&const_bytes.value.inner().1,
|
||||
&const_bytes.value.inner().memory,
|
||||
&const_bytes.value.inner().memory_map,
|
||||
const_bytes.ty,
|
||||
),
|
||||
rustc_type_ir::ConstKind::Unevaluated(unev) => {
|
||||
|
|
@ -1025,7 +1025,7 @@ fn render_const_scalar_inner<'db>(
|
|||
ty.hir_fmt(f)
|
||||
}
|
||||
TyKind::Array(ty, len) => {
|
||||
let Some(len) = consteval_nextsolver::try_const_usize(f.db, len) else {
|
||||
let Some(len) = consteval::try_const_usize(f.db, len) else {
|
||||
return f.write_str("<unknown-array-len>");
|
||||
};
|
||||
let Ok(layout) = f.db.layout_of_ty(ty, trait_env) else {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use stdx::never;
|
|||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
TraitEnvironment, consteval_nextsolver,
|
||||
TraitEnvironment, consteval,
|
||||
db::HirDatabase,
|
||||
method_resolution::TyFingerprint,
|
||||
next_solver::{
|
||||
|
|
@ -128,7 +128,7 @@ fn has_drop_glue_impl<'db>(
|
|||
.max()
|
||||
.unwrap_or(DropGlue::None),
|
||||
TyKind::Array(ty, len) => {
|
||||
if consteval_nextsolver::try_const_usize(db, len) == Some(0) {
|
||||
if consteval::try_const_usize(db, len) == Some(0) {
|
||||
// Arrays of size 0 don't have drop glue.
|
||||
return DropGlue::None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@ use crate::{
|
|||
db::{HirDatabase, InternedClosure, InternedClosureId},
|
||||
infer::InferenceContext,
|
||||
mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
|
||||
next_solver::{
|
||||
DbInterner, EarlyBinder, GenericArgs, Ty, TyKind,
|
||||
mapping::{ChalkToNextSolver, NextSolverToChalk},
|
||||
},
|
||||
next_solver::{DbInterner, EarlyBinder, GenericArgs, Ty, TyKind},
|
||||
traits::FnTrait,
|
||||
};
|
||||
|
||||
|
|
@ -47,16 +44,14 @@ impl<'db> HirPlace<'db> {
|
|||
fn ty(&self, ctx: &mut InferenceContext<'_, 'db>) -> Ty<'db> {
|
||||
let mut ty = ctx.table.resolve_completely(ctx.result[self.local]);
|
||||
for p in &self.projections {
|
||||
ty = p
|
||||
.projected_ty(
|
||||
ty.to_chalk(ctx.interner()),
|
||||
ctx.db,
|
||||
|_, _, _| {
|
||||
unreachable!("Closure field only happens in MIR");
|
||||
},
|
||||
ctx.owner.module(ctx.db).krate(),
|
||||
)
|
||||
.to_nextsolver(ctx.interner());
|
||||
ty = p.projected_ty(
|
||||
&ctx.table.infer_ctxt,
|
||||
ty,
|
||||
|_, _, _| {
|
||||
unreachable!("Closure field only happens in MIR");
|
||||
},
|
||||
ctx.owner.module(ctx.db).krate(),
|
||||
);
|
||||
}
|
||||
ty
|
||||
}
|
||||
|
|
@ -865,16 +860,14 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
continue;
|
||||
}
|
||||
for (i, p) in capture.place.projections.iter().enumerate() {
|
||||
ty = p
|
||||
.projected_ty(
|
||||
ty.to_chalk(self.interner()),
|
||||
self.db,
|
||||
|_, _, _| {
|
||||
unreachable!("Closure field only happens in MIR");
|
||||
},
|
||||
self.owner.module(self.db).krate(),
|
||||
)
|
||||
.to_nextsolver(self.interner());
|
||||
ty = p.projected_ty(
|
||||
&self.table.infer_ctxt,
|
||||
ty,
|
||||
|_, _, _| {
|
||||
unreachable!("Closure field only happens in MIR");
|
||||
},
|
||||
self.owner.module(self.db).krate(),
|
||||
);
|
||||
if ty.is_raw_ptr() || ty.is_union() {
|
||||
capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
|
||||
self.truncate_capture_spans(capture, i + 1);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use crate::{
|
|||
Adjust, Adjustment, AutoBorrow, CallableDefId, DeclContext, DeclOrigin,
|
||||
IncorrectGenericsLenKind, Rawness, TraitEnvironment,
|
||||
autoderef::overloaded_deref_ty,
|
||||
consteval_nextsolver,
|
||||
consteval,
|
||||
generics::generics,
|
||||
infer::{
|
||||
AllowTwoPhase, BreakableKind,
|
||||
|
|
@ -896,7 +896,7 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
Literal::ByteString(bs) => {
|
||||
let byte_type = self.types.u8;
|
||||
|
||||
let len = consteval_nextsolver::usize_const(
|
||||
let len = consteval::usize_const(
|
||||
self.db,
|
||||
Some(bs.len() as u128),
|
||||
self.resolver.krate(),
|
||||
|
|
@ -1221,7 +1221,7 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
let expected = Expectation::has_type(elem_ty);
|
||||
let (elem_ty, len) = match array {
|
||||
Array::ElementList { elements, .. } if elements.is_empty() => {
|
||||
(elem_ty, consteval_nextsolver::usize_const(self.db, Some(0), krate))
|
||||
(elem_ty, consteval::usize_const(self.db, Some(0), krate))
|
||||
}
|
||||
Array::ElementList { elements, .. } => {
|
||||
let mut coerce = CoerceMany::with_coercion_sites(elem_ty, elements);
|
||||
|
|
@ -1231,7 +1231,7 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
}
|
||||
(
|
||||
coerce.complete(self),
|
||||
consteval_nextsolver::usize_const(self.db, Some(elements.len() as u128), krate),
|
||||
consteval::usize_const(self.db, Some(elements.len() as u128), krate),
|
||||
)
|
||||
}
|
||||
&Array::Repeat { initializer, repeat } => {
|
||||
|
|
@ -1248,7 +1248,7 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
_ => _ = self.infer_expr(repeat, &Expectation::HasType(usize), ExprIsRead::Yes),
|
||||
}
|
||||
|
||||
(elem_ty, consteval_nextsolver::eval_to_const(repeat, self))
|
||||
(elem_ty, consteval::eval_to_const(repeat, self))
|
||||
}
|
||||
};
|
||||
// Try to evaluate unevaluated constant, and insert variable if is not possible.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use stdx::TupleExt;
|
|||
|
||||
use crate::{
|
||||
DeclContext, DeclOrigin, InferenceDiagnostic,
|
||||
consteval_nextsolver::{self, try_const_usize, usize_const},
|
||||
consteval::{self, try_const_usize, usize_const},
|
||||
infer::{
|
||||
AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch,
|
||||
coerce::CoerceNever, expr::ExprIsRead,
|
||||
|
|
@ -591,11 +591,7 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
}
|
||||
|
||||
let len = before.len() + suffix.len();
|
||||
let size = consteval_nextsolver::usize_const(
|
||||
self.db,
|
||||
Some(len as u128),
|
||||
self.owner.krate(self.db),
|
||||
);
|
||||
let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db));
|
||||
|
||||
let elem_ty = self.table.next_ty_var();
|
||||
let array_ty = Ty::new_array_with_const_len(self.interner(), elem_ty, size);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_type_ir::inherent::{SliceLike, Ty as _};
|
|||
use stdx::never;
|
||||
|
||||
use crate::{
|
||||
InferenceDiagnostic, ValueTyDefId, consteval_nextsolver,
|
||||
InferenceDiagnostic, ValueTyDefId, consteval,
|
||||
generics::generics,
|
||||
infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
|
||||
lower_nextsolver::LifetimeElisionKind,
|
||||
|
|
@ -128,7 +128,7 @@ impl<'db> InferenceContext<'_, 'db> {
|
|||
match id {
|
||||
GenericParamId::TypeParamId(_) => self.types.error.into(),
|
||||
GenericParamId::ConstParamId(id) => {
|
||||
consteval_nextsolver::unknown_const_as_generic(self.db.const_param_ty_ns(id))
|
||||
consteval::unknown_const_as_generic(self.db.const_param_ty_ns(id))
|
||||
}
|
||||
GenericParamId::LifetimeParamId(_) => self.types.re_error.into(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ use triomphe::Arc;
|
|||
|
||||
use crate::{
|
||||
AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind,
|
||||
consteval::try_const_usize, db::HirDatabase,
|
||||
consteval::try_const_usize,
|
||||
db::HirDatabase,
|
||||
next_solver::{DbInterner, mapping::ChalkToNextSolver},
|
||||
};
|
||||
|
||||
// FIXME: Turn this into a query, it can be quite slow
|
||||
|
|
@ -79,14 +81,17 @@ impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
|
|||
}
|
||||
self.recursive_ty.insert(ty.clone());
|
||||
self.max_depth -= 1;
|
||||
let interner = DbInterner::new_with(self.db, None, None);
|
||||
let r = match ty.kind(Interner) {
|
||||
TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
|
||||
TyKind::Never => BREAK_VISIBLY_UNINHABITED,
|
||||
TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
|
||||
TyKind::Array(item_ty, len) => match try_const_usize(self.db, len) {
|
||||
Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
|
||||
Some(1..) => item_ty.super_visit_with(self, outer_binder),
|
||||
},
|
||||
TyKind::Array(item_ty, len) => {
|
||||
match try_const_usize(self.db, len.to_nextsolver(interner)) {
|
||||
Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
|
||||
Some(1..) => item_ty.super_visit_with(self, outer_binder),
|
||||
}
|
||||
}
|
||||
TyKind::Alias(AliasTy::Projection(projection)) => {
|
||||
// FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle
|
||||
// `TyKind::AssociatedType`, but perhaps in the future it will.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use triomphe::Arc;
|
|||
|
||||
use crate::{
|
||||
TraitEnvironment,
|
||||
consteval_nextsolver::try_const_usize,
|
||||
consteval::try_const_usize,
|
||||
db::HirDatabase,
|
||||
next_solver::{
|
||||
DbInterner, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ extern crate ra_ap_rustc_type_ir as rustc_type_ir;
|
|||
|
||||
extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver;
|
||||
|
||||
extern crate self as hir_ty;
|
||||
|
||||
mod builder;
|
||||
mod chalk_db;
|
||||
mod chalk_ext;
|
||||
|
|
@ -37,7 +39,7 @@ mod utils;
|
|||
|
||||
pub mod autoderef;
|
||||
pub mod consteval;
|
||||
pub mod consteval_nextsolver;
|
||||
pub mod consteval_chalk;
|
||||
pub mod db;
|
||||
pub mod diagnostics;
|
||||
pub mod display;
|
||||
|
|
@ -782,7 +784,12 @@ where
|
|||
_var: InferenceVar,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Const> {
|
||||
if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) }
|
||||
if cfg!(debug_assertions) {
|
||||
Err(NoSolution)
|
||||
} else {
|
||||
let interner = DbInterner::conjure();
|
||||
Ok(unknown_const(ty.to_nextsolver(interner)).to_chalk(interner))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fold_free_var_const(
|
||||
|
|
@ -791,7 +798,12 @@ where
|
|||
_bound_var: BoundVar,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Const> {
|
||||
if cfg!(debug_assertions) { Err(NoSolution) } else { Ok(unknown_const(ty)) }
|
||||
if cfg!(debug_assertions) {
|
||||
Err(NoSolution)
|
||||
} else {
|
||||
let interner = DbInterner::conjure();
|
||||
Ok(unknown_const(ty.to_nextsolver(interner)).to_chalk(interner))
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fold_inference_lifetime(
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ use crate::{
|
|||
ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives,
|
||||
QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty,
|
||||
TyBuilder, TyKind, WhereClause, all_super_traits,
|
||||
consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
|
||||
consteval_chalk::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
|
||||
db::HirDatabase,
|
||||
error_lifetime,
|
||||
generics::{Generics, generics, trait_self_param_idx},
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::{
|
|||
Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy,
|
||||
QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind,
|
||||
TyLoweringContext, WhereClause,
|
||||
consteval::{unknown_const, unknown_const_as_generic},
|
||||
consteval_chalk::{unknown_const, unknown_const_as_generic},
|
||||
db::HirDatabase,
|
||||
error_lifetime,
|
||||
generics::{Generics, generics},
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ use crate::next_solver::ParamConst;
|
|||
use crate::{
|
||||
FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic,
|
||||
TyLoweringDiagnosticKind,
|
||||
consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic},
|
||||
consteval::{intern_const_ref, path_to_const, unknown_const_as_generic},
|
||||
db::HirDatabase,
|
||||
generics::{Generics, generics, trait_self_param_idx},
|
||||
lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics},
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use stdx::never;
|
|||
use crate::{
|
||||
GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource,
|
||||
PathLoweringDiagnostic, TyDefId, ValueTyDefId,
|
||||
consteval_nextsolver::{unknown_const, unknown_const_as_generic},
|
||||
consteval::{unknown_const, unknown_const_as_generic},
|
||||
db::HirDatabase,
|
||||
generics::{Generics, generics},
|
||||
lower::PathDiagnosticCallbackData,
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use base_db::Crate;
|
||||
use chalk_ir::{UniverseIndex, WithKind, cast::Cast};
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
||||
ModuleId, TraitId, TypeAliasId,
|
||||
nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map},
|
||||
nameres::{DefMap, block_def_map, crate_def_map},
|
||||
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
|
|
@ -18,7 +17,7 @@ use intern::sym;
|
|||
use rustc_ast_ir::Mutability;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_type_ir::{
|
||||
FloatTy, IntTy, UintTy,
|
||||
FloatTy, IntTy, TypeVisitableExt, UintTy,
|
||||
inherent::{
|
||||
AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _,
|
||||
},
|
||||
|
|
@ -27,6 +26,8 @@ use smallvec::{SmallVec, smallvec};
|
|||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::next_solver::infer::InferCtxt;
|
||||
use crate::next_solver::infer::select::ImplSource;
|
||||
use crate::{
|
||||
CanonicalVarKinds, DebruijnIndex, GenericArgData, InEnvironment, Interner, TraitEnvironment,
|
||||
TyBuilder, VariableKind,
|
||||
|
|
@ -36,10 +37,10 @@ use crate::{
|
|||
lang_items::is_box,
|
||||
next_solver::{
|
||||
Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId,
|
||||
TraitRef, Ty, TyKind,
|
||||
TraitRef, Ty, TyKind, TypingMode,
|
||||
infer::{
|
||||
DefineOpaqueTypes,
|
||||
traits::{ObligationCause, PredicateObligation},
|
||||
DbInternerInferExt, DefineOpaqueTypes,
|
||||
traits::{Obligation, ObligationCause, PredicateObligation},
|
||||
},
|
||||
mapping::NextSolverToChalk,
|
||||
obligation_ctxt::ObligationCtxt,
|
||||
|
|
@ -689,11 +690,12 @@ pub(crate) fn iterate_method_candidates<'db, T>(
|
|||
}
|
||||
|
||||
pub fn lookup_impl_const<'db>(
|
||||
interner: DbInterner<'db>,
|
||||
infcx: &InferCtxt<'db>,
|
||||
env: Arc<TraitEnvironment<'db>>,
|
||||
const_id: ConstId,
|
||||
subs: GenericArgs<'db>,
|
||||
) -> (ConstId, GenericArgs<'db>) {
|
||||
let interner = infcx.interner;
|
||||
let db = interner.db;
|
||||
|
||||
let trait_id = match const_id.lookup(db).container {
|
||||
|
|
@ -708,7 +710,7 @@ pub fn lookup_impl_const<'db>(
|
|||
None => return (const_id, subs),
|
||||
};
|
||||
|
||||
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name)
|
||||
lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name)
|
||||
.and_then(
|
||||
|assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None },
|
||||
)
|
||||
|
|
@ -759,6 +761,7 @@ pub(crate) fn lookup_impl_method_query<'db>(
|
|||
fn_subst: GenericArgs<'db>,
|
||||
) -> (FunctionId, GenericArgs<'db>) {
|
||||
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
|
||||
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
|
||||
|
||||
let ItemContainerId::TraitId(trait_id) = func.lookup(db).container else {
|
||||
return (func, fn_subst);
|
||||
|
|
@ -772,7 +775,7 @@ pub(crate) fn lookup_impl_method_query<'db>(
|
|||
|
||||
let name = &db.function_signature(func).name;
|
||||
let Some((impl_fn, impl_subst)) =
|
||||
lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name).and_then(|assoc| {
|
||||
lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env, name).and_then(|assoc| {
|
||||
if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
|
||||
})
|
||||
else {
|
||||
|
|
@ -789,78 +792,53 @@ pub(crate) fn lookup_impl_method_query<'db>(
|
|||
}
|
||||
|
||||
fn lookup_impl_assoc_item_for_trait_ref<'db>(
|
||||
infcx: &InferCtxt<'db>,
|
||||
trait_ref: TraitRef<'db>,
|
||||
db: &'db dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment<'db>>,
|
||||
name: &Name,
|
||||
) -> Option<(AssocItemId, GenericArgs<'db>)> {
|
||||
let hir_trait_id = trait_ref.def_id.0;
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
|
||||
let impls = db.trait_impls_in_deps(env.krate);
|
||||
|
||||
let trait_module = hir_trait_id.module(db);
|
||||
let type_module = match self_ty_fp {
|
||||
TyFingerprint::Adt(adt_id) => Some(adt_id.module(db)),
|
||||
TyFingerprint::ForeignType(type_id) => Some(type_id.module(db)),
|
||||
TyFingerprint::Dyn(trait_id) => Some(trait_id.module(db)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let def_blocks: ArrayVec<_, 2> =
|
||||
[trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|block_id| db.trait_impls_in_block(block_id))
|
||||
.collect();
|
||||
|
||||
let impls = impls
|
||||
.iter()
|
||||
.chain(&def_blocks)
|
||||
.flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
|
||||
|
||||
let table = InferenceTable::new(db, env);
|
||||
|
||||
let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?;
|
||||
let item = impl_data.items.iter().find_map(|(n, it)| match *it {
|
||||
AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
|
||||
AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
|
||||
AssocItemId::TypeAliasId(_) => None,
|
||||
})?;
|
||||
let (impl_id, impl_subst) = find_matching_impl(infcx, &env, trait_ref)?;
|
||||
let item =
|
||||
impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
|
||||
AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
|
||||
AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
|
||||
AssocItemId::TypeAliasId(_) => None,
|
||||
})?;
|
||||
Some((item, impl_subst))
|
||||
}
|
||||
|
||||
fn find_matching_impl<'db>(
|
||||
mut impls: impl Iterator<Item = ImplId>,
|
||||
mut table: InferenceTable<'db>,
|
||||
actual_trait_ref: TraitRef<'db>,
|
||||
) -> Option<(&'db ImplItems, GenericArgs<'db>)> {
|
||||
let db = table.db;
|
||||
impls.find_map(|impl_| {
|
||||
table.run_in_snapshot(|table| {
|
||||
let impl_substs = table.fresh_args_for_item(impl_.into());
|
||||
let trait_ref = db
|
||||
.impl_trait(impl_)
|
||||
.expect("non-trait method in find_matching_impl")
|
||||
.instantiate(table.interner(), impl_substs);
|
||||
pub(crate) fn find_matching_impl<'db>(
|
||||
infcx: &InferCtxt<'db>,
|
||||
env: &TraitEnvironment<'db>,
|
||||
trait_ref: TraitRef<'db>,
|
||||
) -> Option<(ImplId, GenericArgs<'db>)> {
|
||||
let trait_ref =
|
||||
infcx.at(&ObligationCause::dummy(), env.env).deeply_normalize(trait_ref).ok()?;
|
||||
|
||||
if !table.unify(trait_ref, actual_trait_ref) {
|
||||
return None;
|
||||
}
|
||||
let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env.env, trait_ref);
|
||||
|
||||
if let Some(predicates) =
|
||||
db.generic_predicates_ns(impl_.into()).instantiate(table.interner(), impl_substs)
|
||||
{
|
||||
for predicate in predicates {
|
||||
if table.try_obligation(predicate.0).no_solution() {
|
||||
return None;
|
||||
}
|
||||
table.register_obligation(predicate.0);
|
||||
}
|
||||
}
|
||||
Some((impl_.impl_items(db), table.resolve_completely(impl_substs)))
|
||||
})
|
||||
})
|
||||
let selection = infcx.select(&obligation).ok()??;
|
||||
|
||||
// Currently, we use a fulfillment context to completely resolve
|
||||
// all nested obligations. This is because they can inform the
|
||||
// inference of the impl's type parameters.
|
||||
let mut ocx = ObligationCtxt::new(infcx);
|
||||
let impl_source = selection.map(|obligation| ocx.register_obligation(obligation));
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let impl_source = infcx.resolve_vars_if_possible(impl_source);
|
||||
if impl_source.has_non_region_infer() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match impl_source {
|
||||
ImplSource::UserDefined(impl_source) => Some((impl_source.impl_def_id, impl_source.args)),
|
||||
ImplSource::Param(_) | ImplSource::Builtin(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_inherent_impl_coherent<'db>(
|
||||
|
|
|
|||
|
|
@ -2,18 +2,7 @@
|
|||
|
||||
use std::{collections::hash_map::Entry, fmt::Display, iter};
|
||||
|
||||
use crate::{
|
||||
CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap,
|
||||
Substitution, TraitEnvironment, Ty, TyExt, TyKind,
|
||||
consteval::usize_const,
|
||||
db::HirDatabase,
|
||||
display::{DisplayTarget, HirDisplay},
|
||||
infer::{PointerCast, normalize},
|
||||
lang_items::is_box,
|
||||
mapping::ToChalk,
|
||||
};
|
||||
use base_db::Crate;
|
||||
use chalk_ir::Mutability;
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId,
|
||||
|
|
@ -21,6 +10,25 @@ use hir_def::{
|
|||
hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId},
|
||||
};
|
||||
use la_arena::{Arena, ArenaMap, Idx, RawIdx};
|
||||
use rustc_ast_ir::Mutability;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustc_type_ir::inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use stdx::{impl_from, never};
|
||||
|
||||
use crate::{
|
||||
CallableDefId, InferenceResult, MemoryMap,
|
||||
consteval::usize_const,
|
||||
db::{HirDatabase, InternedClosureId},
|
||||
display::{DisplayTarget, HirDisplay},
|
||||
infer::PointerCast,
|
||||
lang_items::is_box,
|
||||
next_solver::{
|
||||
Const, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind,
|
||||
infer::{InferCtxt, traits::ObligationCause},
|
||||
obligation_ctxt::ObligationCtxt,
|
||||
},
|
||||
};
|
||||
|
||||
mod borrowck;
|
||||
mod eval;
|
||||
|
|
@ -36,25 +44,22 @@ pub use lower::{MirLowerError, lower_to_mir, mir_body_for_closure_query, mir_bod
|
|||
pub use monomorphization::{
|
||||
monomorphized_mir_body_for_closure_query, monomorphized_mir_body_query,
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use stdx::{impl_from, never};
|
||||
|
||||
pub(crate) use lower::mir_body_cycle_result;
|
||||
pub(crate) use monomorphization::monomorphized_mir_body_cycle_result;
|
||||
|
||||
use super::consteval::{intern_const_scalar, try_const_usize};
|
||||
use super::consteval::try_const_usize;
|
||||
|
||||
pub type BasicBlockId = Idx<BasicBlock>;
|
||||
pub type LocalId = Idx<Local>;
|
||||
pub type BasicBlockId<'db> = Idx<BasicBlock<'db>>;
|
||||
pub type LocalId<'db> = Idx<Local<'db>>;
|
||||
|
||||
fn return_slot() -> LocalId {
|
||||
fn return_slot<'db>() -> LocalId<'db> {
|
||||
LocalId::from_raw(RawIdx::from(0))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Local {
|
||||
pub ty: Ty,
|
||||
pub struct Local<'db> {
|
||||
pub ty: Ty<'db>,
|
||||
}
|
||||
|
||||
/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
|
||||
|
|
@ -76,19 +81,19 @@ pub struct Local {
|
|||
/// currently implements it, but it seems like this may be something to check against in the
|
||||
/// validator.
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Operand {
|
||||
kind: OperandKind,
|
||||
pub struct Operand<'db> {
|
||||
kind: OperandKind<'db>,
|
||||
// FIXME : This should actually just be of type `MirSpan`.
|
||||
span: Option<MirSpan>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum OperandKind {
|
||||
pub enum OperandKind<'db> {
|
||||
/// Creates a value by loading the given place.
|
||||
///
|
||||
/// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there
|
||||
/// is no such requirement.
|
||||
Copy(Place),
|
||||
Copy(Place<'db>),
|
||||
|
||||
/// Creates a value by performing loading the place, just like the `Copy` operand.
|
||||
///
|
||||
|
|
@ -97,41 +102,41 @@ pub enum OperandKind {
|
|||
/// place without first re-initializing it.
|
||||
///
|
||||
/// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
|
||||
Move(Place),
|
||||
Move(Place<'db>),
|
||||
/// Constants are already semantically values, and remain unchanged.
|
||||
Constant(Const),
|
||||
Constant { konst: Const<'db>, ty: Ty<'db> },
|
||||
/// NON STANDARD: This kind of operand returns an immutable reference to that static memory. Rustc
|
||||
/// handles it with the `Constant` variant somehow.
|
||||
Static(StaticId),
|
||||
}
|
||||
|
||||
impl Operand {
|
||||
fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'static>, ty: Ty) -> Self {
|
||||
impl<'db> Operand<'db> {
|
||||
fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'db>, ty: Ty<'db>) -> Self {
|
||||
let interner = DbInterner::conjure();
|
||||
Operand {
|
||||
kind: OperandKind::Constant(intern_const_scalar(
|
||||
ConstScalar::Bytes(data, memory_map),
|
||||
kind: OperandKind::Constant {
|
||||
konst: Const::new_valtree(interner, ty, data, memory_map),
|
||||
ty,
|
||||
)),
|
||||
},
|
||||
span: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self {
|
||||
fn from_bytes(data: Box<[u8]>, ty: Ty<'db>) -> Self {
|
||||
Operand::from_concrete_const(data, MemoryMap::default(), ty)
|
||||
}
|
||||
|
||||
fn const_zst(ty: Ty) -> Operand {
|
||||
fn const_zst(ty: Ty<'db>) -> Operand<'db> {
|
||||
Self::from_bytes(Box::default(), ty)
|
||||
}
|
||||
|
||||
fn from_fn(
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
func_id: hir_def::FunctionId,
|
||||
generic_args: Substitution,
|
||||
) -> Operand {
|
||||
let ty =
|
||||
chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args)
|
||||
.intern(Interner);
|
||||
generic_args: GenericArgs<'db>,
|
||||
) -> Operand<'db> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let ty = Ty::new_fn_def(interner, CallableDefId::FunctionId(func_id).into(), generic_args);
|
||||
Operand::from_bytes(Box::default(), ty)
|
||||
}
|
||||
}
|
||||
|
|
@ -150,83 +155,81 @@ pub enum ProjectionElem<V, T> {
|
|||
}
|
||||
|
||||
impl<V, T> ProjectionElem<V, T> {
|
||||
pub fn projected_ty(
|
||||
pub fn projected_ty<'db>(
|
||||
&self,
|
||||
mut base: Ty,
|
||||
db: &dyn HirDatabase,
|
||||
closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
|
||||
infcx: &InferCtxt<'db>,
|
||||
mut base: Ty<'db>,
|
||||
closure_field: impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db>,
|
||||
krate: Crate,
|
||||
) -> Ty {
|
||||
) -> Ty<'db> {
|
||||
let interner = infcx.interner;
|
||||
let db = interner.db;
|
||||
|
||||
// we only bail on mir building when there are type mismatches
|
||||
// but error types may pop up resulting in us still attempting to build the mir
|
||||
// so just propagate the error type
|
||||
if base.is_unknown() {
|
||||
return TyKind::Error.intern(Interner);
|
||||
if base.is_ty_error() {
|
||||
return Ty::new_error(interner, ErrorGuaranteed);
|
||||
}
|
||||
|
||||
if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) {
|
||||
base = normalize(
|
||||
db,
|
||||
// FIXME: we should get this from caller
|
||||
TraitEnvironment::empty(krate),
|
||||
base,
|
||||
);
|
||||
if matches!(base.kind(), TyKind::Alias(..)) {
|
||||
let mut ocx = ObligationCtxt::new(infcx);
|
||||
// FIXME: we should get this from caller
|
||||
let env = ParamEnv::empty();
|
||||
match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) {
|
||||
Ok(it) => base = it,
|
||||
Err(_) => return Ty::new_error(interner, ErrorGuaranteed),
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
ProjectionElem::Deref => match &base.kind(Interner) {
|
||||
TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
|
||||
TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
|
||||
subst.at(Interner, 0).assert_ty_ref(Interner).clone()
|
||||
}
|
||||
ProjectionElem::Deref => match base.kind() {
|
||||
TyKind::RawPtr(inner, _) | TyKind::Ref(_, inner, _) => inner,
|
||||
TyKind::Adt(adt_def, subst) if is_box(db, adt_def.def_id().0) => subst.type_at(0),
|
||||
_ => {
|
||||
never!(
|
||||
"Overloaded deref on type {} is not a projection",
|
||||
base.display(db, DisplayTarget::from_crate(db, krate))
|
||||
);
|
||||
TyKind::Error.intern(Interner)
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
},
|
||||
ProjectionElem::Field(Either::Left(f)) => match base.kind(Interner) {
|
||||
ProjectionElem::Field(Either::Left(f)) => match base.kind() {
|
||||
TyKind::Adt(_, subst) => {
|
||||
db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
|
||||
db.field_types_ns(f.parent)[f.local_id].instantiate(interner, subst)
|
||||
}
|
||||
ty => {
|
||||
never!("Only adt has field, found {:?}", ty);
|
||||
TyKind::Error.intern(Interner)
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
},
|
||||
ProjectionElem::Field(Either::Right(f)) => match &base.kind(Interner) {
|
||||
TyKind::Tuple(_, subst) => subst
|
||||
.as_slice(Interner)
|
||||
.get(f.index as usize)
|
||||
.map(|x| x.assert_ty_ref(Interner))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
ProjectionElem::Field(Either::Right(f)) => match base.kind() {
|
||||
TyKind::Tuple(subst) => {
|
||||
subst.as_slice().get(f.index as usize).copied().unwrap_or_else(|| {
|
||||
never!("Out of bound tuple field");
|
||||
TyKind::Error.intern(Interner)
|
||||
}),
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
})
|
||||
}
|
||||
ty => {
|
||||
never!("Only tuple has tuple field: {:?}", ty);
|
||||
TyKind::Error.intern(Interner)
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
},
|
||||
ProjectionElem::ClosureField(f) => match &base.kind(Interner) {
|
||||
TyKind::Closure(id, subst) => closure_field(*id, subst, *f),
|
||||
ProjectionElem::ClosureField(f) => match base.kind() {
|
||||
TyKind::Closure(id, subst) => closure_field(id.0, subst, *f),
|
||||
_ => {
|
||||
never!("Only closure has closure field");
|
||||
TyKind::Error.intern(Interner)
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
},
|
||||
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
|
||||
match &base.kind(Interner) {
|
||||
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
|
||||
_ => {
|
||||
never!("Overloaded index is not a projection");
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => match base.kind() {
|
||||
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner,
|
||||
_ => {
|
||||
never!("Overloaded index is not a projection");
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
}
|
||||
&ProjectionElem::Subslice { from, to } => match &base.kind(Interner) {
|
||||
},
|
||||
&ProjectionElem::Subslice { from, to } => match base.kind() {
|
||||
TyKind::Array(inner, c) => {
|
||||
let next_c = usize_const(
|
||||
db,
|
||||
|
|
@ -236,34 +239,34 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
},
|
||||
krate,
|
||||
);
|
||||
TyKind::Array(inner.clone(), next_c).intern(Interner)
|
||||
Ty::new_array_with_const_len(interner, inner, next_c)
|
||||
}
|
||||
TyKind::Slice(_) => base.clone(),
|
||||
TyKind::Slice(_) => base,
|
||||
_ => {
|
||||
never!("Subslice projection should only happen on slice and array");
|
||||
TyKind::Error.intern(Interner)
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
},
|
||||
ProjectionElem::OpaqueCast(_) => {
|
||||
never!("We don't emit these yet");
|
||||
TyKind::Error.intern(Interner)
|
||||
Ty::new_error(interner, ErrorGuaranteed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PlaceElem = ProjectionElem<LocalId, Ty>;
|
||||
type PlaceElem<'db> = ProjectionElem<LocalId<'db>, Ty<'db>>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ProjectionId(u32);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ProjectionStore {
|
||||
id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
|
||||
proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
|
||||
pub struct ProjectionStore<'db> {
|
||||
id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem<'db>]>>,
|
||||
proj_to_id: FxHashMap<Box<[PlaceElem<'db>]>, ProjectionId>,
|
||||
}
|
||||
|
||||
impl Default for ProjectionStore {
|
||||
impl Default for ProjectionStore<'_> {
|
||||
fn default() -> Self {
|
||||
let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
|
||||
// Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
|
||||
|
|
@ -272,17 +275,17 @@ impl Default for ProjectionStore {
|
|||
}
|
||||
}
|
||||
|
||||
impl ProjectionStore {
|
||||
impl<'db> ProjectionStore<'db> {
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
self.id_to_proj.shrink_to_fit();
|
||||
self.proj_to_id.shrink_to_fit();
|
||||
}
|
||||
|
||||
pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
|
||||
pub fn intern_if_exist(&self, projection: &[PlaceElem<'db>]) -> Option<ProjectionId> {
|
||||
self.proj_to_id.get(projection).copied()
|
||||
}
|
||||
|
||||
pub fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
|
||||
pub fn intern(&mut self, projection: Box<[PlaceElem<'db>]>) -> ProjectionId {
|
||||
let new_id = ProjectionId(self.proj_to_id.len() as u32);
|
||||
match self.proj_to_id.entry(projection) {
|
||||
Entry::Occupied(id) => *id.get(),
|
||||
|
|
@ -303,11 +306,15 @@ impl ProjectionId {
|
|||
self == ProjectionId::EMPTY
|
||||
}
|
||||
|
||||
pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
|
||||
pub fn lookup<'a, 'db>(self, store: &'a ProjectionStore<'db>) -> &'a [PlaceElem<'db>] {
|
||||
store.id_to_proj.get(&self).unwrap()
|
||||
}
|
||||
|
||||
pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
|
||||
pub fn project<'db>(
|
||||
self,
|
||||
projection: PlaceElem<'db>,
|
||||
store: &mut ProjectionStore<'db>,
|
||||
) -> ProjectionId {
|
||||
let mut current = self.lookup(store).to_vec();
|
||||
current.push(projection);
|
||||
store.intern(current.into())
|
||||
|
|
@ -315,13 +322,13 @@ impl ProjectionId {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Place {
|
||||
pub local: LocalId,
|
||||
pub struct Place<'db> {
|
||||
pub local: LocalId<'db>,
|
||||
pub projection: ProjectionId,
|
||||
}
|
||||
|
||||
impl Place {
|
||||
fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
|
||||
impl<'db> Place<'db> {
|
||||
fn is_parent(&self, child: &Place<'db>, store: &ProjectionStore<'db>) -> bool {
|
||||
self.local == child.local
|
||||
&& child.projection.lookup(store).starts_with(self.projection.lookup(store))
|
||||
}
|
||||
|
|
@ -329,39 +336,39 @@ impl Place {
|
|||
/// The place itself is not included
|
||||
fn iterate_over_parents<'a>(
|
||||
&'a self,
|
||||
store: &'a ProjectionStore,
|
||||
) -> impl Iterator<Item = Place> + 'a {
|
||||
store: &'a ProjectionStore<'db>,
|
||||
) -> impl Iterator<Item = Place<'db>> + 'a {
|
||||
let projection = self.projection.lookup(store);
|
||||
(0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
|
||||
Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
|
||||
})
|
||||
}
|
||||
|
||||
fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
|
||||
fn project(&self, projection: PlaceElem<'db>, store: &mut ProjectionStore<'db>) -> Place<'db> {
|
||||
Place { local: self.local, projection: self.projection.project(projection, store) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LocalId> for Place {
|
||||
fn from(local: LocalId) -> Self {
|
||||
impl<'db> From<LocalId<'db>> for Place<'db> {
|
||||
fn from(local: LocalId<'db>) -> Self {
|
||||
Self { local, projection: ProjectionId::EMPTY }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum AggregateKind {
|
||||
pub enum AggregateKind<'db> {
|
||||
/// The type is of the element
|
||||
Array(Ty),
|
||||
Array(Ty<'db>),
|
||||
/// The type is of the tuple
|
||||
Tuple(Ty),
|
||||
Adt(VariantId, Substitution),
|
||||
Tuple(Ty<'db>),
|
||||
Adt(VariantId, GenericArgs<'db>),
|
||||
Union(UnionId, FieldId),
|
||||
Closure(Ty),
|
||||
Closure(Ty<'db>),
|
||||
//Coroutine(LocalDefId, SubstsRef, Movability),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct SwitchTargets {
|
||||
pub struct SwitchTargets<'db> {
|
||||
/// Possible values. The locations to branch to in each case
|
||||
/// are found in the corresponding indices from the `targets` vector.
|
||||
values: SmallVec<[u128; 1]>,
|
||||
|
|
@ -378,17 +385,17 @@ pub struct SwitchTargets {
|
|||
//
|
||||
// However we’ve decided to keep this as-is until we figure a case
|
||||
// where some other approach seems to be strictly better than other.
|
||||
targets: SmallVec<[BasicBlockId; 2]>,
|
||||
targets: SmallVec<[BasicBlockId<'db>; 2]>,
|
||||
}
|
||||
|
||||
impl SwitchTargets {
|
||||
impl<'db> SwitchTargets<'db> {
|
||||
/// Creates switch targets from an iterator of values and target blocks.
|
||||
///
|
||||
/// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
|
||||
/// `goto otherwise;`.
|
||||
pub fn new(
|
||||
targets: impl Iterator<Item = (u128, BasicBlockId)>,
|
||||
otherwise: BasicBlockId,
|
||||
targets: impl Iterator<Item = (u128, BasicBlockId<'db>)>,
|
||||
otherwise: BasicBlockId<'db>,
|
||||
) -> Self {
|
||||
let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
|
||||
targets.push(otherwise);
|
||||
|
|
@ -397,12 +404,12 @@ impl SwitchTargets {
|
|||
|
||||
/// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
|
||||
/// and to `else_` if not.
|
||||
pub fn static_if(value: u128, then: BasicBlockId, else_: BasicBlockId) -> Self {
|
||||
pub fn static_if(value: u128, then: BasicBlockId<'db>, else_: BasicBlockId<'db>) -> Self {
|
||||
Self { values: smallvec![value], targets: smallvec![then, else_] }
|
||||
}
|
||||
|
||||
/// Returns the fallback target that is jumped to when none of the values match the operand.
|
||||
pub fn otherwise(&self) -> BasicBlockId {
|
||||
pub fn otherwise(&self) -> BasicBlockId<'db> {
|
||||
*self.targets.last().unwrap()
|
||||
}
|
||||
|
||||
|
|
@ -412,33 +419,33 @@ impl SwitchTargets {
|
|||
/// including the `otherwise` fallback target.
|
||||
///
|
||||
/// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
|
||||
pub fn iter(&self) -> impl Iterator<Item = (u128, BasicBlockId)> + '_ {
|
||||
pub fn iter(&self) -> impl Iterator<Item = (u128, BasicBlockId<'db>)> + '_ {
|
||||
iter::zip(&self.values, &self.targets).map(|(x, y)| (*x, *y))
|
||||
}
|
||||
|
||||
/// Returns a slice with all possible jump targets (including the fallback target).
|
||||
pub fn all_targets(&self) -> &[BasicBlockId] {
|
||||
pub fn all_targets(&self) -> &[BasicBlockId<'db>] {
|
||||
&self.targets
|
||||
}
|
||||
|
||||
/// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
|
||||
/// specific value. This cannot fail, as it'll return the `otherwise`
|
||||
/// branch if there's not a specific match for the value.
|
||||
pub fn target_for_value(&self, value: u128) -> BasicBlockId {
|
||||
pub fn target_for_value(&self, value: u128) -> BasicBlockId<'db> {
|
||||
self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Terminator {
|
||||
pub struct Terminator<'db> {
|
||||
pub span: MirSpan,
|
||||
pub kind: TerminatorKind,
|
||||
pub kind: TerminatorKind<'db>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum TerminatorKind {
|
||||
pub enum TerminatorKind<'db> {
|
||||
/// Block has one successor; we continue execution there.
|
||||
Goto { target: BasicBlockId },
|
||||
Goto { target: BasicBlockId<'db> },
|
||||
|
||||
/// Switches based on the computed value.
|
||||
///
|
||||
|
|
@ -450,9 +457,9 @@ pub enum TerminatorKind {
|
|||
/// Target values may not appear more than once.
|
||||
SwitchInt {
|
||||
/// The discriminant value being tested.
|
||||
discr: Operand,
|
||||
discr: Operand<'db>,
|
||||
|
||||
targets: SwitchTargets,
|
||||
targets: SwitchTargets<'db>,
|
||||
},
|
||||
|
||||
/// Indicates that the landing pad is finished and that the process should continue unwinding.
|
||||
|
|
@ -503,7 +510,7 @@ pub enum TerminatorKind {
|
|||
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
|
||||
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
|
||||
/// > consider indirect assignments.
|
||||
Drop { place: Place, target: BasicBlockId, unwind: Option<BasicBlockId> },
|
||||
Drop { place: Place<'db>, target: BasicBlockId<'db>, unwind: Option<BasicBlockId<'db>> },
|
||||
|
||||
/// Drops the place and assigns a new value to it.
|
||||
///
|
||||
|
|
@ -536,10 +543,10 @@ pub enum TerminatorKind {
|
|||
///
|
||||
/// Disallowed after drop elaboration.
|
||||
DropAndReplace {
|
||||
place: Place,
|
||||
value: Operand,
|
||||
target: BasicBlockId,
|
||||
unwind: Option<BasicBlockId>,
|
||||
place: Place<'db>,
|
||||
value: Operand<'db>,
|
||||
target: BasicBlockId<'db>,
|
||||
unwind: Option<BasicBlockId<'db>>,
|
||||
},
|
||||
|
||||
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
|
||||
|
|
@ -554,18 +561,18 @@ pub enum TerminatorKind {
|
|||
/// [#71117]: https://github.com/rust-lang/rust/issues/71117
|
||||
Call {
|
||||
/// The function that’s being called.
|
||||
func: Operand,
|
||||
func: Operand<'db>,
|
||||
/// Arguments the function is called with.
|
||||
/// These are owned by the callee, which is free to modify them.
|
||||
/// This allows the memory occupied by "by-value" arguments to be
|
||||
/// reused across function calls without duplicating the contents.
|
||||
args: Box<[Operand]>,
|
||||
args: Box<[Operand<'db>]>,
|
||||
/// Where the returned value will be written
|
||||
destination: Place,
|
||||
destination: Place<'db>,
|
||||
/// Where to go after this call returns. If none, the call necessarily diverges.
|
||||
target: Option<BasicBlockId>,
|
||||
target: Option<BasicBlockId<'db>>,
|
||||
/// Cleanups to be done if the call unwinds.
|
||||
cleanup: Option<BasicBlockId>,
|
||||
cleanup: Option<BasicBlockId<'db>>,
|
||||
/// `true` if this is from a call in HIR rather than from an overloaded
|
||||
/// operator. True for overloaded function call.
|
||||
from_hir_call: bool,
|
||||
|
|
@ -581,11 +588,11 @@ pub enum TerminatorKind {
|
|||
/// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
|
||||
/// assertion does not fail, execution continues at the specified basic block.
|
||||
Assert {
|
||||
cond: Operand,
|
||||
cond: Operand<'db>,
|
||||
expected: bool,
|
||||
//msg: AssertMessage,
|
||||
target: BasicBlockId,
|
||||
cleanup: Option<BasicBlockId>,
|
||||
target: BasicBlockId<'db>,
|
||||
cleanup: Option<BasicBlockId<'db>>,
|
||||
},
|
||||
|
||||
/// Marks a suspend point.
|
||||
|
|
@ -602,13 +609,13 @@ pub enum TerminatorKind {
|
|||
/// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
|
||||
Yield {
|
||||
/// The value to return.
|
||||
value: Operand,
|
||||
value: Operand<'db>,
|
||||
/// Where to resume to.
|
||||
resume: BasicBlockId,
|
||||
resume: BasicBlockId<'db>,
|
||||
/// The place to store the resume argument in.
|
||||
resume_arg: Place,
|
||||
resume_arg: Place<'db>,
|
||||
/// Cleanup to be done if the coroutine is dropped at this suspend point.
|
||||
drop: Option<BasicBlockId>,
|
||||
drop: Option<BasicBlockId<'db>>,
|
||||
},
|
||||
|
||||
/// Indicates the end of dropping a coroutine.
|
||||
|
|
@ -631,10 +638,10 @@ pub enum TerminatorKind {
|
|||
/// Disallowed after drop elaboration.
|
||||
FalseEdge {
|
||||
/// The target normal control flow will take.
|
||||
real_target: BasicBlockId,
|
||||
real_target: BasicBlockId<'db>,
|
||||
/// A block control flow could conceptually jump to, but won't in
|
||||
/// practice.
|
||||
imaginary_target: BasicBlockId,
|
||||
imaginary_target: BasicBlockId<'db>,
|
||||
},
|
||||
|
||||
/// A terminator for blocks that only take one path in reality, but where we reserve the right
|
||||
|
|
@ -646,14 +653,14 @@ pub enum TerminatorKind {
|
|||
/// Disallowed after drop elaboration.
|
||||
FalseUnwind {
|
||||
/// The target normal control flow will take.
|
||||
real_target: BasicBlockId,
|
||||
real_target: BasicBlockId<'db>,
|
||||
/// The imaginary cleanup block link. This particular path will never be taken
|
||||
/// in practice, but in order to avoid fragility we want to always
|
||||
/// consider it in borrowck. We don't want to accept programs which
|
||||
/// pass borrowck only when `panic=abort` or some assertions are disabled
|
||||
/// due to release vs. debug mode builds. This needs to be an `Option` because
|
||||
/// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
|
||||
unwind: Option<BasicBlockId>,
|
||||
unwind: Option<BasicBlockId<'db>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -840,8 +847,8 @@ impl From<hir_def::hir::CmpOp> for BinOp {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Operand> for Rvalue {
|
||||
fn from(x: Operand) -> Self {
|
||||
impl<'db> From<Operand<'db>> for Rvalue<'db> {
|
||||
fn from(x: Operand<'db>) -> Self {
|
||||
Self::Use(x)
|
||||
}
|
||||
}
|
||||
|
|
@ -870,14 +877,14 @@ pub enum CastKind {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Rvalue {
|
||||
pub enum Rvalue<'db> {
|
||||
/// Yields the operand unchanged
|
||||
Use(Operand),
|
||||
Use(Operand<'db>),
|
||||
|
||||
/// Creates an array where each element is the value of the operand.
|
||||
///
|
||||
/// Corresponds to source code like `[x; 32]`.
|
||||
Repeat(Operand, Const),
|
||||
Repeat(Operand<'db>, Const<'db>),
|
||||
|
||||
/// Creates a reference of the indicated kind to the place.
|
||||
///
|
||||
|
|
@ -886,7 +893,7 @@ pub enum Rvalue {
|
|||
/// exactly what the behavior of this operation should be.
|
||||
///
|
||||
/// `Shallow` borrows are disallowed after drop lowering.
|
||||
Ref(BorrowKind, Place),
|
||||
Ref(BorrowKind, Place<'db>),
|
||||
|
||||
/// Creates a pointer/reference to the given thread local.
|
||||
///
|
||||
|
|
@ -917,7 +924,7 @@ pub enum Rvalue {
|
|||
/// If the type of the place is an array, this is the array length. For slices (`[T]`, not
|
||||
/// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
|
||||
/// ill-formed for places of other types.
|
||||
Len(Place),
|
||||
Len(Place<'db>),
|
||||
|
||||
/// Performs essentially all of the casts that can be performed via `as`.
|
||||
///
|
||||
|
|
@ -925,7 +932,7 @@ pub enum Rvalue {
|
|||
///
|
||||
/// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
|
||||
/// `ArrayToPointer` and `MutToConstPointer` are special.
|
||||
Cast(CastKind, Operand, Ty),
|
||||
Cast(CastKind, Operand<'db>, Ty<'db>),
|
||||
|
||||
// FIXME link to `pointer::offset` when it hits stable.
|
||||
/// * `Offset` has the same semantics as `pointer::offset`, except that the second
|
||||
|
|
@ -957,7 +964,7 @@ pub enum Rvalue {
|
|||
/// when the value of right-hand side is negative.
|
||||
///
|
||||
/// Other combinations of types and operators are unsupported.
|
||||
CheckedBinaryOp(BinOp, Operand, Operand),
|
||||
CheckedBinaryOp(BinOp, Operand<'db>, Operand<'db>),
|
||||
|
||||
/// Computes a value as described by the operation.
|
||||
//NullaryOp(NullOp, Ty),
|
||||
|
|
@ -968,7 +975,7 @@ pub enum Rvalue {
|
|||
/// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
|
||||
/// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
|
||||
/// return a value with the same type as their operand.
|
||||
UnaryOp(UnOp, Operand),
|
||||
UnaryOp(UnOp, Operand<'db>),
|
||||
|
||||
/// Computes the discriminant of the place, returning it as an integer of type
|
||||
/// [`discriminant_ty`]. Returns zero for types without discriminant.
|
||||
|
|
@ -980,7 +987,7 @@ pub enum Rvalue {
|
|||
/// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
|
||||
/// [#91095]: https://github.com/rust-lang/rust/issues/91095
|
||||
/// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
|
||||
Discriminant(Place),
|
||||
Discriminant(Place<'db>),
|
||||
|
||||
/// Creates an aggregate value, like a tuple or struct.
|
||||
///
|
||||
|
|
@ -990,17 +997,17 @@ pub enum Rvalue {
|
|||
///
|
||||
/// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After
|
||||
/// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
|
||||
Aggregate(AggregateKind, Box<[Operand]>),
|
||||
Aggregate(AggregateKind<'db>, Box<[Operand<'db>]>),
|
||||
|
||||
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
|
||||
///
|
||||
/// This is different from a normal transmute because dataflow analysis will treat the box as
|
||||
/// initialized but its content as uninitialized. Like other pointer casts, this in general
|
||||
/// affects alias analysis.
|
||||
ShallowInitBox(Operand, Ty),
|
||||
ShallowInitBox(Operand<'db>, Ty<'db>),
|
||||
|
||||
/// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer.
|
||||
ShallowInitBoxWithAlloc(Ty),
|
||||
ShallowInitBoxWithAlloc(Ty<'db>),
|
||||
|
||||
/// A CopyForDeref is equivalent to a read from a place at the
|
||||
/// codegen level, but is treated specially by drop elaboration. When such a read happens, it
|
||||
|
|
@ -1010,41 +1017,41 @@ pub enum Rvalue {
|
|||
/// read never happened and just projects further. This allows simplifying various MIR
|
||||
/// optimizations and codegen backends that previously had to handle deref operations anywhere
|
||||
/// in a place.
|
||||
CopyForDeref(Place),
|
||||
CopyForDeref(Place<'db>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum StatementKind {
|
||||
Assign(Place, Rvalue),
|
||||
FakeRead(Place),
|
||||
pub enum StatementKind<'db> {
|
||||
Assign(Place<'db>, Rvalue<'db>),
|
||||
FakeRead(Place<'db>),
|
||||
//SetDiscriminant {
|
||||
// place: Box<Place>,
|
||||
// variant_index: VariantIdx,
|
||||
//},
|
||||
Deinit(Place),
|
||||
StorageLive(LocalId),
|
||||
StorageDead(LocalId),
|
||||
Deinit(Place<'db>),
|
||||
StorageLive(LocalId<'db>),
|
||||
StorageDead(LocalId<'db>),
|
||||
//Retag(RetagKind, Box<Place>),
|
||||
//AscribeUserType(Place, UserTypeProjection, Variance),
|
||||
//Intrinsic(Box<NonDivergingIntrinsic>),
|
||||
Nop,
|
||||
}
|
||||
impl StatementKind {
|
||||
fn with_span(self, span: MirSpan) -> Statement {
|
||||
impl<'db> StatementKind<'db> {
|
||||
fn with_span(self, span: MirSpan) -> Statement<'db> {
|
||||
Statement { kind: self, span }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Statement {
|
||||
pub kind: StatementKind,
|
||||
pub struct Statement<'db> {
|
||||
pub kind: StatementKind<'db>,
|
||||
pub span: MirSpan,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct BasicBlock {
|
||||
pub struct BasicBlock<'db> {
|
||||
/// List of statements in this block.
|
||||
pub statements: Vec<Statement>,
|
||||
pub statements: Vec<Statement<'db>>,
|
||||
|
||||
/// Terminator for this block.
|
||||
///
|
||||
|
|
@ -1054,7 +1061,7 @@ pub struct BasicBlock {
|
|||
/// exception is that certain passes, such as `simplify_cfg`, swap
|
||||
/// out the terminator temporarily with `None` while they continue
|
||||
/// to recurse over the set of basic blocks.
|
||||
pub terminator: Option<Terminator>,
|
||||
pub terminator: Option<Terminator<'db>>,
|
||||
|
||||
/// If true, this block lies on an unwind path. This is used
|
||||
/// during codegen where distinct kinds of basic blocks may be
|
||||
|
|
@ -1064,35 +1071,35 @@ pub struct BasicBlock {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MirBody {
|
||||
pub projection_store: ProjectionStore,
|
||||
pub basic_blocks: Arena<BasicBlock>,
|
||||
pub locals: Arena<Local>,
|
||||
pub start_block: BasicBlockId,
|
||||
pub struct MirBody<'db> {
|
||||
pub projection_store: ProjectionStore<'db>,
|
||||
pub basic_blocks: Arena<BasicBlock<'db>>,
|
||||
pub locals: Arena<Local<'db>>,
|
||||
pub start_block: BasicBlockId<'db>,
|
||||
pub owner: DefWithBodyId,
|
||||
pub binding_locals: ArenaMap<BindingId, LocalId>,
|
||||
pub param_locals: Vec<LocalId>,
|
||||
pub binding_locals: ArenaMap<BindingId, LocalId<'db>>,
|
||||
pub param_locals: Vec<LocalId<'db>>,
|
||||
/// This field stores the closures directly owned by this body. It is used
|
||||
/// in traversing every mir body.
|
||||
pub closures: Vec<ClosureId>,
|
||||
pub closures: Vec<InternedClosureId>,
|
||||
}
|
||||
|
||||
impl MirBody {
|
||||
pub fn local_to_binding_map(&self) -> ArenaMap<LocalId, BindingId> {
|
||||
impl<'db> MirBody<'db> {
|
||||
pub fn local_to_binding_map(&self) -> ArenaMap<LocalId<'db>, BindingId> {
|
||||
self.binding_locals.iter().map(|(it, y)| (*y, it)).collect()
|
||||
}
|
||||
|
||||
fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
|
||||
fn for_operand(
|
||||
op: &mut Operand,
|
||||
f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
|
||||
store: &mut ProjectionStore,
|
||||
fn walk_places(&mut self, mut f: impl FnMut(&mut Place<'db>, &mut ProjectionStore<'db>)) {
|
||||
fn for_operand<'db>(
|
||||
op: &mut Operand<'db>,
|
||||
f: &mut impl FnMut(&mut Place<'db>, &mut ProjectionStore<'db>),
|
||||
store: &mut ProjectionStore<'db>,
|
||||
) {
|
||||
match &mut op.kind {
|
||||
OperandKind::Copy(p) | OperandKind::Move(p) => {
|
||||
f(p, store);
|
||||
}
|
||||
OperandKind::Constant(_) | OperandKind::Static(_) => (),
|
||||
OperandKind::Constant { .. } | OperandKind::Static(_) => (),
|
||||
}
|
||||
}
|
||||
for (_, block) in self.basic_blocks.iter_mut() {
|
||||
|
|
|
|||
|
|
@ -11,14 +11,15 @@ use rustc_hash::FxHashMap;
|
|||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::next_solver::DbInterner;
|
||||
use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
|
||||
use crate::{
|
||||
ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags,
|
||||
db::{HirDatabase, InternedClosure},
|
||||
TraitEnvironment,
|
||||
db::{HirDatabase, InternedClosure, InternedClosureId},
|
||||
display::DisplayTarget,
|
||||
mir::OperandKind,
|
||||
utils::ClosureSubst,
|
||||
next_solver::{
|
||||
DbInterner, GenericArgs, SolverDefIds, Ty, TypingMode,
|
||||
infer::{DbInternerInferExt, InferCtxt},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -35,45 +36,45 @@ pub enum MutabilityReason {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MovedOutOfRef {
|
||||
pub ty: Ty,
|
||||
pub struct MovedOutOfRef<'db> {
|
||||
pub ty: Ty<'db>,
|
||||
pub span: MirSpan,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PartiallyMoved {
|
||||
pub ty: Ty,
|
||||
pub struct PartiallyMoved<'db> {
|
||||
pub ty: Ty<'db>,
|
||||
pub span: MirSpan,
|
||||
pub local: LocalId,
|
||||
pub local: LocalId<'db>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BorrowRegion {
|
||||
pub local: LocalId,
|
||||
pub struct BorrowRegion<'db> {
|
||||
pub local: LocalId<'db>,
|
||||
pub kind: BorrowKind,
|
||||
pub places: Vec<MirSpan>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct BorrowckResult {
|
||||
pub mir_body: Arc<MirBody>,
|
||||
pub mutability_of_locals: ArenaMap<LocalId, MutabilityReason>,
|
||||
pub moved_out_of_ref: Vec<MovedOutOfRef>,
|
||||
pub partially_moved: Vec<PartiallyMoved>,
|
||||
pub borrow_regions: Vec<BorrowRegion>,
|
||||
pub struct BorrowckResult<'db> {
|
||||
pub mir_body: Arc<MirBody<'db>>,
|
||||
pub mutability_of_locals: ArenaMap<LocalId<'db>, MutabilityReason>,
|
||||
pub moved_out_of_ref: Vec<MovedOutOfRef<'db>>,
|
||||
pub partially_moved: Vec<PartiallyMoved<'db>>,
|
||||
pub borrow_regions: Vec<BorrowRegion<'db>>,
|
||||
}
|
||||
|
||||
fn all_mir_bodies<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
mut cb: impl FnMut(Arc<MirBody>),
|
||||
mut cb: impl FnMut(Arc<MirBody<'db>>),
|
||||
) -> Result<(), MirLowerError<'db>> {
|
||||
fn for_closure<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
c: ClosureId,
|
||||
cb: &mut impl FnMut(Arc<MirBody>),
|
||||
c: InternedClosureId,
|
||||
cb: &mut impl FnMut(Arc<MirBody<'db>>),
|
||||
) -> Result<(), MirLowerError<'db>> {
|
||||
match db.mir_body_for_closure(c.into()) {
|
||||
match db.mir_body_for_closure(c) {
|
||||
Ok(body) => {
|
||||
cb(body.clone());
|
||||
body.closures.iter().try_for_each(|&it| for_closure(db, it, cb))
|
||||
|
|
@ -93,14 +94,21 @@ fn all_mir_bodies<'db>(
|
|||
pub fn borrowck_query<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
) -> Result<Arc<[BorrowckResult]>, MirLowerError<'db>> {
|
||||
) -> Result<Arc<[BorrowckResult<'db>]>, MirLowerError<'db>> {
|
||||
let _p = tracing::info_span!("borrowck_query").entered();
|
||||
let module = def.module(db);
|
||||
let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block());
|
||||
let env = db.trait_environment_for_body(def);
|
||||
let mut res = vec![];
|
||||
all_mir_bodies(db, def, |body| {
|
||||
// FIXME(next-solver): Opaques.
|
||||
let infcx = interner.infer_ctxt().build(TypingMode::Borrowck {
|
||||
defining_opaque_types: SolverDefIds::new_from_iter(interner, []),
|
||||
});
|
||||
res.push(BorrowckResult {
|
||||
mutability_of_locals: mutability_of_locals(db, &body),
|
||||
moved_out_of_ref: moved_out_of_ref(db, &body),
|
||||
partially_moved: partially_moved(db, &body),
|
||||
mutability_of_locals: mutability_of_locals(&infcx, &body),
|
||||
moved_out_of_ref: moved_out_of_ref(&infcx, &env, &body),
|
||||
partially_moved: partially_moved(&infcx, &env, &body),
|
||||
borrow_regions: borrow_regions(db, &body),
|
||||
mir_body: body,
|
||||
});
|
||||
|
|
@ -108,51 +116,49 @@ pub fn borrowck_query<'db>(
|
|||
Ok(res.into())
|
||||
}
|
||||
|
||||
fn make_fetch_closure_field(
|
||||
db: &dyn HirDatabase,
|
||||
) -> impl FnOnce(ClosureId, &Substitution, usize) -> Ty + '_ {
|
||||
|c: ClosureId, subst: &Substitution, f: usize| {
|
||||
let InternedClosure(def, _) = db.lookup_intern_closure(c.into());
|
||||
fn make_fetch_closure_field<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> {
|
||||
|c: InternedClosureId, subst: GenericArgs<'db>, f: usize| {
|
||||
let InternedClosure(def, _) = db.lookup_intern_closure(c);
|
||||
let infer = db.infer(def);
|
||||
let (captures, _) = infer.closure_info(c.into());
|
||||
let parent_subst = ClosureSubst(subst).parent_subst(db);
|
||||
let (captures, _) = infer.closure_info(c);
|
||||
let parent_subst = subst.split_closure_args_untupled().parent_args;
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let parent_subst: crate::next_solver::GenericArgs<'_> =
|
||||
parent_subst.to_nextsolver(interner);
|
||||
captures
|
||||
.get(f)
|
||||
.expect("broken closure field")
|
||||
.ty
|
||||
.instantiate(interner, parent_subst)
|
||||
.to_chalk(interner)
|
||||
captures.get(f).expect("broken closure field").ty.instantiate(interner, parent_subst)
|
||||
}
|
||||
}
|
||||
|
||||
fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef> {
|
||||
fn moved_out_of_ref<'db>(
|
||||
infcx: &InferCtxt<'db>,
|
||||
env: &TraitEnvironment<'db>,
|
||||
body: &MirBody<'db>,
|
||||
) -> Vec<MovedOutOfRef<'db>> {
|
||||
let db = infcx.interner.db;
|
||||
let mut result = vec![];
|
||||
let mut for_operand = |op: &Operand, span: MirSpan| match op.kind {
|
||||
let mut for_operand = |op: &Operand<'db>, span: MirSpan| match op.kind {
|
||||
OperandKind::Copy(p) | OperandKind::Move(p) => {
|
||||
let mut ty: Ty = body.locals[p.local].ty.clone();
|
||||
let mut ty: Ty<'db> = body.locals[p.local].ty;
|
||||
let mut is_dereference_of_ref = false;
|
||||
for proj in p.projection.lookup(&body.projection_store) {
|
||||
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
|
||||
is_dereference_of_ref = true;
|
||||
}
|
||||
ty = proj.projected_ty(
|
||||
infcx,
|
||||
ty,
|
||||
db,
|
||||
make_fetch_closure_field(db),
|
||||
body.owner.module(db).krate(),
|
||||
);
|
||||
}
|
||||
if is_dereference_of_ref
|
||||
&& !ty.clone().is_copy(db, body.owner)
|
||||
&& !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR)
|
||||
&& !infcx.type_is_copy_modulo_regions(env.env, ty)
|
||||
&& !ty.references_non_lt_error()
|
||||
{
|
||||
result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty });
|
||||
}
|
||||
}
|
||||
OperandKind::Constant(_) | OperandKind::Static(_) => (),
|
||||
OperandKind::Constant { .. } | OperandKind::Static(_) => (),
|
||||
};
|
||||
for (_, block) in body.basic_blocks.iter() {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
|
@ -223,26 +229,29 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
|
|||
result
|
||||
}
|
||||
|
||||
fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved> {
|
||||
fn partially_moved<'db>(
|
||||
infcx: &InferCtxt<'db>,
|
||||
env: &TraitEnvironment<'db>,
|
||||
body: &MirBody<'db>,
|
||||
) -> Vec<PartiallyMoved<'db>> {
|
||||
let db = infcx.interner.db;
|
||||
let mut result = vec![];
|
||||
let mut for_operand = |op: &Operand, span: MirSpan| match op.kind {
|
||||
let mut for_operand = |op: &Operand<'db>, span: MirSpan| match op.kind {
|
||||
OperandKind::Copy(p) | OperandKind::Move(p) => {
|
||||
let mut ty: Ty = body.locals[p.local].ty.clone();
|
||||
let mut ty: Ty<'db> = body.locals[p.local].ty;
|
||||
for proj in p.projection.lookup(&body.projection_store) {
|
||||
ty = proj.projected_ty(
|
||||
infcx,
|
||||
ty,
|
||||
db,
|
||||
make_fetch_closure_field(db),
|
||||
body.owner.module(db).krate(),
|
||||
);
|
||||
}
|
||||
if !ty.clone().is_copy(db, body.owner)
|
||||
&& !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR)
|
||||
{
|
||||
if !infcx.type_is_copy_modulo_regions(env.env, ty) && !ty.references_non_lt_error() {
|
||||
result.push(PartiallyMoved { span, ty, local: p.local });
|
||||
}
|
||||
}
|
||||
OperandKind::Constant(_) | OperandKind::Static(_) => (),
|
||||
OperandKind::Constant { .. } | OperandKind::Static(_) => (),
|
||||
};
|
||||
for (_, block) in body.basic_blocks.iter() {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
|
@ -313,7 +322,7 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved>
|
|||
result
|
||||
}
|
||||
|
||||
fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec<BorrowRegion> {
|
||||
fn borrow_regions<'db>(db: &'db dyn HirDatabase, body: &MirBody<'db>) -> Vec<BorrowRegion<'db>> {
|
||||
let mut borrows = FxHashMap::default();
|
||||
for (_, block) in body.basic_blocks.iter() {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
|
@ -321,7 +330,7 @@ fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec<BorrowRegion> {
|
|||
if let StatementKind::Assign(_, Rvalue::Ref(kind, p)) = &statement.kind {
|
||||
borrows
|
||||
.entry(p.local)
|
||||
.and_modify(|it: &mut BorrowRegion| {
|
||||
.and_modify(|it: &mut BorrowRegion<'db>| {
|
||||
it.places.push(statement.span);
|
||||
})
|
||||
.or_insert_with(|| BorrowRegion {
|
||||
|
|
@ -363,9 +372,14 @@ enum ProjectionCase {
|
|||
Indirect,
|
||||
}
|
||||
|
||||
fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
|
||||
fn place_case<'db>(
|
||||
infcx: &InferCtxt<'db>,
|
||||
body: &MirBody<'db>,
|
||||
lvalue: &Place<'db>,
|
||||
) -> ProjectionCase {
|
||||
let db = infcx.interner.db;
|
||||
let mut is_part_of = false;
|
||||
let mut ty = body.locals[lvalue.local].ty.clone();
|
||||
let mut ty = body.locals[lvalue.local].ty;
|
||||
for proj in lvalue.projection.lookup(&body.projection_store).iter() {
|
||||
match proj {
|
||||
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
|
||||
|
|
@ -379,7 +393,12 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio
|
|||
}
|
||||
ProjectionElem::OpaqueCast(_) => (),
|
||||
}
|
||||
ty = proj.projected_ty(ty, db, make_fetch_closure_field(db), body.owner.module(db).krate());
|
||||
ty = proj.projected_ty(
|
||||
infcx,
|
||||
ty,
|
||||
make_fetch_closure_field(db),
|
||||
body.owner.module(db).krate(),
|
||||
);
|
||||
}
|
||||
if is_part_of { ProjectionCase::DirectPart } else { ProjectionCase::Direct }
|
||||
}
|
||||
|
|
@ -387,18 +406,18 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio
|
|||
/// Returns a map from basic blocks to the set of locals that might be ever initialized before
|
||||
/// the start of the block. Only `StorageDead` can remove something from this map, and we ignore
|
||||
/// `Uninit` and `drop` and similar after initialization.
|
||||
fn ever_initialized_map(
|
||||
db: &dyn HirDatabase,
|
||||
body: &MirBody,
|
||||
) -> ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> {
|
||||
let mut result: ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>> =
|
||||
fn ever_initialized_map<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
body: &MirBody<'db>,
|
||||
) -> ArenaMap<BasicBlockId<'db>, ArenaMap<LocalId<'db>, bool>> {
|
||||
let mut result: ArenaMap<BasicBlockId<'db>, ArenaMap<LocalId<'db>, bool>> =
|
||||
body.basic_blocks.iter().map(|it| (it.0, ArenaMap::default())).collect();
|
||||
fn dfs(
|
||||
db: &dyn HirDatabase,
|
||||
body: &MirBody,
|
||||
l: LocalId,
|
||||
stack: &mut Vec<BasicBlockId>,
|
||||
result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>,
|
||||
fn dfs<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
body: &MirBody<'db>,
|
||||
l: LocalId<'db>,
|
||||
stack: &mut Vec<BasicBlockId<'db>>,
|
||||
result: &mut ArenaMap<BasicBlockId<'db>, ArenaMap<LocalId<'db>, bool>>,
|
||||
) {
|
||||
while let Some(b) = stack.pop() {
|
||||
let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
|
||||
|
|
@ -486,7 +505,11 @@ fn ever_initialized_map(
|
|||
result
|
||||
}
|
||||
|
||||
fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap<LocalId, MutabilityReason>) {
|
||||
fn push_mut_span<'db>(
|
||||
local: LocalId<'db>,
|
||||
span: MirSpan,
|
||||
result: &mut ArenaMap<LocalId<'db>, MutabilityReason>,
|
||||
) {
|
||||
match &mut result[local] {
|
||||
MutabilityReason::Mut { spans } => spans.push(span),
|
||||
it @ (MutabilityReason::Not | MutabilityReason::Unused) => {
|
||||
|
|
@ -495,23 +518,27 @@ fn push_mut_span(local: LocalId, span: MirSpan, result: &mut ArenaMap<LocalId, M
|
|||
};
|
||||
}
|
||||
|
||||
fn record_usage(local: LocalId, result: &mut ArenaMap<LocalId, MutabilityReason>) {
|
||||
fn record_usage<'db>(local: LocalId<'db>, result: &mut ArenaMap<LocalId<'db>, MutabilityReason>) {
|
||||
if let it @ MutabilityReason::Unused = &mut result[local] {
|
||||
*it = MutabilityReason::Not;
|
||||
};
|
||||
}
|
||||
|
||||
fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap<LocalId, MutabilityReason>) {
|
||||
fn record_usage_for_operand<'db>(
|
||||
arg: &Operand<'db>,
|
||||
result: &mut ArenaMap<LocalId<'db>, MutabilityReason>,
|
||||
) {
|
||||
if let OperandKind::Copy(p) | OperandKind::Move(p) = arg.kind {
|
||||
record_usage(p.local, result);
|
||||
}
|
||||
}
|
||||
|
||||
fn mutability_of_locals(
|
||||
db: &dyn HirDatabase,
|
||||
body: &MirBody,
|
||||
) -> ArenaMap<LocalId, MutabilityReason> {
|
||||
let mut result: ArenaMap<LocalId, MutabilityReason> =
|
||||
fn mutability_of_locals<'db>(
|
||||
infcx: &InferCtxt<'db>,
|
||||
body: &MirBody<'db>,
|
||||
) -> ArenaMap<LocalId<'db>, MutabilityReason> {
|
||||
let db = infcx.interner.db;
|
||||
let mut result: ArenaMap<LocalId<'db>, MutabilityReason> =
|
||||
body.locals.iter().map(|it| (it.0, MutabilityReason::Unused)).collect();
|
||||
|
||||
let ever_init_maps = ever_initialized_map(db, body);
|
||||
|
|
@ -520,7 +547,7 @@ fn mutability_of_locals(
|
|||
for statement in &block.statements {
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(place, value) => {
|
||||
match place_case(db, body, place) {
|
||||
match place_case(infcx, body, place) {
|
||||
ProjectionCase::Direct => {
|
||||
if ever_init_map.get(place.local).copied().unwrap_or_default() {
|
||||
push_mut_span(place.local, statement.span, &mut result);
|
||||
|
|
@ -569,7 +596,7 @@ fn mutability_of_locals(
|
|||
},
|
||||
p,
|
||||
) = value
|
||||
&& place_case(db, body, p) != ProjectionCase::Indirect
|
||||
&& place_case(infcx, body, p) != ProjectionCase::Indirect
|
||||
{
|
||||
push_mut_span(p.local, statement.span, &mut result);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,32 +3,21 @@
|
|||
//!
|
||||
use std::cmp::{self, Ordering};
|
||||
|
||||
use chalk_ir::TyKind;
|
||||
use hir_def::signatures::FunctionSignature;
|
||||
use hir_def::{
|
||||
CrateRootModuleId,
|
||||
builtin_type::{BuiltinInt, BuiltinUint},
|
||||
resolver::HasResolver,
|
||||
};
|
||||
use hir_def::{CrateRootModuleId, resolver::HasResolver, signatures::FunctionSignature};
|
||||
use hir_expand::name::Name;
|
||||
use intern::{Symbol, sym};
|
||||
use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _};
|
||||
use stdx::never;
|
||||
|
||||
use crate::next_solver::mapping::NextSolverToChalk;
|
||||
use crate::{
|
||||
display::DisplayTarget,
|
||||
drop::{DropGlue, has_drop_glue},
|
||||
error_lifetime,
|
||||
mir::eval::{
|
||||
Address, AdtId, Arc, BuiltinType, Evaluator, FunctionId, HasModule, HirDisplay,
|
||||
InternedClosure, Interner, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId,
|
||||
LangItem, Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Substitution,
|
||||
Ty, TyBuilder, TyExt, pad16,
|
||||
},
|
||||
next_solver::{
|
||||
DbInterner,
|
||||
mapping::{ChalkToNextSolver, convert_ty_for_result},
|
||||
Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay,
|
||||
InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, LangItem,
|
||||
Layout, Locals, Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, pad16,
|
||||
},
|
||||
next_solver::Region,
|
||||
};
|
||||
|
||||
mod simd;
|
||||
|
|
@ -53,9 +42,9 @@ impl<'db> Evaluator<'db> {
|
|||
pub(super) fn detect_and_exec_special_function(
|
||||
&mut self,
|
||||
def: FunctionId,
|
||||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
locals: &Locals,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
generic_args: GenericArgs<'db>,
|
||||
locals: &Locals<'db>,
|
||||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<'db, bool> {
|
||||
|
|
@ -118,18 +107,16 @@ impl<'db> Evaluator<'db> {
|
|||
if let ItemContainerId::TraitId(t) = def.lookup(self.db).container
|
||||
&& self.db.lang_attr(t.into()) == Some(LangItem::Clone)
|
||||
{
|
||||
let [self_ty] = generic_args.as_slice(Interner) else {
|
||||
let [self_ty] = generic_args.as_slice() else {
|
||||
not_supported!("wrong generic arg count for clone");
|
||||
};
|
||||
let Some(self_ty) = self_ty.ty(Interner) else {
|
||||
let Some(self_ty) = self_ty.ty() else {
|
||||
not_supported!("wrong generic arg kind for clone");
|
||||
};
|
||||
// Clone has special impls for tuples and function pointers
|
||||
if matches!(
|
||||
self_ty.kind(Interner),
|
||||
TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
|
||||
) {
|
||||
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||
if matches!(self_ty.kind(), TyKind::FnPtr(..) | TyKind::Tuple(..) | TyKind::Closure(..))
|
||||
{
|
||||
self.exec_clone(def, args, self_ty, locals, destination, span)?;
|
||||
return Ok(true);
|
||||
}
|
||||
// Return early to prevent caching clone as non special fn.
|
||||
|
|
@ -161,15 +148,14 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_clone(
|
||||
&mut self,
|
||||
def: FunctionId,
|
||||
args: &[IntervalAndTy],
|
||||
self_ty: Ty,
|
||||
locals: &Locals,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
self_ty: Ty<'db>,
|
||||
locals: &Locals<'db>,
|
||||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<'db, ()> {
|
||||
let interner = self.interner;
|
||||
match self_ty.kind(Interner) {
|
||||
TyKind::Function(_) => {
|
||||
match self_ty.kind() {
|
||||
TyKind::FnPtr(..) => {
|
||||
let [arg] = args else {
|
||||
not_supported!("wrong arg count for clone");
|
||||
};
|
||||
|
|
@ -182,30 +168,35 @@ impl<'db> Evaluator<'db> {
|
|||
not_supported!("wrong arg count for clone");
|
||||
};
|
||||
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||
let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure((*id).into());
|
||||
let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0);
|
||||
let infer = self.db.infer(closure_owner);
|
||||
let (captures, _) = infer.closure_info((*id).into());
|
||||
let layout = self.layout(self_ty.to_nextsolver(interner))?;
|
||||
let (captures, _) = infer.closure_info(id.0);
|
||||
let layout = self.layout(self_ty)?;
|
||||
let db = self.db;
|
||||
let ty_iter = captures
|
||||
.iter()
|
||||
.map(|c| c.ty(db, subst.to_nextsolver(interner)).to_chalk(interner));
|
||||
let ty_iter = captures.iter().map(|c| c.ty(db, subst));
|
||||
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
|
||||
}
|
||||
TyKind::Tuple(_, subst) => {
|
||||
TyKind::Tuple(subst) => {
|
||||
let [arg] = args else {
|
||||
not_supported!("wrong arg count for clone");
|
||||
};
|
||||
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||
let layout = self.layout(self_ty.to_nextsolver(interner))?;
|
||||
let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
|
||||
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
|
||||
let layout = self.layout(self_ty)?;
|
||||
self.exec_clone_for_fields(
|
||||
subst.iter(),
|
||||
layout,
|
||||
addr,
|
||||
def,
|
||||
locals,
|
||||
destination,
|
||||
span,
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
self.exec_fn_with_args(
|
||||
def,
|
||||
args,
|
||||
Substitution::from1(Interner, self_ty),
|
||||
GenericArgs::new_from_iter(self.interner(), [self_ty.into()]),
|
||||
locals,
|
||||
destination,
|
||||
None,
|
||||
|
|
@ -218,21 +209,25 @@ impl<'db> Evaluator<'db> {
|
|||
|
||||
fn exec_clone_for_fields(
|
||||
&mut self,
|
||||
ty_iter: impl Iterator<Item = Ty>,
|
||||
ty_iter: impl Iterator<Item = Ty<'db>>,
|
||||
layout: Arc<Layout>,
|
||||
addr: Address,
|
||||
def: FunctionId,
|
||||
locals: &Locals,
|
||||
locals: &Locals<'db>,
|
||||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<'db, ()> {
|
||||
let interner = DbInterner::new_with(self.db, None, None);
|
||||
for (i, ty) in ty_iter.enumerate() {
|
||||
let size = self.layout(ty.to_nextsolver(interner))?.size.bytes_usize();
|
||||
let size = self.layout(ty)?.size.bytes_usize();
|
||||
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
|
||||
let arg = IntervalAndTy {
|
||||
interval: Interval { addr: tmp, size: self.ptr_size() },
|
||||
ty: TyKind::Ref(Mutability::Not, error_lifetime(), ty.clone()).intern(Interner),
|
||||
ty: Ty::new_ref(
|
||||
self.interner(),
|
||||
Region::error(self.interner()),
|
||||
ty,
|
||||
Mutability::Not,
|
||||
),
|
||||
};
|
||||
let offset = layout.fields.offset(i).bytes_usize();
|
||||
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
|
||||
|
|
@ -251,7 +246,7 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_alloc_fn(
|
||||
&mut self,
|
||||
alloc_fn: &Symbol,
|
||||
args: &[IntervalAndTy],
|
||||
args: &[IntervalAndTy<'db>],
|
||||
destination: Interval,
|
||||
) -> Result<'db, ()> {
|
||||
match alloc_fn {
|
||||
|
|
@ -313,9 +308,9 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_lang_item(
|
||||
&mut self,
|
||||
it: LangItem,
|
||||
generic_args: &Substitution,
|
||||
args: &[IntervalAndTy],
|
||||
locals: &Locals,
|
||||
generic_args: GenericArgs<'db>,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
locals: &Locals<'db>,
|
||||
span: MirSpan,
|
||||
) -> Result<'db, Vec<u8>> {
|
||||
use LangItem::*;
|
||||
|
|
@ -328,7 +323,7 @@ impl<'db> Evaluator<'db> {
|
|||
"argument of BeginPanic is not provided".into(),
|
||||
))?
|
||||
.clone();
|
||||
while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) {
|
||||
while let TyKind::Ref(_, ty, _) = arg.ty.kind() {
|
||||
if ty.is_str() {
|
||||
let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size());
|
||||
let len = from_bytes!(usize, metadata);
|
||||
|
|
@ -347,13 +342,10 @@ impl<'db> Evaluator<'db> {
|
|||
let pointee = arg.interval.get(self)?;
|
||||
arg = IntervalAndTy {
|
||||
interval: Interval::new(Address::from_bytes(pointee)?, size),
|
||||
ty: ty.clone(),
|
||||
ty,
|
||||
};
|
||||
}
|
||||
Err(MirEvalError::Panic(format!(
|
||||
"unknown-panic-payload: {:?}",
|
||||
arg.ty.kind(Interner)
|
||||
)))
|
||||
Err(MirEvalError::Panic(format!("unknown-panic-payload: {:?}", arg.ty.kind())))
|
||||
}
|
||||
SliceLen => {
|
||||
let arg = args.next().ok_or(MirEvalError::InternalError(
|
||||
|
|
@ -364,18 +356,17 @@ impl<'db> Evaluator<'db> {
|
|||
Ok(arg[ptr_size..].into())
|
||||
}
|
||||
DropInPlace => {
|
||||
let ty =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner)).ok_or(
|
||||
MirEvalError::InternalError(
|
||||
"generic argument of drop_in_place is not provided".into(),
|
||||
),
|
||||
)?;
|
||||
let ty = generic_args.as_slice().first().and_then(|it| it.ty()).ok_or(
|
||||
MirEvalError::InternalError(
|
||||
"generic argument of drop_in_place is not provided".into(),
|
||||
),
|
||||
)?;
|
||||
let arg = args.next().ok_or(MirEvalError::InternalError(
|
||||
"argument of drop_in_place is not provided".into(),
|
||||
))?;
|
||||
let arg = arg.interval.get(self)?.to_owned();
|
||||
self.run_drop_glue_deep(
|
||||
ty.clone(),
|
||||
ty,
|
||||
locals,
|
||||
Address::from_bytes(&arg[0..self.ptr_size()])?,
|
||||
&arg[self.ptr_size()..],
|
||||
|
|
@ -390,9 +381,9 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_syscall(
|
||||
&mut self,
|
||||
id: i64,
|
||||
args: &[IntervalAndTy],
|
||||
args: &[IntervalAndTy<'db>],
|
||||
destination: Interval,
|
||||
_locals: &Locals,
|
||||
_locals: &Locals<'db>,
|
||||
_span: MirSpan,
|
||||
) -> Result<'db, ()> {
|
||||
match id {
|
||||
|
|
@ -420,10 +411,10 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_extern_c(
|
||||
&mut self,
|
||||
as_str: &str,
|
||||
args: &[IntervalAndTy],
|
||||
_generic_args: &Substitution,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
_generic_args: GenericArgs<'db>,
|
||||
destination: Interval,
|
||||
locals: &Locals,
|
||||
locals: &Locals<'db>,
|
||||
span: MirSpan,
|
||||
) -> Result<'db, ()> {
|
||||
match as_str {
|
||||
|
|
@ -586,14 +577,13 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_intrinsic(
|
||||
&mut self,
|
||||
name: &str,
|
||||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
generic_args: GenericArgs<'db>,
|
||||
destination: Interval,
|
||||
locals: &Locals,
|
||||
locals: &Locals<'db>,
|
||||
span: MirSpan,
|
||||
needs_override: bool,
|
||||
) -> Result<'db, bool> {
|
||||
let interner = DbInterner::new_with(self.db, None, None);
|
||||
if let Some(name) = name.strip_prefix("atomic_") {
|
||||
return self
|
||||
.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span)
|
||||
|
|
@ -751,9 +741,7 @@ impl<'db> Evaluator<'db> {
|
|||
}
|
||||
match name {
|
||||
"size_of" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"size_of generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -764,20 +752,16 @@ impl<'db> Evaluator<'db> {
|
|||
// FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89
|
||||
// (https://github.com/rust-lang/rust/pull/142410)
|
||||
"min_align_of" | "align_of" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"align_of generic arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
let align = self.layout(ty.to_nextsolver(interner))?.align.bytes();
|
||||
let align = self.layout(ty)?.align.bytes();
|
||||
destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size])
|
||||
}
|
||||
"size_of_val" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"size_of_val generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -798,9 +782,7 @@ impl<'db> Evaluator<'db> {
|
|||
// FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89
|
||||
// (https://github.com/rust-lang/rust/pull/142410)
|
||||
"min_align_of_val" | "align_of_val" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"align_of_val generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -819,9 +801,7 @@ impl<'db> Evaluator<'db> {
|
|||
}
|
||||
}
|
||||
"type_name" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"type_name generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -848,18 +828,12 @@ impl<'db> Evaluator<'db> {
|
|||
.write_from_bytes(self, &len.to_le_bytes())
|
||||
}
|
||||
"needs_drop" => {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"size_of generic arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
let result = match has_drop_glue(
|
||||
&self.infcx,
|
||||
ty.to_nextsolver(self.interner),
|
||||
self.trait_env.clone(),
|
||||
) {
|
||||
let result = match has_drop_glue(&self.infcx, ty, self.trait_env.clone()) {
|
||||
DropGlue::HasDropGlue => true,
|
||||
DropGlue::None => false,
|
||||
DropGlue::DependOnParams => {
|
||||
|
|
@ -922,9 +896,7 @@ impl<'db> Evaluator<'db> {
|
|||
let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false));
|
||||
let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false));
|
||||
let ans = lhs.wrapping_sub(rhs);
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"ptr_offset_from generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1013,13 +985,11 @@ impl<'db> Evaluator<'db> {
|
|||
"const_eval_select args are not provided".into(),
|
||||
));
|
||||
};
|
||||
let result_ty = TyKind::Tuple(
|
||||
2,
|
||||
Substitution::from_iter(Interner, [lhs.ty.clone(), TyBuilder::bool()]),
|
||||
)
|
||||
.intern(Interner);
|
||||
let op_size =
|
||||
self.size_of_sized(&lhs.ty, locals, "operand of add_with_overflow")?;
|
||||
let result_ty = Ty::new_tup_from_iter(
|
||||
self.interner(),
|
||||
[lhs.ty, Ty::new_bool(self.interner())].into_iter(),
|
||||
);
|
||||
let op_size = self.size_of_sized(lhs.ty, locals, "operand of add_with_overflow")?;
|
||||
let lhs = u128::from_le_bytes(pad16(lhs.get(self)?, false));
|
||||
let rhs = u128::from_le_bytes(pad16(rhs.get(self)?, false));
|
||||
let (ans, u128overflow) = match name {
|
||||
|
|
@ -1031,7 +1001,7 @@ impl<'db> Evaluator<'db> {
|
|||
let is_overflow = u128overflow
|
||||
|| ans.to_le_bytes()[op_size..].iter().any(|&it| it != 0 && it != 255);
|
||||
let is_overflow = vec![u8::from(is_overflow)];
|
||||
let layout = self.layout(result_ty.to_nextsolver(interner))?;
|
||||
let layout = self.layout(result_ty)?;
|
||||
let result = self.construct_with_layout(
|
||||
layout.size.bytes_usize(),
|
||||
&layout,
|
||||
|
|
@ -1048,9 +1018,7 @@ impl<'db> Evaluator<'db> {
|
|||
"copy_nonoverlapping args are not provided".into(),
|
||||
));
|
||||
};
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"copy_nonoverlapping generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1069,43 +1037,35 @@ impl<'db> Evaluator<'db> {
|
|||
return Err(MirEvalError::InternalError("offset args are not provided".into()));
|
||||
};
|
||||
let ty = if name == "offset" {
|
||||
let Some(ty0) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty0) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"offset generic arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
let Some(ty1) =
|
||||
generic_args.as_slice(Interner).get(1).and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty1) = generic_args.as_slice().get(1).and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"offset generic arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
if !matches!(
|
||||
ty1.as_builtin(),
|
||||
Some(
|
||||
BuiltinType::Int(BuiltinInt::Isize)
|
||||
| BuiltinType::Uint(BuiltinUint::Usize)
|
||||
)
|
||||
ty1.kind(),
|
||||
TyKind::Int(rustc_type_ir::IntTy::Isize)
|
||||
| TyKind::Uint(rustc_type_ir::UintTy::Usize)
|
||||
) {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"offset generic arg is not usize or isize".into(),
|
||||
));
|
||||
}
|
||||
match ty0.as_raw_ptr() {
|
||||
Some((ty, _)) => ty,
|
||||
None => {
|
||||
match ty0.kind() {
|
||||
TyKind::RawPtr(ty, _) => ty,
|
||||
_ => {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"offset generic arg is not a raw pointer".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"arith_offset generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1230,9 +1190,7 @@ impl<'db> Evaluator<'db> {
|
|||
"discriminant_value arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"discriminant_value generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1240,7 +1198,7 @@ impl<'db> Evaluator<'db> {
|
|||
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||
let size = self.size_of_sized(ty, locals, "discriminant_value ptr type")?;
|
||||
let interval = Interval { addr, size };
|
||||
let r = self.compute_discriminant(ty.clone(), interval.get(self)?)?;
|
||||
let r = self.compute_discriminant(ty, interval.get(self)?)?;
|
||||
destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])
|
||||
}
|
||||
"const_eval_select" => {
|
||||
|
|
@ -1250,14 +1208,13 @@ impl<'db> Evaluator<'db> {
|
|||
));
|
||||
};
|
||||
let mut args = vec![const_fn.clone()];
|
||||
let TyKind::Tuple(_, fields) = tuple.ty.kind(Interner) else {
|
||||
let TyKind::Tuple(fields) = tuple.ty.kind() else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"const_eval_select arg[0] is not a tuple".into(),
|
||||
));
|
||||
};
|
||||
let layout = self.layout(tuple.ty.to_nextsolver(interner))?;
|
||||
for (i, field) in fields.iter(Interner).enumerate() {
|
||||
let field = field.assert_ty_ref(Interner).clone();
|
||||
let layout = self.layout(tuple.ty)?;
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
let offset = layout.fields.offset(i).bytes_usize();
|
||||
let addr = tuple.interval.addr.offset(offset);
|
||||
args.push(IntervalAndTy::new(addr, field, self, locals)?);
|
||||
|
|
@ -1271,7 +1228,7 @@ impl<'db> Evaluator<'db> {
|
|||
def,
|
||||
&args,
|
||||
// FIXME: wrong for manual impls of `FnOnce`
|
||||
Substitution::empty(Interner),
|
||||
GenericArgs::new_from_iter(self.interner(), []),
|
||||
locals,
|
||||
destination,
|
||||
None,
|
||||
|
|
@ -1297,9 +1254,7 @@ impl<'db> Evaluator<'db> {
|
|||
));
|
||||
};
|
||||
let dst = Address::from_bytes(ptr.get(self)?)?;
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"write_via_copy generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1316,9 +1271,7 @@ impl<'db> Evaluator<'db> {
|
|||
};
|
||||
let count = from_bytes!(usize, count.get(self)?);
|
||||
let val = from_bytes!(u8, val.get(self)?);
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"write_bytes generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1346,16 +1299,14 @@ impl<'db> Evaluator<'db> {
|
|||
"three_way_compare args are not provided".into(),
|
||||
));
|
||||
};
|
||||
let Some(ty) =
|
||||
generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"three_way_compare generic arg is not provided".into(),
|
||||
));
|
||||
};
|
||||
let signed = match ty.as_builtin().unwrap() {
|
||||
BuiltinType::Int(_) => true,
|
||||
BuiltinType::Uint(_) => false,
|
||||
let signed = match ty.kind() {
|
||||
TyKind::Int(_) => true,
|
||||
TyKind::Uint(_) => false,
|
||||
_ => {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"three_way_compare expects an integral type".into(),
|
||||
|
|
@ -1379,8 +1330,8 @@ impl<'db> Evaluator<'db> {
|
|||
result = (l as i8).cmp(&(r as i8));
|
||||
}
|
||||
if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) {
|
||||
let ty = self.db.ty(e.into()).skip_binder().to_chalk(interner);
|
||||
let r = self.compute_discriminant(ty.clone(), &[result as i8 as u8])?;
|
||||
let ty = self.db.ty(e.into()).skip_binder();
|
||||
let r = self.compute_discriminant(ty, &[result as i8 as u8])?;
|
||||
destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?;
|
||||
Ok(())
|
||||
} else {
|
||||
|
|
@ -1409,38 +1360,37 @@ impl<'db> Evaluator<'db> {
|
|||
|
||||
fn size_align_of_unsized(
|
||||
&mut self,
|
||||
ty: &Ty,
|
||||
ty: Ty<'db>,
|
||||
metadata: Interval,
|
||||
locals: &Locals,
|
||||
locals: &Locals<'db>,
|
||||
) -> Result<'db, (usize, usize)> {
|
||||
let interner = DbInterner::new_with(self.db, None, None);
|
||||
Ok(match ty.kind(Interner) {
|
||||
Ok(match ty.kind() {
|
||||
TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1),
|
||||
TyKind::Slice(inner) => {
|
||||
let len = from_bytes!(usize, metadata.get(self)?);
|
||||
let (size, align) = self.size_align_of_sized(inner, locals, "slice inner type")?;
|
||||
(size * len, align)
|
||||
}
|
||||
TyKind::Dyn(_) => self.size_align_of_sized(
|
||||
&convert_ty_for_result(interner, self.vtable_map.ty_of_bytes(metadata.get(self)?)?),
|
||||
TyKind::Dynamic(..) => self.size_align_of_sized(
|
||||
self.vtable_map.ty_of_bytes(metadata.get(self)?)?,
|
||||
locals,
|
||||
"dyn concrete type",
|
||||
)?,
|
||||
TyKind::Adt(id, subst) => {
|
||||
let id = id.0;
|
||||
let layout = self.layout_adt(id, subst.clone())?;
|
||||
TyKind::Adt(adt_def, subst) => {
|
||||
let id = adt_def.def_id().0;
|
||||
let layout = self.layout_adt(id, subst)?;
|
||||
let id = match id {
|
||||
AdtId::StructId(s) => s,
|
||||
_ => not_supported!("unsized enum or union"),
|
||||
};
|
||||
let field_types = &self.db.field_types(id.into());
|
||||
let field_types = self.db.field_types_ns(id.into());
|
||||
let last_field_ty =
|
||||
field_types.iter().next_back().unwrap().1.clone().substitute(Interner, subst);
|
||||
field_types.iter().next_back().unwrap().1.instantiate(self.interner(), subst);
|
||||
let sized_part_size =
|
||||
layout.fields.offset(field_types.iter().count() - 1).bytes_usize();
|
||||
let sized_part_align = layout.align.bytes() as usize;
|
||||
let (unsized_part_size, unsized_part_align) =
|
||||
self.size_align_of_unsized(&last_field_ty, metadata, locals)?;
|
||||
self.size_align_of_unsized(last_field_ty, metadata, locals)?;
|
||||
let align = sized_part_align.max(unsized_part_align) as isize;
|
||||
let size = (sized_part_size + unsized_part_size) as isize;
|
||||
// Must add any necessary padding to `size`
|
||||
|
|
@ -1463,13 +1413,12 @@ impl<'db> Evaluator<'db> {
|
|||
fn exec_atomic_intrinsic(
|
||||
&mut self,
|
||||
name: &str,
|
||||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
generic_args: GenericArgs<'db>,
|
||||
destination: Interval,
|
||||
locals: &Locals,
|
||||
locals: &Locals<'db>,
|
||||
_span: MirSpan,
|
||||
) -> Result<'db, ()> {
|
||||
let interner = DbInterner::new_with(self.db, None, None);
|
||||
// We are a single threaded runtime with no UB checking and no optimization, so
|
||||
// we can implement atomic intrinsics as normal functions.
|
||||
|
||||
|
|
@ -1479,8 +1428,7 @@ impl<'db> Evaluator<'db> {
|
|||
|
||||
// The rest of atomic intrinsics have exactly one generic arg
|
||||
|
||||
let Some(ty) = generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"atomic intrinsic generic arg is not provided".into(),
|
||||
));
|
||||
|
|
@ -1562,12 +1510,11 @@ impl<'db> Evaluator<'db> {
|
|||
} else {
|
||||
(arg0_interval, false)
|
||||
};
|
||||
let result_ty = TyKind::Tuple(
|
||||
2,
|
||||
Substitution::from_iter(Interner, [ty.clone(), TyBuilder::bool()]),
|
||||
)
|
||||
.intern(Interner);
|
||||
let layout = self.layout(result_ty.to_nextsolver(interner))?;
|
||||
let result_ty = Ty::new_tup_from_iter(
|
||||
self.interner(),
|
||||
[ty, Ty::new_bool(self.interner())].into_iter(),
|
||||
);
|
||||
let layout = self.layout(result_ty)?;
|
||||
let result = self.construct_with_layout(
|
||||
layout.size.bytes_usize(),
|
||||
&layout,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::TyKind;
|
||||
use crate::consteval::try_const_usize;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -23,22 +22,20 @@ macro_rules! not_supported {
|
|||
}
|
||||
|
||||
impl<'db> Evaluator<'db> {
|
||||
fn detect_simd_ty(&self, ty: &Ty) -> Result<'db, (usize, Ty)> {
|
||||
match ty.kind(Interner) {
|
||||
TyKind::Adt(id, subst) => {
|
||||
let len = match subst.as_slice(Interner).get(1).and_then(|it| it.constant(Interner))
|
||||
{
|
||||
fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> {
|
||||
match ty.kind() {
|
||||
TyKind::Adt(adt_def, subst) => {
|
||||
let len = match subst.as_slice().get(1).and_then(|it| it.konst()) {
|
||||
Some(len) => len,
|
||||
_ => {
|
||||
if let AdtId::StructId(id) = id.0 {
|
||||
if let AdtId::StructId(id) = adt_def.def_id().0 {
|
||||
let struct_data = id.fields(self.db);
|
||||
let fields = struct_data.fields();
|
||||
let Some((first_field, _)) = fields.iter().next() else {
|
||||
not_supported!("simd type with no field");
|
||||
};
|
||||
let field_ty = self.db.field_types(id.into())[first_field]
|
||||
.clone()
|
||||
.substitute(Interner, subst);
|
||||
let field_ty = self.db.field_types_ns(id.into())[first_field]
|
||||
.instantiate(self.interner(), subst);
|
||||
return Ok((fields.len(), field_ty));
|
||||
}
|
||||
return Err(MirEvalError::InternalError(
|
||||
|
|
@ -48,14 +45,12 @@ impl<'db> Evaluator<'db> {
|
|||
};
|
||||
match try_const_usize(self.db, len) {
|
||||
Some(len) => {
|
||||
let Some(ty) =
|
||||
subst.as_slice(Interner).first().and_then(|it| it.ty(Interner))
|
||||
else {
|
||||
let Some(ty) = subst.as_slice().first().and_then(|it| it.ty()) else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"simd type with no ty param".into(),
|
||||
));
|
||||
};
|
||||
Ok((len as usize, ty.clone()))
|
||||
Ok((len as usize, ty))
|
||||
}
|
||||
None => Err(MirEvalError::InternalError(
|
||||
"simd type with unevaluatable len param".into(),
|
||||
|
|
@ -69,10 +64,10 @@ impl<'db> Evaluator<'db> {
|
|||
pub(super) fn exec_simd_intrinsic(
|
||||
&mut self,
|
||||
name: &str,
|
||||
args: &[IntervalAndTy],
|
||||
_generic_args: &Substitution,
|
||||
args: &[IntervalAndTy<'db>],
|
||||
_generic_args: GenericArgs<'db>,
|
||||
destination: Interval,
|
||||
_locals: &Locals,
|
||||
_locals: &Locals<'db>,
|
||||
_span: MirSpan,
|
||||
) -> Result<'db, ()> {
|
||||
match name {
|
||||
|
|
@ -99,8 +94,8 @@ impl<'db> Evaluator<'db> {
|
|||
let [left, right] = args else {
|
||||
return Err(MirEvalError::InternalError("simd args are not provided".into()));
|
||||
};
|
||||
let (len, ty) = self.detect_simd_ty(&left.ty)?;
|
||||
let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_)));
|
||||
let (len, ty) = self.detect_simd_ty(left.ty)?;
|
||||
let is_signed = matches!(ty.kind(), TyKind::Int(_));
|
||||
let size = left.interval.size / len;
|
||||
let dest_size = destination.size / len;
|
||||
let mut destination_bytes = vec![];
|
||||
|
|
@ -137,7 +132,7 @@ impl<'db> Evaluator<'db> {
|
|||
"simd_bitmask args are not provided".into(),
|
||||
));
|
||||
};
|
||||
let (op_len, _) = self.detect_simd_ty(&op.ty)?;
|
||||
let (op_len, _) = self.detect_simd_ty(op.ty)?;
|
||||
let op_count = op.interval.size / op_len;
|
||||
let mut result: u64 = 0;
|
||||
for (i, val) in op.get(self)?.chunks(op_count).enumerate() {
|
||||
|
|
@ -153,7 +148,7 @@ impl<'db> Evaluator<'db> {
|
|||
"simd_shuffle args are not provided".into(),
|
||||
));
|
||||
};
|
||||
let TyKind::Array(_, index_len) = index.ty.kind(Interner) else {
|
||||
let TyKind::Array(_, index_len) = index.ty.kind() else {
|
||||
return Err(MirEvalError::InternalError(
|
||||
"simd_shuffle index argument has non-array type".into(),
|
||||
));
|
||||
|
|
@ -166,7 +161,7 @@ impl<'db> Evaluator<'db> {
|
|||
));
|
||||
}
|
||||
};
|
||||
let (left_len, _) = self.detect_simd_ty(&left.ty)?;
|
||||
let (left_len, _) = self.detect_simd_ty(left.ty)?;
|
||||
let left_size = left.interval.size / left_len;
|
||||
let vector =
|
||||
left.get(self)?.chunks(left_size).chain(right.get(self)?.chunks(left_size));
|
||||
|
|
|
|||
|
|
@ -4,15 +4,20 @@ use span::Edition;
|
|||
use syntax::{TextRange, TextSize};
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use crate::display::DisplayTarget;
|
||||
use crate::{
|
||||
Interner, Substitution, db::HirDatabase, mir::MirLowerError, setup_tracing, test_db::TestDB,
|
||||
db::HirDatabase,
|
||||
display::DisplayTarget,
|
||||
mir::MirLowerError,
|
||||
next_solver::{DbInterner, GenericArgs},
|
||||
setup_tracing,
|
||||
test_db::TestDB,
|
||||
};
|
||||
|
||||
use super::{MirEvalError, interpret_mir};
|
||||
|
||||
fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> {
|
||||
crate::attach_db(db, || {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let module_id = db.module_for_file(file_id.file_id(db));
|
||||
let def_map = module_id.def_map(db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
|
|
@ -34,7 +39,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String),
|
|||
let body = db
|
||||
.monomorphized_mir_body(
|
||||
func_id.into(),
|
||||
Substitution::empty(Interner),
|
||||
GenericArgs::new_from_iter(interner, []),
|
||||
db.trait_environment(func_id.into()),
|
||||
)
|
||||
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
|
||||
|
|
@ -631,11 +636,16 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[ignore = "
|
||||
FIXME(next-solver):
|
||||
This does not work currently because I replaced homemade selection with selection by the trait solver;
|
||||
This will work once we implement `Interner::impl_specializes()` properly.
|
||||
"]
|
||||
#[test]
|
||||
fn specialization_array_clone() {
|
||||
check_pass(
|
||||
r#"
|
||||
//- minicore: copy, derive, slice, index, coerce_unsized
|
||||
//- minicore: copy, derive, slice, index, coerce_unsized, panic
|
||||
impl<T: Clone, const N: usize> Clone for [T; N] {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
|
|
@ -650,8 +660,7 @@ trait SpecArrayClone: Clone {
|
|||
impl<T: Clone> SpecArrayClone for T {
|
||||
#[inline]
|
||||
default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
|
||||
// FIXME: panic here when we actually implement specialization.
|
||||
from_slice(array)
|
||||
panic!("should go to the specialized impl")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,14 @@
|
|||
//! MIR lowering for places
|
||||
|
||||
use crate::mir::{MutBorrowKind, Operand, OperandKind};
|
||||
|
||||
use super::*;
|
||||
use hir_def::FunctionId;
|
||||
use intern::sym;
|
||||
use rustc_type_ir::inherent::{AdtDef, Region as _, Ty as _};
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
mir::{MutBorrowKind, Operand, OperandKind},
|
||||
next_solver::Region,
|
||||
};
|
||||
|
||||
macro_rules! not_supported {
|
||||
($it: expr) => {
|
||||
|
|
@ -16,8 +20,8 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
fn lower_expr_to_some_place_without_adjust(
|
||||
&mut self,
|
||||
expr_id: ExprId,
|
||||
prev_block: BasicBlockId,
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
prev_block: BasicBlockId<'db>,
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
let ty = self.expr_ty_without_adjust(expr_id);
|
||||
let place = self.temp(ty, prev_block, expr_id.into())?;
|
||||
let Some(current) =
|
||||
|
|
@ -31,12 +35,12 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
fn lower_expr_to_some_place_with_adjust(
|
||||
&mut self,
|
||||
expr_id: ExprId,
|
||||
prev_block: BasicBlockId,
|
||||
prev_block: BasicBlockId<'db>,
|
||||
adjustments: &[Adjustment<'db>],
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
let ty = adjustments
|
||||
.last()
|
||||
.map(|it| it.target.to_chalk(self.interner))
|
||||
.map(|it| it.target)
|
||||
.unwrap_or_else(|| self.expr_ty_without_adjust(expr_id));
|
||||
let place = self.temp(ty, prev_block, expr_id.into())?;
|
||||
let Some(current) =
|
||||
|
|
@ -49,11 +53,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
pub(super) fn lower_expr_as_place_with_adjust(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
current: BasicBlockId<'db>,
|
||||
expr_id: ExprId,
|
||||
upgrade_rvalue: bool,
|
||||
adjustments: &[Adjustment<'db>],
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| {
|
||||
if !upgrade_rvalue {
|
||||
return Err(MirLowerError::MutatingRvalue);
|
||||
|
|
@ -89,11 +93,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
current,
|
||||
r,
|
||||
rest.last()
|
||||
.map(|it| it.target.to_chalk(self.interner))
|
||||
.map(|it| it.target)
|
||||
.unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)),
|
||||
last.target.to_chalk(self.interner),
|
||||
last.target,
|
||||
expr_id.into(),
|
||||
match od.0.to_chalk(self.interner) {
|
||||
match od.0 {
|
||||
Some(Mutability::Mut) => true,
|
||||
Some(Mutability::Not) => false,
|
||||
None => {
|
||||
|
|
@ -111,10 +115,10 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
pub(super) fn lower_expr_as_place(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
current: BasicBlockId<'db>,
|
||||
expr_id: ExprId,
|
||||
upgrade_rvalue: bool,
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
match self.infer.expr_adjustments.get(&expr_id) {
|
||||
Some(a) => self.lower_expr_as_place_with_adjust(current, expr_id, upgrade_rvalue, a),
|
||||
None => self.lower_expr_as_place_without_adjust(current, expr_id, upgrade_rvalue),
|
||||
|
|
@ -123,10 +127,10 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
pub(super) fn lower_expr_as_place_without_adjust(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
current: BasicBlockId<'db>,
|
||||
expr_id: ExprId,
|
||||
upgrade_rvalue: bool,
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
let try_rvalue = |this: &mut MirLowerCtx<'_, 'db>| {
|
||||
if !upgrade_rvalue {
|
||||
return Err(MirLowerError::MutatingRvalue);
|
||||
|
|
@ -149,9 +153,13 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
}
|
||||
ValueNs::StaticId(s) => {
|
||||
let ty = self.expr_ty_without_adjust(expr_id);
|
||||
let ref_ty =
|
||||
TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner);
|
||||
let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into();
|
||||
let ref_ty = Ty::new_ref(
|
||||
self.interner(),
|
||||
Region::new_static(self.interner()),
|
||||
ty,
|
||||
Mutability::Not,
|
||||
);
|
||||
let temp: Place<'db> = self.temp(ref_ty, current, expr_id.into())?.into();
|
||||
self.push_assignment(
|
||||
current,
|
||||
temp,
|
||||
|
|
@ -167,10 +175,10 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
}
|
||||
}
|
||||
Expr::UnaryOp { expr, op: hir_def::hir::UnaryOp::Deref } => {
|
||||
let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) {
|
||||
TyKind::Ref(..) | TyKind::Raw(..) => true,
|
||||
let is_builtin = match self.expr_ty_without_adjust(*expr).kind() {
|
||||
TyKind::Ref(..) | TyKind::RawPtr(..) => true,
|
||||
TyKind::Adt(id, _) => {
|
||||
if let Some(lang_item) = self.db.lang_attr(id.0.into()) {
|
||||
if let Some(lang_item) = self.db.lang_attr(id.def_id().0.into()) {
|
||||
lang_item == LangItem::OwnedBox
|
||||
} else {
|
||||
false
|
||||
|
|
@ -219,9 +227,9 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
Expr::Index { base, index } => {
|
||||
let base_ty = self.expr_ty_after_adjustments(*base);
|
||||
let index_ty = self.expr_ty_after_adjustments(*index);
|
||||
if index_ty != TyBuilder::usize()
|
||||
if !matches!(index_ty.kind(), TyKind::Uint(rustc_ast_ir::UintTy::Usize))
|
||||
|| !matches!(
|
||||
base_ty.strip_reference().kind(Interner),
|
||||
base_ty.strip_reference().kind(),
|
||||
TyKind::Array(..) | TyKind::Slice(..)
|
||||
)
|
||||
{
|
||||
|
|
@ -230,7 +238,6 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
"[overloaded index]".to_owned(),
|
||||
));
|
||||
};
|
||||
let index_fn = (index_fn.0, index_fn.1.to_chalk(self.interner));
|
||||
let Some((base_place, current)) =
|
||||
self.lower_expr_as_place(current, *base, true)?
|
||||
else {
|
||||
|
|
@ -279,24 +286,26 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn lower_overloaded_index(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
place: Place,
|
||||
base_ty: Ty,
|
||||
result_ty: Ty,
|
||||
index_operand: Operand,
|
||||
current: BasicBlockId<'db>,
|
||||
place: Place<'db>,
|
||||
base_ty: Ty<'db>,
|
||||
result_ty: Ty<'db>,
|
||||
index_operand: Operand<'db>,
|
||||
span: MirSpan,
|
||||
index_fn: (FunctionId, Substitution),
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
index_fn: (FunctionId, GenericArgs<'db>),
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
let mutability = match base_ty.as_reference() {
|
||||
Some((_, _, mutability)) => mutability,
|
||||
None => Mutability::Not,
|
||||
};
|
||||
let result_ref = TyKind::Ref(mutability, error_lifetime(), result_ty).intern(Interner);
|
||||
let mut result: Place = self.temp(result_ref, current, span)?.into();
|
||||
let index_fn_op = Operand::const_zst(
|
||||
TyKind::FnDef(CallableDefId::FunctionId(index_fn.0).to_chalk(self.db), index_fn.1)
|
||||
.intern(Interner),
|
||||
);
|
||||
let result_ref =
|
||||
Ty::new_ref(self.interner(), Region::error(self.interner()), result_ty, mutability);
|
||||
let mut result: Place<'db> = self.temp(result_ref, current, span)?.into();
|
||||
let index_fn_op = Operand::const_zst(Ty::new_fn_def(
|
||||
self.interner(),
|
||||
CallableDefId::FunctionId(index_fn.0).into(),
|
||||
index_fn.1,
|
||||
));
|
||||
let Some(current) = self.lower_call(
|
||||
index_fn_op,
|
||||
Box::new([Operand { kind: OperandKind::Copy(place), span: None }, index_operand]),
|
||||
|
|
@ -314,14 +323,14 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn lower_overloaded_deref(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
place: Place,
|
||||
source_ty: Ty,
|
||||
target_ty: Ty,
|
||||
current: BasicBlockId<'db>,
|
||||
place: Place<'db>,
|
||||
source_ty: Ty<'db>,
|
||||
target_ty: Ty<'db>,
|
||||
span: MirSpan,
|
||||
mutability: bool,
|
||||
) -> Result<'db, Option<(Place, BasicBlockId)>> {
|
||||
let (chalk_mut, trait_lang_item, trait_method_name, borrow_kind) = if !mutability {
|
||||
) -> Result<'db, Option<(Place<'db>, BasicBlockId<'db>)>> {
|
||||
let (mutability, trait_lang_item, trait_method_name, borrow_kind) = if !mutability {
|
||||
(
|
||||
Mutability::Not,
|
||||
LangItem::Deref,
|
||||
|
|
@ -336,9 +345,10 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||
)
|
||||
};
|
||||
let ty_ref = TyKind::Ref(chalk_mut, error_lifetime(), source_ty.clone()).intern(Interner);
|
||||
let target_ty_ref = TyKind::Ref(chalk_mut, error_lifetime(), target_ty).intern(Interner);
|
||||
let ref_place: Place = self.temp(ty_ref, current, span)?.into();
|
||||
let error_region = Region::error(self.interner());
|
||||
let ty_ref = Ty::new_ref(self.interner(), error_region, source_ty, mutability);
|
||||
let target_ty_ref = Ty::new_ref(self.interner(), error_region, target_ty, mutability);
|
||||
let ref_place: Place<'db> = self.temp(ty_ref, current, span)?.into();
|
||||
self.push_assignment(current, ref_place, Rvalue::Ref(borrow_kind, place), span);
|
||||
let deref_trait = self
|
||||
.resolve_lang_item(trait_lang_item)?
|
||||
|
|
@ -348,14 +358,12 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
.trait_items(self.db)
|
||||
.method_by_name(&trait_method_name)
|
||||
.ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
|
||||
let deref_fn_op = Operand::const_zst(
|
||||
TyKind::FnDef(
|
||||
CallableDefId::FunctionId(deref_fn).to_chalk(self.db),
|
||||
Substitution::from1(Interner, source_ty),
|
||||
)
|
||||
.intern(Interner),
|
||||
);
|
||||
let mut result: Place = self.temp(target_ty_ref, current, span)?.into();
|
||||
let deref_fn_op = Operand::const_zst(Ty::new_fn_def(
|
||||
self.interner(),
|
||||
CallableDefId::FunctionId(deref_fn).into(),
|
||||
GenericArgs::new_from_iter(self.interner(), [source_ty.into()]),
|
||||
));
|
||||
let mut result: Place<'db> = self.temp(target_ty_ref, current, span)?.into();
|
||||
let Some(current) = self.lower_call(
|
||||
deref_fn_op,
|
||||
Box::new([Operand { kind: OperandKind::Copy(ref_place), span: None }]),
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
//! MIR lowering for patterns
|
||||
|
||||
use hir_def::{AssocItemId, hir::ExprId, signatures::VariantFields};
|
||||
use rustc_type_ir::inherent::{IntoKind, SliceLike, Ty as _};
|
||||
|
||||
use crate::next_solver::mapping::NextSolverToChalk;
|
||||
use crate::next_solver::GenericArgs;
|
||||
use crate::{
|
||||
BindingMode,
|
||||
mir::{
|
||||
LocalId, MutBorrowKind, Operand, OperandKind,
|
||||
lower::{
|
||||
BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner,
|
||||
MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, Place, PlaceElem,
|
||||
ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, Substitution,
|
||||
SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, ValueNs,
|
||||
VariantId,
|
||||
BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, MemoryMap,
|
||||
MirLowerCtx, MirLowerError, MirSpan, Pat, PatId, Place, PlaceElem, ProjectionElem,
|
||||
RecordFieldPat, ResolveValueResult, Result, Rvalue, SwitchTargets, TerminatorKind,
|
||||
TupleFieldId, TupleId, Ty, TyKind, ValueNs, VariantId,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -63,11 +63,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
/// so it should be an empty block.
|
||||
pub(super) fn pattern_match(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
current_else: Option<BasicBlockId>,
|
||||
cond_place: Place,
|
||||
current: BasicBlockId<'db>,
|
||||
current_else: Option<BasicBlockId<'db>>,
|
||||
cond_place: Place<'db>,
|
||||
pattern: PatId,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
let (current, current_else) = self.pattern_match_inner(
|
||||
current,
|
||||
current_else,
|
||||
|
|
@ -87,10 +87,10 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
pub(super) fn pattern_match_assignment(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
value: Place,
|
||||
current: BasicBlockId<'db>,
|
||||
value: Place<'db>,
|
||||
pattern: PatId,
|
||||
) -> Result<'db, BasicBlockId> {
|
||||
) -> Result<'db, BasicBlockId<'db>> {
|
||||
let (current, _) =
|
||||
self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?;
|
||||
Ok(current)
|
||||
|
|
@ -99,9 +99,9 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
pub(super) fn match_self_param(
|
||||
&mut self,
|
||||
id: BindingId,
|
||||
current: BasicBlockId,
|
||||
local: LocalId,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
current: BasicBlockId<'db>,
|
||||
local: LocalId<'db>,
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
self.pattern_match_binding(
|
||||
id,
|
||||
BindingMode::Move,
|
||||
|
|
@ -114,12 +114,12 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn pattern_match_inner(
|
||||
&mut self,
|
||||
mut current: BasicBlockId,
|
||||
mut current_else: Option<BasicBlockId>,
|
||||
mut cond_place: Place,
|
||||
mut current: BasicBlockId<'db>,
|
||||
mut current_else: Option<BasicBlockId<'db>>,
|
||||
mut cond_place: Place<'db>,
|
||||
pattern: PatId,
|
||||
mode: MatchingMode,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
|
||||
cond_place.projection = self.result.projection_store.intern(
|
||||
cond_place
|
||||
|
|
@ -135,8 +135,8 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
Pat::Missing => return Err(MirLowerError::IncompletePattern),
|
||||
Pat::Wild => (current, current_else),
|
||||
Pat::Tuple { args, ellipsis } => {
|
||||
let subst = match self.infer[pattern].to_chalk(self.interner).kind(Interner) {
|
||||
TyKind::Tuple(_, s) => s.clone(),
|
||||
let subst = match self.infer[pattern].kind() {
|
||||
TyKind::Tuple(s) => s,
|
||||
_ => {
|
||||
return Err(MirLowerError::TypeError(
|
||||
"non tuple type matched with tuple pattern",
|
||||
|
|
@ -148,7 +148,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
current_else,
|
||||
args,
|
||||
*ellipsis,
|
||||
(0..subst.len(Interner)).map(|i| {
|
||||
(0..subst.len()).map(|i| {
|
||||
PlaceElem::Field(Either::Right(TupleFieldId {
|
||||
tuple: TupleId(!0), // Dummy as it is unused
|
||||
index: i as u32,
|
||||
|
|
@ -209,14 +209,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
}
|
||||
Pat::Range { start, end } => {
|
||||
let mut add_check = |l: &ExprId, binop| -> Result<'db, ()> {
|
||||
let lv = self.lower_literal_or_const_to_operand(
|
||||
self.infer[pattern].to_chalk(self.interner),
|
||||
l,
|
||||
)?;
|
||||
let lv = self.lower_literal_or_const_to_operand(self.infer[pattern], l)?;
|
||||
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
|
||||
let next = self.new_basic_block();
|
||||
let discr: Place =
|
||||
self.temp(TyBuilder::bool(), current, pattern.into())?.into();
|
||||
let discr: Place<'db> =
|
||||
self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into();
|
||||
self.push_assignment(
|
||||
current,
|
||||
discr,
|
||||
|
|
@ -252,12 +249,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
Pat::Slice { prefix, slice, suffix } => {
|
||||
if mode == MatchingMode::Check {
|
||||
// emit runtime length check for slice
|
||||
if let TyKind::Slice(_) =
|
||||
self.infer[pattern].to_chalk(self.interner).kind(Interner)
|
||||
{
|
||||
if let TyKind::Slice(_) = self.infer[pattern].kind() {
|
||||
let pattern_len = prefix.len() + suffix.len();
|
||||
let place_len: Place =
|
||||
self.temp(TyBuilder::usize(), current, pattern.into())?.into();
|
||||
let place_len: Place<'db> = self
|
||||
.temp(Ty::new_usize(self.interner()), current, pattern.into())?
|
||||
.into();
|
||||
self.push_assignment(
|
||||
current,
|
||||
place_len,
|
||||
|
|
@ -287,10 +283,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
let c = Operand::from_concrete_const(
|
||||
pattern_len.to_le_bytes().into(),
|
||||
MemoryMap::default(),
|
||||
TyBuilder::usize(),
|
||||
Ty::new_usize(self.interner()),
|
||||
);
|
||||
let discr: Place =
|
||||
self.temp(TyBuilder::bool(), current, pattern.into())?.into();
|
||||
let discr: Place<'db> = self
|
||||
.temp(Ty::new_bool(self.interner()), current, pattern.into())?
|
||||
.into();
|
||||
self.push_assignment(
|
||||
current,
|
||||
discr,
|
||||
|
|
@ -398,26 +395,19 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern)
|
||||
&& let AssocItemId::ConstId(c) = x.0
|
||||
{
|
||||
break 'b (c, x.1.to_chalk(self.interner));
|
||||
break 'b (c, x.1);
|
||||
}
|
||||
if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr {
|
||||
break 'b (c, Substitution::empty(Interner));
|
||||
break 'b (c, GenericArgs::new_from_iter(self.interner(), []));
|
||||
}
|
||||
not_supported!("path in pattern position that is not const or variant")
|
||||
};
|
||||
let tmp: Place = self
|
||||
.temp(self.infer[pattern].to_chalk(self.interner), current, pattern.into())?
|
||||
.into();
|
||||
let tmp: Place<'db> =
|
||||
self.temp(self.infer[pattern], current, pattern.into())?.into();
|
||||
let span = pattern.into();
|
||||
self.lower_const(
|
||||
c.into(),
|
||||
current,
|
||||
tmp,
|
||||
subst,
|
||||
span,
|
||||
self.infer[pattern].to_chalk(self.interner),
|
||||
)?;
|
||||
let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into();
|
||||
self.lower_const(c.into(), current, tmp, subst, span)?;
|
||||
let tmp2: Place<'db> =
|
||||
self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into();
|
||||
self.push_assignment(
|
||||
current,
|
||||
tmp2,
|
||||
|
|
@ -444,10 +434,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
Pat::Lit(l) => match &self.body[*l] {
|
||||
Expr::Literal(l) => {
|
||||
if mode == MatchingMode::Check {
|
||||
let c = self.lower_literal_to_operand(
|
||||
self.infer[pattern].to_chalk(self.interner),
|
||||
l,
|
||||
)?;
|
||||
let c = self.lower_literal_to_operand(self.infer[pattern], l)?;
|
||||
self.pattern_match_const(current_else, current, c, cond_place, pattern)?
|
||||
} else {
|
||||
(current, current_else)
|
||||
|
|
@ -519,11 +506,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
&mut self,
|
||||
id: BindingId,
|
||||
mode: BindingMode,
|
||||
cond_place: Place,
|
||||
cond_place: Place<'db>,
|
||||
span: MirSpan,
|
||||
current: BasicBlockId,
|
||||
current_else: Option<BasicBlockId>,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
current: BasicBlockId<'db>,
|
||||
current_else: Option<BasicBlockId<'db>>,
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
let target_place = self.binding_local(id)?;
|
||||
self.push_storage_live(id, current)?;
|
||||
self.push_match_assignment(current, target_place, mode, cond_place, span);
|
||||
|
|
@ -532,10 +519,10 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn push_match_assignment(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
target_place: LocalId,
|
||||
current: BasicBlockId<'db>,
|
||||
target_place: LocalId<'db>,
|
||||
mode: BindingMode,
|
||||
cond_place: Place,
|
||||
cond_place: Place<'db>,
|
||||
span: MirSpan,
|
||||
) {
|
||||
self.push_assignment(
|
||||
|
|
@ -558,15 +545,16 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn pattern_match_const(
|
||||
&mut self,
|
||||
current_else: Option<BasicBlockId>,
|
||||
current: BasicBlockId,
|
||||
c: Operand,
|
||||
cond_place: Place,
|
||||
current_else: Option<BasicBlockId<'db>>,
|
||||
current: BasicBlockId<'db>,
|
||||
c: Operand<'db>,
|
||||
cond_place: Place<'db>,
|
||||
pattern: Idx<Pat>,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
let then_target = self.new_basic_block();
|
||||
let else_target = current_else.unwrap_or_else(|| self.new_basic_block());
|
||||
let discr: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into();
|
||||
let discr: Place<'db> =
|
||||
self.temp(Ty::new_bool(self.interner()), current, pattern.into())?.into();
|
||||
self.push_assignment(
|
||||
current,
|
||||
discr,
|
||||
|
|
@ -591,14 +579,14 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn pattern_matching_variant(
|
||||
&mut self,
|
||||
cond_place: Place,
|
||||
cond_place: Place<'db>,
|
||||
variant: VariantId,
|
||||
mut current: BasicBlockId,
|
||||
mut current: BasicBlockId<'db>,
|
||||
span: MirSpan,
|
||||
mut current_else: Option<BasicBlockId>,
|
||||
mut current_else: Option<BasicBlockId<'db>>,
|
||||
shape: AdtPatternShape<'_>,
|
||||
mode: MatchingMode,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
Ok(match variant {
|
||||
VariantId::EnumVariantId(v) => {
|
||||
if mode == MatchingMode::Check {
|
||||
|
|
@ -647,11 +635,11 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
shape: AdtPatternShape<'_>,
|
||||
variant_data: &VariantFields,
|
||||
v: VariantId,
|
||||
current: BasicBlockId,
|
||||
current_else: Option<BasicBlockId>,
|
||||
cond_place: &Place,
|
||||
current: BasicBlockId<'db>,
|
||||
current_else: Option<BasicBlockId<'db>>,
|
||||
cond_place: &Place<'db>,
|
||||
mode: MatchingMode,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
Ok(match shape {
|
||||
AdtPatternShape::Record { args } => {
|
||||
let it = args
|
||||
|
|
@ -690,12 +678,12 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn pattern_match_adt(
|
||||
&mut self,
|
||||
mut current: BasicBlockId,
|
||||
mut current_else: Option<BasicBlockId>,
|
||||
args: impl Iterator<Item = (PlaceElem, PatId)>,
|
||||
cond_place: &Place,
|
||||
mut current: BasicBlockId<'db>,
|
||||
mut current_else: Option<BasicBlockId<'db>>,
|
||||
args: impl Iterator<Item = (PlaceElem<'db>, PatId)>,
|
||||
cond_place: &Place<'db>,
|
||||
mode: MatchingMode,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
for (proj, arg) in args {
|
||||
let cond_place = cond_place.project(proj, &mut self.result.projection_store);
|
||||
(current, current_else) =
|
||||
|
|
@ -706,14 +694,14 @@ impl<'db> MirLowerCtx<'_, 'db> {
|
|||
|
||||
fn pattern_match_tuple_like(
|
||||
&mut self,
|
||||
current: BasicBlockId,
|
||||
current_else: Option<BasicBlockId>,
|
||||
current: BasicBlockId<'db>,
|
||||
current_else: Option<BasicBlockId<'db>>,
|
||||
args: &[PatId],
|
||||
ellipsis: Option<u32>,
|
||||
fields: impl DoubleEndedIterator<Item = PlaceElem> + Clone,
|
||||
cond_place: &Place,
|
||||
fields: impl DoubleEndedIterator<Item = PlaceElem<'db>> + Clone,
|
||||
cond_place: &Place<'db>,
|
||||
mode: MatchingMode,
|
||||
) -> Result<'db, (BasicBlockId, Option<BasicBlockId>)> {
|
||||
) -> Result<'db, (BasicBlockId<'db>, Option<BasicBlockId<'db>>)> {
|
||||
let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize));
|
||||
let it = al
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
use hir_def::db::DefDatabase;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::Edition;
|
||||
use test_fixture::WithFixture;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{db::HirDatabase, mir::MirBody, setup_tracing, test_db::TestDB};
|
||||
use crate::{db::HirDatabase, setup_tracing, test_db::TestDB};
|
||||
|
||||
fn lower_mir(
|
||||
#[rust_analyzer::rust_fixture] ra_fixture: &str,
|
||||
) -> FxHashMap<String, Result<Arc<MirBody>, ()>> {
|
||||
fn lower_mir(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
|
||||
let _tracing = setup_tracing();
|
||||
let (db, file_ids) = TestDB::with_many_files(ra_fixture);
|
||||
crate::attach_db(&db, || {
|
||||
|
|
@ -20,14 +14,9 @@ fn lower_mir(
|
|||
hir_def::ModuleDefId::FunctionId(it) => Some(it),
|
||||
_ => None,
|
||||
});
|
||||
funcs
|
||||
.map(|func| {
|
||||
let name =
|
||||
db.function_signature(func).name.display(&db, Edition::CURRENT).to_string();
|
||||
let mir = db.mir_body(func.into());
|
||||
(name, mir.map_err(drop))
|
||||
})
|
||||
.collect()
|
||||
for func in funcs {
|
||||
_ = db.mir_body(func.into());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,232 +7,129 @@
|
|||
//!
|
||||
//! So the monomorphization should be called even if the substitution is empty.
|
||||
|
||||
use std::mem;
|
||||
|
||||
use chalk_ir::{
|
||||
ConstData, DebruijnIndex,
|
||||
fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable},
|
||||
};
|
||||
use hir_def::DefWithBodyId;
|
||||
use rustc_type_ir::inherent::{IntoKind, SliceLike};
|
||||
use rustc_type_ir::{
|
||||
FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::next_solver::DbInterner;
|
||||
use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
|
||||
use crate::next_solver::{Const, ConstKind, Region, RegionKind};
|
||||
use crate::{
|
||||
Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind,
|
||||
consteval::{intern_const_scalar, unknown_const},
|
||||
db::{HirDatabase, InternedClosure, InternedClosureId},
|
||||
from_placeholder_idx,
|
||||
generics::{Generics, generics},
|
||||
infer::normalize,
|
||||
TraitEnvironment,
|
||||
db::{HirDatabase, InternedClosureId},
|
||||
next_solver::{
|
||||
DbInterner, GenericArgs, Ty, TyKind, TypingMode,
|
||||
infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause},
|
||||
obligation_ctxt::ObligationCtxt,
|
||||
references_non_lt_error,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind};
|
||||
|
||||
macro_rules! not_supported {
|
||||
($it: expr) => {
|
||||
return Err(MirLowerError::NotSupported(format!($it)))
|
||||
};
|
||||
struct Filler<'db> {
|
||||
infcx: InferCtxt<'db>,
|
||||
trait_env: Arc<TraitEnvironment<'db>>,
|
||||
subst: GenericArgs<'db>,
|
||||
}
|
||||
|
||||
struct Filler<'a, 'db> {
|
||||
db: &'db dyn HirDatabase,
|
||||
trait_env: Arc<TraitEnvironment<'db>>,
|
||||
subst: &'a Substitution,
|
||||
generics: Option<Generics>,
|
||||
interner: DbInterner<'db>,
|
||||
}
|
||||
impl<'a, 'db> FallibleTypeFolder<Interner> for Filler<'a, 'db> {
|
||||
impl<'db> FallibleTypeFolder<DbInterner<'db>> for Filler<'db> {
|
||||
type Error = MirLowerError<'db>;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
|
||||
self
|
||||
fn cx(&self) -> DbInterner<'db> {
|
||||
self.infcx.interner
|
||||
}
|
||||
|
||||
fn interner(&self) -> Interner {
|
||||
Interner
|
||||
}
|
||||
fn try_fold_ty(&mut self, ty: Ty<'db>) -> Result<Ty<'db>, Self::Error> {
|
||||
if !ty.has_type_flags(TypeFlags::HAS_ALIAS | TypeFlags::HAS_PARAM) {
|
||||
return Ok(ty);
|
||||
}
|
||||
|
||||
fn try_fold_ty(
|
||||
&mut self,
|
||||
ty: Ty,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> std::result::Result<Ty, Self::Error> {
|
||||
match ty.kind(Interner) {
|
||||
TyKind::AssociatedType(id, subst) => {
|
||||
// I don't know exactly if and why this is needed, but it looks like `normalize_ty` likes
|
||||
// this kind of associated types.
|
||||
Ok(TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
|
||||
associated_ty_id: *id,
|
||||
substitution: subst.clone().try_fold_with(self, outer_binder)?,
|
||||
}))
|
||||
.intern(Interner))
|
||||
match ty.kind() {
|
||||
TyKind::Alias(..) => {
|
||||
// First instantiate params.
|
||||
let ty = ty.try_super_fold_with(self)?;
|
||||
|
||||
let mut ocx = ObligationCtxt::new(&self.infcx);
|
||||
let ty = ocx
|
||||
.structurally_normalize_ty(&ObligationCause::dummy(), self.trait_env.env, ty)
|
||||
.map_err(|_| MirLowerError::NotSupported("can't normalize alias".to_owned()))?;
|
||||
ty.try_super_fold_with(self)
|
||||
}
|
||||
TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
|
||||
opaque_ty_id: id,
|
||||
substitution: subst,
|
||||
}))
|
||||
| TyKind::OpaqueType(id, subst) => {
|
||||
let impl_trait_id = self.db.lookup_intern_impl_trait_id((*id).into());
|
||||
let subst = subst.clone().try_fold_with(self.as_dyn(), outer_binder)?;
|
||||
match impl_trait_id {
|
||||
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
||||
let infer = self.db.infer(func.into());
|
||||
let filler = &mut Filler {
|
||||
db: self.db,
|
||||
trait_env: self.trait_env.clone(),
|
||||
subst: &subst,
|
||||
generics: Some(generics(self.db, func.into())),
|
||||
interner: self.interner,
|
||||
};
|
||||
filler.try_fold_ty(
|
||||
infer.type_of_rpit[idx.to_nextsolver(self.interner)]
|
||||
.to_chalk(self.interner),
|
||||
outer_binder,
|
||||
)
|
||||
}
|
||||
crate::ImplTraitId::TypeAliasImplTrait(..) => {
|
||||
not_supported!("type alias impl trait");
|
||||
}
|
||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
||||
not_supported!("async block impl trait");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ty.try_super_fold_with(self.as_dyn(), outer_binder),
|
||||
TyKind::Param(param) => Ok(self
|
||||
.subst
|
||||
.as_slice()
|
||||
.get(param.index as usize)
|
||||
.and_then(|arg| arg.ty())
|
||||
.ok_or_else(|| {
|
||||
MirLowerError::GenericArgNotProvided(param.id.into(), self.subst)
|
||||
})?),
|
||||
_ => ty.try_super_fold_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fold_free_placeholder_const(
|
||||
&mut self,
|
||||
_ty: chalk_ir::Ty<Interner>,
|
||||
idx: chalk_ir::PlaceholderIndex,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> std::result::Result<chalk_ir::Const<Interner>, Self::Error> {
|
||||
let it = from_placeholder_idx(self.db, idx).0;
|
||||
let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else {
|
||||
not_supported!("missing idx in generics");
|
||||
fn try_fold_const(&mut self, ct: Const<'db>) -> Result<Const<'db>, Self::Error> {
|
||||
let ConstKind::Param(param) = ct.kind() else {
|
||||
return ct.try_super_fold_with(self);
|
||||
};
|
||||
Ok(self
|
||||
.subst
|
||||
.as_slice(Interner)
|
||||
.get(idx)
|
||||
.and_then(|it| it.constant(Interner))
|
||||
.ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))?
|
||||
.clone())
|
||||
self.subst
|
||||
.as_slice()
|
||||
.get(param.index as usize)
|
||||
.and_then(|arg| arg.konst())
|
||||
.ok_or_else(|| MirLowerError::GenericArgNotProvided(param.id.into(), self.subst))
|
||||
}
|
||||
|
||||
fn try_fold_free_placeholder_ty(
|
||||
&mut self,
|
||||
idx: chalk_ir::PlaceholderIndex,
|
||||
_outer_binder: DebruijnIndex,
|
||||
) -> std::result::Result<Ty, Self::Error> {
|
||||
let it = from_placeholder_idx(self.db, idx).0;
|
||||
let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else {
|
||||
not_supported!("missing idx in generics");
|
||||
fn try_fold_region(&mut self, region: Region<'db>) -> Result<Region<'db>, Self::Error> {
|
||||
let RegionKind::ReEarlyParam(param) = region.kind() else {
|
||||
return Ok(region);
|
||||
};
|
||||
Ok(self
|
||||
.subst
|
||||
.as_slice(Interner)
|
||||
.get(idx)
|
||||
.and_then(|it| it.ty(Interner))
|
||||
.ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))?
|
||||
.clone())
|
||||
}
|
||||
|
||||
fn try_fold_const(
|
||||
&mut self,
|
||||
constant: chalk_ir::Const<Interner>,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Result<chalk_ir::Const<Interner>, Self::Error> {
|
||||
let next_ty = normalize(
|
||||
self.db,
|
||||
self.trait_env.clone(),
|
||||
constant.data(Interner).ty.clone().try_fold_with(self, outer_binder)?,
|
||||
);
|
||||
ConstData { ty: next_ty, value: constant.data(Interner).value.clone() }
|
||||
.intern(Interner)
|
||||
.try_super_fold_with(self, outer_binder)
|
||||
self.subst
|
||||
.as_slice()
|
||||
.get(param.index as usize)
|
||||
.and_then(|arg| arg.region())
|
||||
.ok_or_else(|| MirLowerError::GenericArgNotProvided(param.id.into(), self.subst))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'db> Filler<'a, 'db> {
|
||||
fn fill_ty(&mut self, ty: &mut Ty) -> Result<(), MirLowerError<'db>> {
|
||||
let tmp = mem::replace(ty, TyKind::Error.intern(Interner));
|
||||
*ty = normalize(
|
||||
self.db,
|
||||
self.trait_env.clone(),
|
||||
tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?,
|
||||
);
|
||||
Ok(())
|
||||
impl<'db> Filler<'db> {
|
||||
fn new(
|
||||
db: &'db dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment<'db>>,
|
||||
subst: GenericArgs<'db>,
|
||||
) -> Self {
|
||||
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
|
||||
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
|
||||
Self { infcx, trait_env: env, subst }
|
||||
}
|
||||
|
||||
fn fill_const(&mut self, c: &mut Const) -> Result<(), MirLowerError<'db>> {
|
||||
let tmp = mem::replace(c, unknown_const(c.data(Interner).ty.clone()));
|
||||
*c = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?;
|
||||
Ok(())
|
||||
fn fill<T: TypeFoldable<DbInterner<'db>> + Copy>(
|
||||
&mut self,
|
||||
t: &mut T,
|
||||
) -> Result<(), MirLowerError<'db>> {
|
||||
// Can't deep normalized as that'll try to normalize consts and fail.
|
||||
*t = t.try_fold_with(self)?;
|
||||
if references_non_lt_error(t) {
|
||||
Err(MirLowerError::NotSupported("monomorphization resulted in errors".to_owned()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_subst(&mut self, ty: &mut Substitution) -> Result<(), MirLowerError<'db>> {
|
||||
let tmp = mem::replace(ty, Substitution::empty(Interner));
|
||||
*ty = tmp.try_fold_with(self, DebruijnIndex::INNERMOST)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError<'db>> {
|
||||
fn fill_operand(&mut self, op: &mut Operand<'db>) -> Result<(), MirLowerError<'db>> {
|
||||
match &mut op.kind {
|
||||
OperandKind::Constant(c) => {
|
||||
match &c.data(Interner).value {
|
||||
chalk_ir::ConstValue::BoundVar(b) => {
|
||||
let resolved = self
|
||||
.subst
|
||||
.as_slice(Interner)
|
||||
.get(b.index)
|
||||
.ok_or_else(|| {
|
||||
MirLowerError::GenericArgNotProvided(
|
||||
self.generics
|
||||
.as_ref()
|
||||
.and_then(|it| it.iter().nth(b.index))
|
||||
.and_then(|(id, _)| match id {
|
||||
hir_def::GenericParamId::ConstParamId(id) => {
|
||||
Some(hir_def::TypeOrConstParamId::from(id))
|
||||
}
|
||||
hir_def::GenericParamId::TypeParamId(id) => {
|
||||
Some(hir_def::TypeOrConstParamId::from(id))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap(),
|
||||
self.subst.clone(),
|
||||
)
|
||||
})?
|
||||
.assert_const_ref(Interner);
|
||||
*c = resolved.clone();
|
||||
}
|
||||
chalk_ir::ConstValue::InferenceVar(_)
|
||||
| chalk_ir::ConstValue::Placeholder(_) => {}
|
||||
chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
|
||||
crate::ConstScalar::UnevaluatedConst(const_id, subst) => {
|
||||
let mut subst = subst.clone();
|
||||
self.fill_subst(&mut subst)?;
|
||||
*c = intern_const_scalar(
|
||||
crate::ConstScalar::UnevaluatedConst(*const_id, subst),
|
||||
c.data(Interner).ty.clone(),
|
||||
);
|
||||
}
|
||||
crate::ConstScalar::Bytes(_, _) | crate::ConstScalar::Unknown => (),
|
||||
},
|
||||
}
|
||||
self.fill_const(c)?;
|
||||
OperandKind::Constant { konst, ty } => {
|
||||
self.fill(konst)?;
|
||||
self.fill(ty)?;
|
||||
}
|
||||
OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError<'db>> {
|
||||
fn fill_body(&mut self, body: &mut MirBody<'db>) -> Result<(), MirLowerError<'db>> {
|
||||
for (_, l) in body.locals.iter_mut() {
|
||||
self.fill_ty(&mut l.ty)?;
|
||||
self.fill(&mut l.ty)?;
|
||||
}
|
||||
for (_, bb) in body.basic_blocks.iter_mut() {
|
||||
for statement in &mut bb.statements {
|
||||
|
|
@ -245,20 +142,20 @@ impl<'a, 'db> Filler<'a, 'db> {
|
|||
match ak {
|
||||
super::AggregateKind::Array(ty)
|
||||
| super::AggregateKind::Tuple(ty)
|
||||
| super::AggregateKind::Closure(ty) => self.fill_ty(ty)?,
|
||||
super::AggregateKind::Adt(_, subst) => self.fill_subst(subst)?,
|
||||
| super::AggregateKind::Closure(ty) => self.fill(ty)?,
|
||||
super::AggregateKind::Adt(_, subst) => self.fill(subst)?,
|
||||
super::AggregateKind::Union(_, _) => (),
|
||||
}
|
||||
}
|
||||
Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => {
|
||||
self.fill_ty(ty)?;
|
||||
self.fill(ty)?;
|
||||
}
|
||||
Rvalue::Use(op) => {
|
||||
self.fill_operand(op)?;
|
||||
}
|
||||
Rvalue::Repeat(op, len) => {
|
||||
self.fill_operand(op)?;
|
||||
self.fill_const(len)?;
|
||||
self.fill(len)?;
|
||||
}
|
||||
Rvalue::Ref(_, _)
|
||||
| Rvalue::Len(_)
|
||||
|
|
@ -312,12 +209,10 @@ impl<'a, 'db> Filler<'a, 'db> {
|
|||
pub fn monomorphized_mir_body_query<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
subst: Substitution,
|
||||
subst: GenericArgs<'db>,
|
||||
trait_env: Arc<crate::TraitEnvironment<'db>>,
|
||||
) -> Result<Arc<MirBody>, MirLowerError<'db>> {
|
||||
let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
|
||||
let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
|
||||
let filler = &mut Filler { db, subst: &subst, trait_env, generics, interner };
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
|
||||
let mut filler = Filler::new(db, trait_env, subst);
|
||||
let body = db.mir_body(owner)?;
|
||||
let mut body = (*body).clone();
|
||||
filler.fill_body(&mut body)?;
|
||||
|
|
@ -327,22 +222,19 @@ pub fn monomorphized_mir_body_query<'db>(
|
|||
pub(crate) fn monomorphized_mir_body_cycle_result<'db>(
|
||||
_db: &'db dyn HirDatabase,
|
||||
_: DefWithBodyId,
|
||||
_: Substitution,
|
||||
_: GenericArgs<'db>,
|
||||
_: Arc<crate::TraitEnvironment<'db>>,
|
||||
) -> Result<Arc<MirBody>, MirLowerError<'db>> {
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
|
||||
Err(MirLowerError::Loop)
|
||||
}
|
||||
|
||||
pub fn monomorphized_mir_body_for_closure_query<'db>(
|
||||
db: &'db dyn HirDatabase,
|
||||
closure: InternedClosureId,
|
||||
subst: Substitution,
|
||||
subst: GenericArgs<'db>,
|
||||
trait_env: Arc<crate::TraitEnvironment<'db>>,
|
||||
) -> Result<Arc<MirBody>, MirLowerError<'db>> {
|
||||
let InternedClosure(owner, _) = db.lookup_intern_closure(closure);
|
||||
let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
|
||||
let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
|
||||
let filler = &mut Filler { db, subst: &subst, trait_env, generics, interner };
|
||||
) -> Result<Arc<MirBody<'db>>, MirLowerError<'db>> {
|
||||
let mut filler = Filler::new(db, trait_env, subst);
|
||||
let body = db.mir_body_for_closure(closure)?;
|
||||
let mut body = (*body).clone();
|
||||
filler.fill_body(&mut body)?;
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ use hir_expand::{Lookup, name::Name};
|
|||
use la_arena::ArenaMap;
|
||||
|
||||
use crate::{
|
||||
ClosureId,
|
||||
db::HirDatabase,
|
||||
db::{HirDatabase, InternedClosureId},
|
||||
display::{ClosureStyle, DisplayTarget, HirDisplay},
|
||||
mir::{PlaceElem, ProjectionElem, StatementKind, TerminatorKind},
|
||||
};
|
||||
|
|
@ -37,8 +36,8 @@ macro_rules! wln {
|
|||
};
|
||||
}
|
||||
|
||||
impl MirBody {
|
||||
pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String {
|
||||
impl<'db> MirBody<'db> {
|
||||
pub fn pretty_print(&self, db: &'db dyn HirDatabase, display_target: DisplayTarget) -> String {
|
||||
let hir_body = db.body(self.owner);
|
||||
let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target);
|
||||
ctx.for_body(|this| match ctx.body.owner {
|
||||
|
|
@ -81,7 +80,7 @@ impl MirBody {
|
|||
|
||||
// String with lines is rendered poorly in `dbg` macros, which I use very much, so this
|
||||
// function exists to solve that.
|
||||
pub fn dbg(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> impl Debug {
|
||||
pub fn dbg(&self, db: &'db dyn HirDatabase, display_target: DisplayTarget) -> impl Debug {
|
||||
struct StringDbg(String);
|
||||
impl Debug for StringDbg {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
@ -92,17 +91,17 @@ impl MirBody {
|
|||
}
|
||||
}
|
||||
|
||||
struct MirPrettyCtx<'a> {
|
||||
body: &'a MirBody,
|
||||
struct MirPrettyCtx<'a, 'db> {
|
||||
body: &'a MirBody<'db>,
|
||||
hir_body: &'a Body,
|
||||
db: &'a dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
result: String,
|
||||
indent: String,
|
||||
local_to_binding: ArenaMap<LocalId, BindingId>,
|
||||
local_to_binding: ArenaMap<LocalId<'db>, BindingId>,
|
||||
display_target: DisplayTarget,
|
||||
}
|
||||
|
||||
impl Write for MirPrettyCtx<'_> {
|
||||
impl Write for MirPrettyCtx<'_, '_> {
|
||||
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||
let mut it = s.split('\n'); // note: `.lines()` is wrong here
|
||||
self.write(it.next().unwrap_or_default());
|
||||
|
|
@ -114,12 +113,12 @@ impl Write for MirPrettyCtx<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
enum LocalName {
|
||||
Unknown(LocalId),
|
||||
Binding(Name, LocalId),
|
||||
enum LocalName<'db> {
|
||||
Unknown(LocalId<'db>),
|
||||
Binding(Name, LocalId<'db>),
|
||||
}
|
||||
|
||||
impl HirDisplay for LocalName {
|
||||
impl<'db> HirDisplay for LocalName<'db> {
|
||||
fn hir_fmt(
|
||||
&self,
|
||||
f: &mut crate::display::HirFormatter<'_>,
|
||||
|
|
@ -133,8 +132,8 @@ impl HirDisplay for LocalName {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> MirPrettyCtx<'a> {
|
||||
fn for_body(&mut self, name: impl FnOnce(&mut MirPrettyCtx<'_>)) {
|
||||
impl<'a, 'db> MirPrettyCtx<'a, 'db> {
|
||||
fn for_body(&mut self, name: impl FnOnce(&mut MirPrettyCtx<'_, 'db>)) {
|
||||
name(self);
|
||||
self.with_block(|this| {
|
||||
this.locals();
|
||||
|
|
@ -146,8 +145,8 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn for_closure(&mut self, closure: ClosureId) {
|
||||
let body = match self.db.mir_body_for_closure(closure.into()) {
|
||||
fn for_closure(&mut self, closure: InternedClosureId) {
|
||||
let body = match self.db.mir_body_for_closure(closure) {
|
||||
Ok(it) => it,
|
||||
Err(e) => {
|
||||
wln!(self, "// error in {closure:?}: {e:?}");
|
||||
|
|
@ -168,7 +167,7 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
self.indent = ctx.indent;
|
||||
}
|
||||
|
||||
fn with_block(&mut self, f: impl FnOnce(&mut MirPrettyCtx<'_>)) {
|
||||
fn with_block(&mut self, f: impl FnOnce(&mut MirPrettyCtx<'_, 'db>)) {
|
||||
self.indent += " ";
|
||||
wln!(self, "{{");
|
||||
f(self);
|
||||
|
|
@ -180,9 +179,9 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
}
|
||||
|
||||
fn new(
|
||||
body: &'a MirBody,
|
||||
body: &'a MirBody<'db>,
|
||||
hir_body: &'a Body,
|
||||
db: &'a dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
display_target: DisplayTarget,
|
||||
) -> Self {
|
||||
let local_to_binding = body.local_to_binding_map();
|
||||
|
|
@ -217,14 +216,14 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn local_name(&self, local: LocalId) -> LocalName {
|
||||
fn local_name(&self, local: LocalId<'db>) -> LocalName<'db> {
|
||||
match self.local_to_binding.get(local) {
|
||||
Some(b) => LocalName::Binding(self.hir_body[*b].name.clone(), local),
|
||||
None => LocalName::Unknown(local),
|
||||
}
|
||||
}
|
||||
|
||||
fn basic_block_id(&self, basic_block_id: BasicBlockId) -> String {
|
||||
fn basic_block_id(&self, basic_block_id: BasicBlockId<'db>) -> String {
|
||||
format!("'bb{}", u32::from(basic_block_id.into_raw()))
|
||||
}
|
||||
|
||||
|
|
@ -312,8 +311,12 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn place(&mut self, p: &Place) {
|
||||
fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) {
|
||||
fn place(&mut self, p: &Place<'db>) {
|
||||
fn f<'db>(
|
||||
this: &mut MirPrettyCtx<'_, 'db>,
|
||||
local: LocalId<'db>,
|
||||
projections: &[PlaceElem<'db>],
|
||||
) {
|
||||
let Some((last, head)) = projections.split_last() else {
|
||||
// no projection
|
||||
w!(this, "{}", this.local_name(local).display_test(this.db, this.display_target));
|
||||
|
|
@ -373,19 +376,19 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
f(self, p.local, p.projection.lookup(&self.body.projection_store));
|
||||
}
|
||||
|
||||
fn operand(&mut self, r: &Operand) {
|
||||
fn operand(&mut self, r: &Operand<'db>) {
|
||||
match &r.kind {
|
||||
OperandKind::Copy(p) | OperandKind::Move(p) => {
|
||||
// MIR at the time of writing doesn't have difference between move and copy, so we show them
|
||||
// equally. Feel free to change it.
|
||||
self.place(p);
|
||||
}
|
||||
OperandKind::Constant(c) => w!(self, "Const({})", self.hir_display(c)),
|
||||
OperandKind::Constant { konst, .. } => w!(self, "Const({})", self.hir_display(konst)),
|
||||
OperandKind::Static(s) => w!(self, "Static({:?})", s),
|
||||
}
|
||||
}
|
||||
|
||||
fn rvalue(&mut self, r: &Rvalue) {
|
||||
fn rvalue(&mut self, r: &Rvalue<'db>) {
|
||||
match r {
|
||||
Rvalue::Use(op) => self.operand(op),
|
||||
Rvalue::Ref(r, p) => {
|
||||
|
|
@ -475,7 +478,7 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn operand_list(&mut self, it: &[Operand]) {
|
||||
fn operand_list(&mut self, it: &[Operand<'db>]) {
|
||||
let mut it = it.iter();
|
||||
if let Some(first) = it.next() {
|
||||
self.operand(first);
|
||||
|
|
@ -486,7 +489,10 @@ impl<'a> MirPrettyCtx<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn hir_display<T: HirDisplay>(&self, ty: &'a T) -> impl Display + 'a {
|
||||
fn hir_display<'b, T: HirDisplay>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T>
|
||||
where
|
||||
'db: 'b,
|
||||
{
|
||||
ty.display_test(self.db, self.display_target)
|
||||
.with_closure_style(ClosureStyle::ClosureWithSubst)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::hash::Hash;
|
|||
|
||||
use hir_def::{ConstParamId, TypeOrConstParamId};
|
||||
use intern::{Interned, Symbol};
|
||||
use macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_ast_ir::{try_visit, visit::VisitorResult};
|
||||
use rustc_type_ir::{
|
||||
BoundVar, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
|
||||
|
|
@ -23,7 +24,7 @@ use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder,
|
|||
pub type ConstKind<'db> = rustc_type_ir::ConstKind<DbInterner<'db>>;
|
||||
pub type UnevaluatedConst<'db> = rustc_type_ir::UnevaluatedConst<DbInterner<'db>>;
|
||||
|
||||
#[salsa::interned(constructor = new_, debug)]
|
||||
#[salsa::interned(constructor = new_)]
|
||||
pub struct Const<'db> {
|
||||
#[returns(ref)]
|
||||
kind_: InternedWrapperNoDebug<WithCachedTypeInfo<ConstKind<'db>>>,
|
||||
|
|
@ -61,6 +62,21 @@ impl<'db> Const<'db> {
|
|||
Const::new(interner, ConstKind::Placeholder(placeholder))
|
||||
}
|
||||
|
||||
pub fn new_valtree(
|
||||
interner: DbInterner<'db>,
|
||||
ty: Ty<'db>,
|
||||
memory: Box<[u8]>,
|
||||
memory_map: MemoryMap<'db>,
|
||||
) -> Self {
|
||||
Const::new(
|
||||
interner,
|
||||
ConstKind::Value(ValueConst {
|
||||
ty,
|
||||
value: Valtree::new(ConstBytes { memory, memory_map }),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_ct_infer(&self) -> bool {
|
||||
matches!(&self.inner().internee, ConstKind::Infer(_))
|
||||
}
|
||||
|
|
@ -77,6 +93,12 @@ impl<'db> Const<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db> std::fmt::Debug for Const<'db> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.inner().internee.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> std::fmt::Debug for InternedWrapperNoDebug<WithCachedTypeInfo<ConstKind<'db>>> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.internee.fmt(f)
|
||||
|
|
@ -135,9 +157,12 @@ impl ParamConst {
|
|||
/// A type-level constant value.
|
||||
///
|
||||
/// Represents a typed, fully evaluated constant.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TypeFoldable, TypeVisitable)]
|
||||
pub struct ValueConst<'db> {
|
||||
pub(crate) ty: Ty<'db>,
|
||||
// FIXME: Should we ignore this for TypeVisitable, TypeFoldable?
|
||||
#[type_visitable(ignore)]
|
||||
#[type_foldable(identity)]
|
||||
pub(crate) value: Valtree<'db>,
|
||||
}
|
||||
|
||||
|
|
@ -158,33 +183,15 @@ impl<'db> rustc_type_ir::inherent::ValueConst<DbInterner<'db>> for ValueConst<'d
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db> rustc_type_ir::TypeVisitable<DbInterner<'db>> for ValueConst<'db> {
|
||||
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
|
||||
&self,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
self.ty.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> rustc_type_ir::TypeFoldable<DbInterner<'db>> for ValueConst<'db> {
|
||||
fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
|
||||
ValueConst { ty: self.ty.fold_with(folder), value: self.value }
|
||||
}
|
||||
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(ValueConst { ty: self.ty.try_fold_with(folder)?, value: self.value })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ConstBytes<'db>(pub Box<[u8]>, pub MemoryMap<'db>);
|
||||
pub struct ConstBytes<'db> {
|
||||
pub memory: Box<[u8]>,
|
||||
pub memory_map: MemoryMap<'db>,
|
||||
}
|
||||
|
||||
impl Hash for ConstBytes<'_> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state)
|
||||
self.memory.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +219,7 @@ impl<'db> Valtree<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable)]
|
||||
pub struct ExprConst;
|
||||
|
||||
impl rustc_type_ir::inherent::ParamLike for ParamConst {
|
||||
|
|
@ -412,29 +419,6 @@ impl<'db> PlaceholderLike<DbInterner<'db>> for PlaceholderConst {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeVisitable<DbInterner<'db>> for ExprConst {
|
||||
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
|
||||
&self,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
// Ensure we get back to this when we fill in the fields
|
||||
let ExprConst = &self;
|
||||
V::Result::output()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeFoldable<DbInterner<'db>> for ExprConst {
|
||||
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(ExprConst)
|
||||
}
|
||||
fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
|
||||
ExprConst
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Relate<DbInterner<'db>> for ExprConst {
|
||||
fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
|
||||
relation: &mut R,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Definition of `SolverDefId`
|
||||
|
||||
use hir_def::{
|
||||
AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId,
|
||||
StaticId, StructId, TraitId, TypeAliasId, UnionId,
|
||||
AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId,
|
||||
ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
|
||||
};
|
||||
use rustc_type_ir::inherent;
|
||||
use stdx::impl_from;
|
||||
|
|
@ -119,6 +119,16 @@ impl From<GenericDefId> for SolverDefId {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<GeneralConstId> for SolverDefId {
|
||||
#[inline]
|
||||
fn from(value: GeneralConstId) -> Self {
|
||||
match value {
|
||||
GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id),
|
||||
GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SolverDefId> for GenericDefId {
|
||||
type Error = SolverDefId;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use hir_def::{GenericDefId, GenericParamId};
|
||||
use intern::{Interned, Symbol};
|
||||
use macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_type_ir::inherent::Const as _;
|
||||
use rustc_type_ir::{
|
||||
ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys,
|
||||
|
|
@ -23,7 +24,7 @@ use super::{
|
|||
interned_vec_db,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
|
||||
pub enum GenericArg<'db> {
|
||||
Ty(Ty<'db>),
|
||||
Lifetime(Region<'db>),
|
||||
|
|
@ -55,6 +56,13 @@ impl<'db> GenericArg<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn konst(self) -> Option<Const<'db>> {
|
||||
match self.kind() {
|
||||
GenericArgKind::Const(konst) => Some(konst),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn region(self) -> Option<Region<'db>> {
|
||||
match self.kind() {
|
||||
GenericArgKind::Lifetime(r) => Some(r),
|
||||
|
|
@ -72,7 +80,7 @@ impl<'db> From<Term<'db>> for GenericArg<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
|
||||
pub enum Term<'db> {
|
||||
Ty(Ty<'db>),
|
||||
Const(Const<'db>),
|
||||
|
|
@ -130,39 +138,6 @@ impl<'db> IntoKind for GenericArg<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeVisitable<DbInterner<'db>> for GenericArg<'db> {
|
||||
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
|
||||
&self,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
match self {
|
||||
GenericArg::Lifetime(lt) => lt.visit_with(visitor),
|
||||
GenericArg::Ty(ty) => ty.visit_with(visitor),
|
||||
GenericArg::Const(ct) => ct.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeFoldable<DbInterner<'db>> for GenericArg<'db> {
|
||||
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
match self.kind() {
|
||||
GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
|
||||
GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
|
||||
GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
|
||||
}
|
||||
}
|
||||
fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
|
||||
match self.kind() {
|
||||
GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
|
||||
GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
|
||||
GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Relate<DbInterner<'db>> for GenericArg<'db> {
|
||||
fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
|
||||
relation: &mut R,
|
||||
|
|
@ -553,36 +528,6 @@ impl<'db> From<Const<'db>> for Term<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeVisitable<DbInterner<'db>> for Term<'db> {
|
||||
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
|
||||
&self,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
match self {
|
||||
Term::Ty(ty) => ty.visit_with(visitor),
|
||||
Term::Const(ct) => ct.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeFoldable<DbInterner<'db>> for Term<'db> {
|
||||
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
match self.kind() {
|
||||
TermKind::Ty(ty) => ty.try_fold_with(folder).map(Into::into),
|
||||
TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
|
||||
}
|
||||
}
|
||||
fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
|
||||
match self.kind() {
|
||||
TermKind::Ty(ty) => ty.fold_with(folder).into(),
|
||||
TermKind::Const(ct) => ct.fold_with(folder).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Relate<DbInterner<'db>> for Term<'db> {
|
||||
fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
|
||||
relation: &mut R,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use hir_def::{ImplId, TraitId};
|
||||
use macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_type_ir::{
|
||||
Interner,
|
||||
solve::{BuiltinImplSource, CandidateSource, Certainty, inspect::ProbeKind},
|
||||
|
|
@ -177,7 +178,7 @@ pub type SelectionResult<'db, T> = Result<Option<T>, SelectionError<'db>>;
|
|||
/// ### The type parameter `N`
|
||||
///
|
||||
/// See explanation on `ImplSourceUserDefinedData`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
|
||||
pub enum ImplSource<'db, N> {
|
||||
/// ImplSource identifying a particular impl.
|
||||
UserDefined(ImplSourceUserDefinedData<'db, N>),
|
||||
|
|
@ -242,8 +243,10 @@ impl<'db, N> ImplSource<'db, N> {
|
|||
/// is `Obligation`, as one might expect. During codegen, however, this
|
||||
/// is `()`, because codegen only requires a shallow resolution of an
|
||||
/// impl, and nested obligations are satisfied later.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
|
||||
pub struct ImplSourceUserDefinedData<'db, N> {
|
||||
#[type_visitable(ignore)]
|
||||
#[type_foldable(identity)]
|
||||
pub impl_def_id: ImplId,
|
||||
pub args: GenericArgs<'db>,
|
||||
pub nested: Vec<N>,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use std::{
|
|||
};
|
||||
|
||||
use hir_def::TraitId;
|
||||
use macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_type_ir::elaborate::Elaboratable;
|
||||
use rustc_type_ir::{
|
||||
PredicatePolarity, Upcast,
|
||||
|
|
@ -65,8 +66,10 @@ impl ObligationCause {
|
|||
/// either identifying an `impl` (e.g., `impl Eq for i32`) that
|
||||
/// satisfies the obligation, or else finding a bound that is in
|
||||
/// scope. The eventual result is usually a `Selection` (defined below).
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, TypeVisitable, TypeFoldable)]
|
||||
pub struct Obligation<'db, T> {
|
||||
#[type_foldable(identity)]
|
||||
#[type_visitable(ignore)]
|
||||
/// The reason we have to prove this thing.
|
||||
pub cause: ObligationCause,
|
||||
|
||||
|
|
@ -117,39 +120,6 @@ impl<'db> Elaboratable<DbInterner<'db>> for PredicateObligation<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db, T: TypeVisitable<DbInterner<'db>>> TypeVisitable<DbInterner<'db>> for Obligation<'db, T> {
|
||||
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
|
||||
&self,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
rustc_ast_ir::try_visit!(self.param_env.visit_with(visitor));
|
||||
self.predicate.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db, T: TypeFoldable<DbInterner<'db>>> TypeFoldable<DbInterner<'db>> for Obligation<'db, T> {
|
||||
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(Obligation {
|
||||
cause: self.cause.clone(),
|
||||
param_env: self.param_env.try_fold_with(folder)?,
|
||||
predicate: self.predicate.try_fold_with(folder)?,
|
||||
recursion_depth: self.recursion_depth,
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
|
||||
Obligation {
|
||||
cause: self.cause.clone(),
|
||||
param_env: self.param_env.fold_with(folder),
|
||||
predicate: self.predicate.fold_with(folder),
|
||||
recursion_depth: self.recursion_depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db, T: Copy> Obligation<'db, T> {
|
||||
pub fn as_goal(&self) -> Goal<'db, T> {
|
||||
Goal { param_env: self.param_env, predicate: self.predicate }
|
||||
|
|
|
|||
|
|
@ -1,77 +1,81 @@
|
|||
//! Things related to the Interner in the next-trait-solver.
|
||||
#![allow(unused)]
|
||||
#![allow(unused)] // FIXME(next-solver): Remove this.
|
||||
|
||||
use std::{fmt, ops::ControlFlow};
|
||||
|
||||
pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db};
|
||||
|
||||
use base_db::Crate;
|
||||
use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances};
|
||||
use hir_def::lang_item::LangItem;
|
||||
use hir_def::signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags};
|
||||
use hir_def::{AdtId, BlockId, GenericDefId, TypeAliasId, VariantId};
|
||||
use hir_def::{AttrDefId, Lookup};
|
||||
use hir_def::{CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId};
|
||||
use hir_def::{
|
||||
AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, GenericDefId, ItemContainerId, Lookup,
|
||||
StructId, TypeAliasId, UnionId, VariantId,
|
||||
lang_item::LangItem,
|
||||
signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags},
|
||||
};
|
||||
use intern::sym::non_exhaustive;
|
||||
use intern::{Interned, impl_internable, sym};
|
||||
use la_arena::Idx;
|
||||
use rustc_abi::{Align, ReprFlags, ReprOptions};
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_type_ir::elaborate::elaborate;
|
||||
use rustc_type_ir::error::TypeError;
|
||||
use rustc_type_ir::inherent::{
|
||||
AdtDef as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike as _, Span as _,
|
||||
};
|
||||
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
use rustc_type_ir::solve::SizedTraitKind;
|
||||
use rustc_index::{IndexVec, bit_set::DenseBitSet};
|
||||
use rustc_type_ir::{
|
||||
AliasTerm, AliasTermKind, AliasTy, AliasTyKind, EarlyBinder, FlagComputation, Flags,
|
||||
ImplPolarity, InferTy, ProjectionPredicate, TraitPredicate, TraitRef, Upcast,
|
||||
AliasTerm, AliasTermKind, AliasTy, AliasTyKind, BoundVar, CollectAndApply, DebruijnIndex,
|
||||
EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy,
|
||||
ProjectionPredicate, RegionKind, TermKind, TraitPredicate, TraitRef, TypeVisitableExt,
|
||||
UniverseIndex, Upcast, Variance, WithCachedTypeInfo,
|
||||
elaborate::{self, elaborate},
|
||||
error::TypeError,
|
||||
inherent::{
|
||||
self, AdtDef as _, Const as _, GenericArgs as _, GenericsOf, IntoKind, ParamEnv as _,
|
||||
Region as _, SliceLike as _, Span as _, Ty as _,
|
||||
},
|
||||
ir_print,
|
||||
lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem},
|
||||
relate,
|
||||
solve::SizedTraitKind,
|
||||
};
|
||||
use salsa::plumbing::AsId;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use std::fmt;
|
||||
use std::ops::ControlFlow;
|
||||
use syntax::ast::SelfParamKind;
|
||||
use tracing::debug;
|
||||
use triomphe::Arc;
|
||||
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_type_ir::TypeVisitableExt;
|
||||
use rustc_type_ir::{
|
||||
BoundVar, CollectAndApply, DebruijnIndex, GenericArgKind, RegionKind, TermKind, UniverseIndex,
|
||||
Variance, WithCachedTypeInfo, elaborate,
|
||||
inherent::{self, Const as _, Region as _, Ty as _},
|
||||
ir_print, relate,
|
||||
use crate::{
|
||||
ConstScalar, FnAbi, Interner,
|
||||
db::HirDatabase,
|
||||
lower_nextsolver::{self, TyLoweringContext},
|
||||
method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint},
|
||||
next_solver::{
|
||||
AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
|
||||
CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug,
|
||||
RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper,
|
||||
TypingMode,
|
||||
infer::{
|
||||
DbInternerInferExt, InferCtxt,
|
||||
traits::{Obligation, ObligationCause},
|
||||
},
|
||||
obligation_ctxt::ObligationCtxt,
|
||||
util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::lower_nextsolver::{self, TyLoweringContext};
|
||||
use crate::method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint};
|
||||
use crate::next_solver::infer::InferCtxt;
|
||||
use crate::next_solver::util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls};
|
||||
use crate::next_solver::{
|
||||
AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
|
||||
CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug,
|
||||
RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper,
|
||||
};
|
||||
use crate::{ConstScalar, FnAbi, Interner, db::HirDatabase};
|
||||
|
||||
use super::generics::generics;
|
||||
use super::util::sizedness_constraint_for_ty;
|
||||
use super::{
|
||||
Binder, BoundExistentialPredicate, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause,
|
||||
Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints,
|
||||
ClauseKind, Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints,
|
||||
ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv,
|
||||
ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate,
|
||||
PredicateKind, Term, Ty, TyKind, Tys, ValueConst,
|
||||
PredicateKind, SolverDefId, Term, Ty, TyKind, Tys, Valtree, ValueConst,
|
||||
abi::Safety,
|
||||
fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate},
|
||||
generics::Generics,
|
||||
generics::{Generics, generics},
|
||||
mapping::ChalkToNextSolver,
|
||||
region::{
|
||||
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region,
|
||||
},
|
||||
util::sizedness_constraint_for_ty,
|
||||
};
|
||||
use super::{ClauseKind, SolverDefId, Valtree};
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
|
|
@ -1102,7 +1106,15 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
|
|||
fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy<Self>) -> AliasTyKind {
|
||||
match alias.def_id {
|
||||
SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque,
|
||||
SolverDefId::TypeAliasId(_) => AliasTyKind::Projection,
|
||||
SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container {
|
||||
ItemContainerId::ImplId(impl_)
|
||||
if self.db.impl_signature(impl_).target_trait.is_none() =>
|
||||
{
|
||||
AliasTyKind::Inherent
|
||||
}
|
||||
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => AliasTyKind::Projection,
|
||||
_ => AliasTyKind::Free,
|
||||
},
|
||||
_ => unimplemented!("Unexpected alias: {:?}", alias.def_id),
|
||||
}
|
||||
}
|
||||
|
|
@ -1113,7 +1125,19 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
|
|||
) -> rustc_type_ir::AliasTermKind {
|
||||
match alias.def_id {
|
||||
SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy,
|
||||
SolverDefId::TypeAliasId(_) => AliasTermKind::ProjectionTy,
|
||||
SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container {
|
||||
ItemContainerId::ImplId(impl_)
|
||||
if self.db.impl_signature(impl_).target_trait.is_none() =>
|
||||
{
|
||||
AliasTermKind::InherentTy
|
||||
}
|
||||
ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => {
|
||||
AliasTermKind::ProjectionTy
|
||||
}
|
||||
_ => AliasTermKind::FreeTy,
|
||||
},
|
||||
// rustc creates an `AnonConst` for consts, and evaluates them with CTFE (normalizing projections
|
||||
// via selection, similar to ours `find_matching_impl()`, and not with the trait solver), so mimic it.
|
||||
SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst,
|
||||
_ => unimplemented!("Unexpected alias: {:?}", alias.def_id),
|
||||
}
|
||||
|
|
@ -1676,8 +1700,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
|
|||
}
|
||||
|
||||
fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool {
|
||||
// FIXME
|
||||
false
|
||||
self.db.impl_signature(impl_def_id.0).is_default()
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self), ret)]
|
||||
|
|
@ -1731,7 +1754,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
|
|||
}
|
||||
|
||||
fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed {
|
||||
panic!("Bug encountered in next-trait-solver.")
|
||||
panic!("Bug encountered in next-trait-solver: {}", msg.to_string())
|
||||
}
|
||||
|
||||
fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool {
|
||||
|
|
@ -1929,7 +1952,12 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
|
|||
false
|
||||
}
|
||||
|
||||
fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool {
|
||||
// FIXME(next-solver): Make this a query? Can this make cycles?
|
||||
fn impl_specializes(
|
||||
self,
|
||||
specializing_impl_def_id: Self::ImplId,
|
||||
parent_impl_def_id: Self::ImplId,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const<Interner> {
|
|||
ConstScalar::Bytes(bytes, memory) => {
|
||||
rustc_type_ir::ConstKind::Value(ValueConst::new(
|
||||
data.ty.to_nextsolver(interner),
|
||||
ConstBytes(bytes.clone(), memory.clone()),
|
||||
ConstBytes { memory: bytes.clone(), memory_map: memory.clone() },
|
||||
))
|
||||
}
|
||||
ConstScalar::UnevaluatedConst(c, subst) => {
|
||||
|
|
@ -1710,8 +1710,10 @@ pub fn convert_const_for_result<'db>(
|
|||
let bytes = value_const.value.inner();
|
||||
let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
|
||||
// SAFETY: we will never actually use this without a database
|
||||
interned: ConstScalar::Bytes(bytes.0.clone(), unsafe {
|
||||
std::mem::transmute::<MemoryMap<'db>, MemoryMap<'static>>(bytes.1.clone())
|
||||
interned: ConstScalar::Bytes(bytes.memory.clone(), unsafe {
|
||||
std::mem::transmute::<MemoryMap<'db>, MemoryMap<'static>>(
|
||||
bytes.memory_map.clone(),
|
||||
)
|
||||
}),
|
||||
});
|
||||
return chalk_ir::ConstData {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use intern::Interned;
|
||||
use macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_ast_ir::try_visit;
|
||||
use rustc_type_ir::{
|
||||
self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags,
|
||||
|
|
@ -424,7 +425,7 @@ impl<'db> rustc_type_ir::TypeSuperVisitable<DbInterner<'db>> for Clauses<'db> {
|
|||
pub struct Clause<'db>(pub(crate) Predicate<'db>);
|
||||
|
||||
// We could cram the reveal into the clauses like rustc does, probably
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, TypeVisitable, TypeFoldable)]
|
||||
pub struct ParamEnv<'db> {
|
||||
pub(crate) clauses: Clauses<'db>,
|
||||
}
|
||||
|
|
@ -435,28 +436,6 @@ impl<'db> ParamEnv<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeVisitable<DbInterner<'db>> for ParamEnv<'db> {
|
||||
fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
|
||||
&self,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
try_visit!(self.clauses.visit_with(visitor));
|
||||
V::Result::output()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TypeFoldable<DbInterner<'db>> for ParamEnv<'db> {
|
||||
fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(ParamEnv { clauses: self.clauses.try_fold_with(folder)? })
|
||||
}
|
||||
fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
|
||||
ParamEnv { clauses: self.clauses.fold_with(folder) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> rustc_type_ir::inherent::ParamEnv<DbInterner<'db>> for ParamEnv<'db> {
|
||||
fn caller_bounds(self) -> impl rustc_type_ir::inherent::SliceLike<Item = Clause<'db>> {
|
||||
self.clauses
|
||||
|
|
|
|||
|
|
@ -149,13 +149,9 @@ impl<'db> SolverDelegate for SolverContext<'db> {
|
|||
fn fetch_eligible_assoc_item(
|
||||
&self,
|
||||
goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
|
||||
trait_assoc_def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
|
||||
trait_assoc_def_id: SolverDefId,
|
||||
impl_id: ImplIdWrapper,
|
||||
) -> Result<Option<<Self::Interner as rustc_type_ir::Interner>::DefId>, ErrorGuaranteed> {
|
||||
let trait_assoc_id = match trait_assoc_def_id {
|
||||
SolverDefId::TypeAliasId(id) => id,
|
||||
_ => panic!("Unexpected SolverDefId"),
|
||||
};
|
||||
) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
|
||||
let trait_ = self
|
||||
.0
|
||||
.interner
|
||||
|
|
@ -167,18 +163,47 @@ impl<'db> SolverDelegate for SolverContext<'db> {
|
|||
.def_id
|
||||
.0;
|
||||
let trait_data = trait_.trait_items(self.0.interner.db());
|
||||
let id =
|
||||
impl_id.0.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> {
|
||||
match item {
|
||||
(_, AssocItemId::TypeAliasId(type_alias)) => {
|
||||
let name = &self.0.interner.db().type_alias_signature(*type_alias).name;
|
||||
let found_trait_assoc_id = trait_data.associated_type_by_name(name)?;
|
||||
(found_trait_assoc_id == trait_assoc_id).then_some(*type_alias)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
});
|
||||
Ok(id.map(SolverDefId::TypeAliasId))
|
||||
let impl_items = impl_id.0.impl_items(self.0.interner.db());
|
||||
let id = match trait_assoc_def_id {
|
||||
SolverDefId::TypeAliasId(trait_assoc_id) => {
|
||||
let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id);
|
||||
impl_items
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|(impl_assoc_name, impl_assoc_id)| {
|
||||
if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id
|
||||
&& *impl_assoc_name == trait_assoc_data.name
|
||||
{
|
||||
Some(impl_assoc_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(SolverDefId::TypeAliasId)
|
||||
}
|
||||
SolverDefId::ConstId(trait_assoc_id) => {
|
||||
let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id);
|
||||
let trait_assoc_name = trait_assoc_data
|
||||
.name
|
||||
.as_ref()
|
||||
.expect("unnamed consts should not get passed to the solver");
|
||||
impl_items
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|(impl_assoc_name, impl_assoc_id)| {
|
||||
if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id
|
||||
&& impl_assoc_name == trait_assoc_name
|
||||
{
|
||||
Some(impl_assoc_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(SolverDefId::ConstId)
|
||||
}
|
||||
_ => panic!("Unexpected SolverDefId"),
|
||||
};
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn is_transmutable(
|
||||
|
|
@ -200,9 +225,9 @@ impl<'db> SolverDelegate for SolverContext<'db> {
|
|||
SolverDefId::StaticId(c) => GeneralConstId::StaticId(c),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let subst = uv.args.to_chalk(self.interner);
|
||||
let subst = uv.args;
|
||||
let ec = self.cx().db.const_eval(c, subst, None).ok()?;
|
||||
Some(ec.to_nextsolver(self.interner))
|
||||
Some(ec)
|
||||
}
|
||||
|
||||
fn compute_goal_fast_path(
|
||||
|
|
|
|||
|
|
@ -8,11 +8,10 @@ use hir_def::{AdtId, GenericDefId, TypeOrConstParamId, TypeParamId};
|
|||
use intern::{Interned, Symbol, sym};
|
||||
use rustc_abi::{Float, Integer, Size};
|
||||
use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
|
||||
use rustc_type_ir::TyVid;
|
||||
use rustc_type_ir::{
|
||||
BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy,
|
||||
IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo,
|
||||
IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, WithCachedTypeInfo,
|
||||
inherent::{
|
||||
Abi, AdtDef as _, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike,
|
||||
PlaceholderLike, Safety as _, SliceLike, Ty as _,
|
||||
|
|
@ -24,14 +23,13 @@ use rustc_type_ir::{
|
|||
use salsa::plumbing::{AsId, FromId};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::next_solver::{AdtDef, Binder};
|
||||
use crate::{
|
||||
FnAbi,
|
||||
db::HirDatabase,
|
||||
interner::InternedWrapperNoDebug,
|
||||
next_solver::{
|
||||
CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, GenericArg,
|
||||
PolyFnSig, TypeAliasIdWrapper,
|
||||
AdtDef, Binder, CallableIdWrapper, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig,
|
||||
GenericArg, PolyFnSig, Region, TypeAliasIdWrapper,
|
||||
abi::Safety,
|
||||
util::{CoroutineArgsExt, IntegerTypeExt},
|
||||
},
|
||||
|
|
@ -392,7 +390,7 @@ impl<'db> Ty<'db> {
|
|||
|
||||
/// Whether the type contains some non-lifetime, aka. type or const, error type.
|
||||
pub fn references_non_lt_error(self) -> bool {
|
||||
self.references_error() && self.visit_with(&mut ReferencesNonLifetimeError).is_break()
|
||||
references_non_lt_error(&self)
|
||||
}
|
||||
|
||||
pub fn callable_sig(self, interner: DbInterner<'db>) -> Option<Binder<'db, FnSig<'db>>> {
|
||||
|
|
@ -409,6 +407,13 @@ impl<'db> Ty<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_reference(self) -> Option<(Ty<'db>, Region<'db>, Mutability)> {
|
||||
match self.kind() {
|
||||
TyKind::Ref(lifetime, ty, mutability) => Some((ty, lifetime, mutability)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_reference_or_ptr(self) -> Option<(Ty<'db>, Rawness, Mutability)> {
|
||||
match self.kind() {
|
||||
TyKind::Ref(_, ty, mutability) => Some((ty, Rawness::Ref, mutability)),
|
||||
|
|
@ -417,6 +422,18 @@ impl<'db> Ty<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn strip_references(self) -> Ty<'db> {
|
||||
let mut t = self;
|
||||
while let TyKind::Ref(_lifetime, ty, _mutability) = t.kind() {
|
||||
t = ty;
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
pub fn strip_reference(self) -> Ty<'db> {
|
||||
self.as_reference().map_or(self, |(ty, _, _)| ty)
|
||||
}
|
||||
|
||||
/// Replace infer vars with errors.
|
||||
///
|
||||
/// This needs to be called for every type that may contain infer vars and is yielded to outside inference,
|
||||
|
|
@ -428,6 +445,10 @@ impl<'db> Ty<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn references_non_lt_error<'db, T: TypeVisitableExt<DbInterner<'db>>>(t: &T) -> bool {
|
||||
t.references_error() && t.visit_with(&mut ReferencesNonLifetimeError).is_break()
|
||||
}
|
||||
|
||||
struct ReferencesNonLifetimeError;
|
||||
|
||||
impl<'db> TypeVisitor<DbInterner<'db>> for ReferencesNonLifetimeError {
|
||||
|
|
|
|||
|
|
@ -20,11 +20,10 @@ use hir_expand::name::Name;
|
|||
use intern::sym;
|
||||
use rustc_abi::TargetDataLayout;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustc_type_ir::inherent::{GenericArgs, IntoKind, SliceLike};
|
||||
use rustc_type_ir::inherent::{IntoKind, SliceLike};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use span::Edition;
|
||||
|
||||
use crate::next_solver::mapping::NextSolverToChalk;
|
||||
use crate::{
|
||||
ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef,
|
||||
TraitRefExt, Ty,
|
||||
|
|
@ -34,7 +33,7 @@ use crate::{
|
|||
mir::pad16,
|
||||
next_solver::{
|
||||
DbInterner,
|
||||
mapping::{ChalkToNextSolver, convert_args_for_result},
|
||||
mapping::{ChalkToNextSolver, NextSolverToChalk, convert_args_for_result},
|
||||
},
|
||||
to_chalk_trait_id,
|
||||
};
|
||||
|
|
@ -196,15 +195,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
|
|||
pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution);
|
||||
|
||||
impl<'a> ClosureSubst<'a> {
|
||||
pub(crate) fn parent_subst(&self, db: &dyn HirDatabase) -> Substitution {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let subst =
|
||||
<Substitution as ChalkToNextSolver<crate::next_solver::GenericArgs<'_>>>::to_nextsolver(
|
||||
self.0, interner,
|
||||
);
|
||||
subst.split_closure_args().parent_args.to_chalk(interner)
|
||||
}
|
||||
|
||||
pub(crate) fn sig_ty(&self, db: &dyn HirDatabase) -> Ty {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let subst =
|
||||
|
|
@ -310,10 +300,12 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
|
|||
if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value
|
||||
&& let ConstScalar::UnevaluatedConst(id, subst) = &c.interned
|
||||
{
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
return Ok(eval);
|
||||
let interner = DbInterner::conjure();
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.to_nextsolver(interner), None) {
|
||||
return Ok(eval.to_chalk(interner));
|
||||
} else {
|
||||
return Ok(unknown_const(constant.data(Interner).ty.clone()));
|
||||
return Ok(unknown_const(constant.data(Interner).ty.to_nextsolver(interner))
|
||||
.to_chalk(interner));
|
||||
}
|
||||
}
|
||||
Ok(constant)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ use hir_ty::{
|
|||
GenericArgData, Interner, ParamKind, ProjectionTy, QuantifiedWhereClause, Scalar, Substitution,
|
||||
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic,
|
||||
ValueTyDefId, WhereClause, all_super_traits, autoderef, check_orphan_rules,
|
||||
consteval::{ConstExt, try_const_usize, unknown_const_as_generic},
|
||||
consteval_chalk::{ConstExt, try_const_usize, unknown_const_as_generic},
|
||||
diagnostics::BodyValidationDiagnostic,
|
||||
direct_super_traits, error_lifetime, known_const_to_ast,
|
||||
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
|
||||
|
|
@ -2153,8 +2153,11 @@ impl DefWithBody {
|
|||
mir::MirSpan::Unknown => continue,
|
||||
};
|
||||
acc.push(
|
||||
MovedOutOfRef { ty: Type::new_for_crate(krate, moof.ty.clone()), span }
|
||||
.into(),
|
||||
MovedOutOfRef {
|
||||
ty: Type::new_for_crate(krate, moof.ty.to_chalk(interner)),
|
||||
span,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
let mol = &borrowck_result.mutability_of_locals;
|
||||
|
|
@ -2649,9 +2652,10 @@ impl Function {
|
|||
db: &dyn HirDatabase,
|
||||
span_formatter: impl Fn(FileId, TextRange) -> String,
|
||||
) -> Result<String, ConstEvalError<'_>> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let body = db.monomorphized_mir_body(
|
||||
self.id.into(),
|
||||
Substitution::empty(Interner),
|
||||
GenericArgs::new_from_iter(interner, []),
|
||||
db.trait_environment(self.id.into()),
|
||||
)?;
|
||||
let (result, output) = interpret_mir(db, body, false, None)?;
|
||||
|
|
@ -2933,8 +2937,10 @@ impl Const {
|
|||
|
||||
/// Evaluate the constant.
|
||||
pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst, ConstEvalError<'_>> {
|
||||
db.const_eval(self.id.into(), Substitution::empty(Interner), None)
|
||||
.map(|it| EvaluatedConst { const_: it, def: self.id.into() })
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().to_chalk(interner);
|
||||
db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None)
|
||||
.map(|it| EvaluatedConst { const_: it.to_chalk(interner), def: self.id.into(), ty })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2947,6 +2953,7 @@ impl HasVisibility for Const {
|
|||
pub struct EvaluatedConst {
|
||||
def: DefWithBodyId,
|
||||
const_: hir_ty::Const,
|
||||
ty: hir_ty::Ty,
|
||||
}
|
||||
|
||||
impl EvaluatedConst {
|
||||
|
|
@ -2955,6 +2962,7 @@ impl EvaluatedConst {
|
|||
}
|
||||
|
||||
pub fn render_debug<'db>(&self, db: &'db dyn HirDatabase) -> Result<String, MirEvalError<'db>> {
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let data = self.const_.data(Interner);
|
||||
if let TyKind::Scalar(s) = data.ty.kind(Interner)
|
||||
&& matches!(s, Scalar::Int(_) | Scalar::Uint(_))
|
||||
|
|
@ -2972,7 +2980,12 @@ impl EvaluatedConst {
|
|||
return Ok(result);
|
||||
}
|
||||
}
|
||||
mir::render_const_using_debug_impl(db, self.def, &self.const_)
|
||||
mir::render_const_using_debug_impl(
|
||||
db,
|
||||
self.def,
|
||||
self.const_.to_nextsolver(interner),
|
||||
self.ty.to_nextsolver(interner),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3011,8 +3024,10 @@ impl Static {
|
|||
|
||||
/// Evaluate the static initializer.
|
||||
pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst, ConstEvalError<'_>> {
|
||||
db.const_eval(self.id.into(), Substitution::empty(Interner), None)
|
||||
.map(|it| EvaluatedConst { const_: it, def: self.id.into() })
|
||||
let interner = DbInterner::new_with(db, None, None);
|
||||
let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().to_chalk(interner);
|
||||
db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None)
|
||||
.map(|it| EvaluatedConst { const_: it.to_chalk(interner), def: self.id.into(), ty })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ use hir_expand::{
|
|||
mod_path::{ModPath, PathKind, path},
|
||||
name::{AsName, Name},
|
||||
};
|
||||
use hir_ty::next_solver::GenericArgs;
|
||||
use hir_ty::{
|
||||
Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy,
|
||||
Substitution, ToChalk, TraitEnvironment, Ty, TyKind, TyLoweringContext,
|
||||
|
|
@ -47,7 +46,8 @@ use hir_ty::{
|
|||
lang_items::lang_items_for_bin_op,
|
||||
method_resolution,
|
||||
next_solver::{
|
||||
DbInterner,
|
||||
DbInterner, GenericArgs, TypingMode,
|
||||
infer::DbInternerInferExt,
|
||||
mapping::{ChalkToNextSolver, NextSolverToChalk},
|
||||
},
|
||||
};
|
||||
|
|
@ -1439,12 +1439,9 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
None => return (const_id, subs),
|
||||
};
|
||||
let env = db.trait_environment_for_body(owner);
|
||||
method_resolution::lookup_impl_const(
|
||||
DbInterner::new_with(db, None, None),
|
||||
env,
|
||||
const_id,
|
||||
subs,
|
||||
)
|
||||
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
|
||||
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
|
||||
method_resolution::lookup_impl_const(&infcx, env, const_id, subs)
|
||||
}
|
||||
|
||||
fn lang_trait_fn(
|
||||
|
|
|
|||
|
|
@ -6306,6 +6306,8 @@ const FOO$0: (&str, &str) = {
|
|||
);
|
||||
}
|
||||
|
||||
// FIXME(next-solver): this fails to normalize the const, probably due to the solver
|
||||
// refusing to give the impl because of the error type.
|
||||
#[test]
|
||||
fn hover_const_eval_in_generic_trait() {
|
||||
// Doesn't compile, but we shouldn't crash.
|
||||
|
|
@ -6327,12 +6329,16 @@ fn test() {
|
|||
*FOO*
|
||||
|
||||
```rust
|
||||
ra_test_fixture::S
|
||||
ra_test_fixture::Trait
|
||||
```
|
||||
|
||||
```rust
|
||||
const FOO: bool = true
|
||||
const FOO: bool = false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
`Self` = `S<{unknown}>`
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//! }
|
||||
//! ```
|
||||
use hir::{
|
||||
ChalkTyInterner, DefWithBody,
|
||||
DefWithBody,
|
||||
db::{DefDatabase as _, HirDatabase as _},
|
||||
mir::{MirSpan, TerminatorKind},
|
||||
};
|
||||
|
|
@ -46,7 +46,7 @@ pub(super) fn hints(
|
|||
if !place.projection.is_empty() {
|
||||
continue; // Ignore complex cases for now
|
||||
}
|
||||
if mir.locals[place.local].ty.adt_id(ChalkTyInterner).is_none() {
|
||||
if mir.locals[place.local].ty.as_adt().is_none() {
|
||||
continue; // Arguably only ADTs have significant drop impls
|
||||
}
|
||||
let Some(&binding_idx) = local_to_binding.get(place.local) else {
|
||||
|
|
|
|||
19
src/tools/rust-analyzer/crates/macros/Cargo.toml
Normal file
19
src/tools/rust-analyzer/crates/macros/Cargo.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "macros"
|
||||
version = "0.0.0"
|
||||
repository.workspace = true
|
||||
description = "Proc macros for rust-analyzer."
|
||||
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = "2.0.9"
|
||||
synstructure = "0.13.0"
|
||||
164
src/tools/rust-analyzer/crates/macros/src/lib.rs
Normal file
164
src/tools/rust-analyzer/crates/macros/src/lib.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
//! Proc macros for rust-analyzer.
|
||||
|
||||
use quote::{ToTokens, quote};
|
||||
use syn::parse_quote;
|
||||
use synstructure::decl_derive;
|
||||
|
||||
decl_derive!(
|
||||
[TypeFoldable, attributes(type_foldable)] =>
|
||||
/// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported).
|
||||
///
|
||||
/// The fold will produce a value of the same struct or enum variant as the input, with
|
||||
/// each field respectively folded using the `TypeFoldable` implementation for its type.
|
||||
/// However, if a field of a struct or an enum variant is annotated with
|
||||
/// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its
|
||||
/// type is not required to implement `TypeFoldable`).
|
||||
type_foldable_derive
|
||||
);
|
||||
decl_derive!(
|
||||
[TypeVisitable, attributes(type_visitable)] =>
|
||||
/// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported).
|
||||
///
|
||||
/// Each field of the struct or enum variant will be visited in definition order, using the
|
||||
/// `TypeVisitable` implementation for its type. However, if a field of a struct or an enum
|
||||
/// variant is annotated with `#[type_visitable(ignore)]` then that field will not be
|
||||
/// visited (and its type is not required to implement `TypeVisitable`).
|
||||
type_visitable_derive
|
||||
);
|
||||
|
||||
fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
if let syn::Data::Union(_) = s.ast().data {
|
||||
panic!("cannot derive on union")
|
||||
}
|
||||
|
||||
// ignore fields with #[type_visitable(ignore)]
|
||||
s.filter(|bi| {
|
||||
let mut ignored = false;
|
||||
|
||||
bi.ast().attrs.iter().for_each(|attr| {
|
||||
if !attr.path().is_ident("type_visitable") {
|
||||
return;
|
||||
}
|
||||
let _ = attr.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("ignore") {
|
||||
ignored = true;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
|
||||
!ignored
|
||||
});
|
||||
|
||||
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "db") {
|
||||
s.add_impl_generic(parse_quote! { 'db });
|
||||
}
|
||||
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
let body_visit = s.each(|bind| {
|
||||
quote! {
|
||||
match ::rustc_type_ir::VisitorResult::branch(
|
||||
::rustc_type_ir::TypeVisitable::visit_with(#bind, __visitor)
|
||||
) {
|
||||
::core::ops::ControlFlow::Continue(()) => {},
|
||||
::core::ops::ControlFlow::Break(r) => {
|
||||
return ::rustc_type_ir::VisitorResult::from_residual(r);
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
s.bind_with(|_| synstructure::BindStyle::Move);
|
||||
|
||||
s.bound_impl(
|
||||
quote!(::rustc_type_ir::TypeVisitable<::hir_ty::next_solver::DbInterner<'db>>),
|
||||
quote! {
|
||||
fn visit_with<__V: ::rustc_type_ir::TypeVisitor<::hir_ty::next_solver::DbInterner<'db>>>(
|
||||
&self,
|
||||
__visitor: &mut __V
|
||||
) -> __V::Result {
|
||||
match *self { #body_visit }
|
||||
<__V::Result as ::rustc_type_ir::VisitorResult>::output()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
if let syn::Data::Union(_) = s.ast().data {
|
||||
panic!("cannot derive on union")
|
||||
}
|
||||
|
||||
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "db") {
|
||||
s.add_impl_generic(parse_quote! { 'db });
|
||||
}
|
||||
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.bind_with(|_| synstructure::BindStyle::Move);
|
||||
let try_body_fold = s.each_variant(|vi| {
|
||||
let bindings = vi.bindings();
|
||||
vi.construct(|_, index| {
|
||||
let bind = &bindings[index];
|
||||
|
||||
// retain value of fields with #[type_foldable(identity)]
|
||||
if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
|
||||
bind.to_token_stream()
|
||||
} else {
|
||||
quote! {
|
||||
::rustc_type_ir::TypeFoldable::try_fold_with(#bind, __folder)?
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let body_fold = s.each_variant(|vi| {
|
||||
let bindings = vi.bindings();
|
||||
vi.construct(|_, index| {
|
||||
let bind = &bindings[index];
|
||||
|
||||
// retain value of fields with #[type_foldable(identity)]
|
||||
if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
|
||||
bind.to_token_stream()
|
||||
} else {
|
||||
quote! {
|
||||
::rustc_type_ir::TypeFoldable::fold_with(#bind, __folder)
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
s.bound_impl(
|
||||
quote!(::rustc_type_ir::TypeFoldable<::hir_ty::next_solver::DbInterner<'db>>),
|
||||
quote! {
|
||||
fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder<::hir_ty::next_solver::DbInterner<'db>>>(
|
||||
self,
|
||||
__folder: &mut __F
|
||||
) -> Result<Self, __F::Error> {
|
||||
Ok(match self { #try_body_fold })
|
||||
}
|
||||
|
||||
fn fold_with<__F: ::rustc_type_ir::TypeFolder<::hir_ty::next_solver::DbInterner<'db>>>(
|
||||
self,
|
||||
__folder: &mut __F
|
||||
) -> Self {
|
||||
match self { #body_fold }
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool {
|
||||
let mut ignored = false;
|
||||
attrs.iter().for_each(|attr| {
|
||||
if !attr.path().is_ident(name) {
|
||||
return;
|
||||
}
|
||||
let _ = attr.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident(meta) {
|
||||
ignored = true;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
|
||||
ignored
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue