mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
Implement recursion in mir interpreter without recursion
This commit is contained in:
parent
3a1054fc1c
commit
4a444e768c
15 changed files with 432 additions and 264 deletions
|
@ -18,7 +18,7 @@ use crate::{
|
|||
generics::GenericParams,
|
||||
import_map::ImportMap,
|
||||
item_tree::{AttrOwner, ItemTree},
|
||||
lang_item::{LangItem, LangItemTarget, LangItems},
|
||||
lang_item::{self, LangItem, LangItemTarget, LangItems},
|
||||
nameres::{diagnostics::DefDiagnostic, DefMap},
|
||||
visibility::{self, Visibility},
|
||||
AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
|
||||
|
@ -204,6 +204,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
|||
#[salsa::invoke(AttrsWithOwner::attrs_query)]
|
||||
fn attrs(&self, def: AttrDefId) -> Attrs;
|
||||
|
||||
#[salsa::invoke(lang_item::lang_attr_query)]
|
||||
fn lang_attr(&self, def: AttrDefId) -> Option<LangItem>;
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke(AttrsWithOwner::attrs_with_owner)]
|
||||
fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner;
|
||||
|
|
|
@ -180,15 +180,15 @@ impl LangItems {
|
|||
T: Into<AttrDefId> + Copy,
|
||||
{
|
||||
let _p = profile::span("collect_lang_item");
|
||||
if let Some(lang_item) = lang_attr(db, item) {
|
||||
if let Some(lang_item) = db.lang_attr(item.into()) {
|
||||
self.items.entry(lang_item).or_insert_with(|| constructor(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lang_attr(db: &dyn DefDatabase, item: impl Into<AttrDefId> + Copy) -> Option<LangItem> {
|
||||
let attrs = db.attrs(item.into());
|
||||
attrs.by_key("lang").string_value().cloned().and_then(|it| LangItem::from_str(&it))
|
||||
pub(crate) fn lang_attr_query(db: &dyn DefDatabase, item: AttrDefId) -> Option<LangItem> {
|
||||
let attrs = db.attrs(item);
|
||||
attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(&it))
|
||||
}
|
||||
|
||||
pub enum GenericRequirement {
|
||||
|
|
|
@ -11,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
|
|||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
hir::Movability,
|
||||
lang_item::{lang_attr, LangItem, LangItemTarget},
|
||||
lang_item::{LangItem, LangItemTarget},
|
||||
AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId,
|
||||
};
|
||||
use hir_expand::name::name;
|
||||
|
@ -565,7 +565,7 @@ pub(crate) fn trait_datum_query(
|
|||
let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
|
||||
let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();
|
||||
let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses };
|
||||
let well_known = lang_attr(db.upcast(), trait_).and_then(well_known_trait_from_lang_item);
|
||||
let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item);
|
||||
let trait_datum = TraitDatum {
|
||||
id: trait_id,
|
||||
binders: make_binders(db, &generic_params, trait_datum_bound),
|
||||
|
|
|
@ -228,7 +228,7 @@ pub(crate) fn const_eval_query(
|
|||
}
|
||||
GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
|
||||
};
|
||||
let c = interpret_mir(db, &body, false).0?;
|
||||
let c = interpret_mir(db, body, false).0?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ pub(crate) fn const_eval_static_query(
|
|||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def.into()),
|
||||
)?;
|
||||
let c = interpret_mir(db, &body, false).0?;
|
||||
let c = interpret_mir(db, body, false).0?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ pub(crate) fn const_eval_discriminant_variant(
|
|||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def),
|
||||
)?;
|
||||
let c = interpret_mir(db, &mir_body, false).0?;
|
||||
let c = interpret_mir(db, mir_body, false).0?;
|
||||
let c = try_const_usize(db, &c).unwrap() as i128;
|
||||
Ok(c)
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ pub(crate) fn eval_to_const(
|
|||
}
|
||||
let infer = ctx.clone().resolve_all();
|
||||
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) {
|
||||
if let Ok(result) = interpret_mir(db, &mir_body, true).0 {
|
||||
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ mod intrinsics;
|
|||
|
||||
fn simplify(e: ConstEvalError) -> ConstEvalError {
|
||||
match e {
|
||||
ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e, _, _)) => {
|
||||
ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => {
|
||||
simplify(ConstEvalError::MirEvalError(*e))
|
||||
}
|
||||
_ => e,
|
||||
|
@ -2471,7 +2471,7 @@ fn exec_limits() {
|
|||
}
|
||||
const GOAL: i32 = f(0);
|
||||
"#,
|
||||
|e| e == ConstEvalError::MirEvalError(MirEvalError::StackOverflow),
|
||||
|e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded),
|
||||
);
|
||||
// Reasonable code should still work
|
||||
check_number(
|
||||
|
|
|
@ -110,6 +110,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[salsa::invoke(crate::layout::target_data_layout_query)]
|
||||
fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
|
||||
|
||||
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
|
||||
fn lookup_impl_method(
|
||||
&self,
|
||||
env: Arc<crate::TraitEnvironment>,
|
||||
func: FunctionId,
|
||||
fn_subst: Substitution,
|
||||
) -> (FunctionId, Substitution);
|
||||
|
||||
#[salsa::invoke(crate::lower::callable_item_sig)]
|
||||
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ use hir_def::{
|
|||
generics::{
|
||||
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||
},
|
||||
lang_item::{lang_attr, LangItem},
|
||||
lang_item::LangItem,
|
||||
nameres::MacroSubNs,
|
||||
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
|
||||
resolver::{HasResolver, Resolver, TypeNs},
|
||||
|
@ -1012,7 +1012,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// (So ideally, we'd only ignore `~const Drop` here)
|
||||
// - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until
|
||||
// the builtin impls are supported by Chalk, we ignore them here.
|
||||
if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) {
|
||||
if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) {
|
||||
if matches!(lang, LangItem::Drop | LangItem::Destruct) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -682,7 +682,7 @@ pub fn is_dyn_method(
|
|||
/// Looks up the impl method that actually runs for the trait method `func`.
|
||||
///
|
||||
/// Returns `func` if it's not a method defined in a trait or the lookup failed.
|
||||
pub fn lookup_impl_method(
|
||||
pub(crate) fn lookup_impl_method_query(
|
||||
db: &dyn HirDatabase,
|
||||
env: Arc<TraitEnvironment>,
|
||||
func: FunctionId,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -32,7 +32,7 @@ impl Evaluator<'_> {
|
|||
def: FunctionId,
|
||||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<bool> {
|
||||
|
@ -168,7 +168,7 @@ impl Evaluator<'_> {
|
|||
|
||||
fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
|
||||
use LangItem::*;
|
||||
let candidate = lang_attr(self.db.upcast(), def)?;
|
||||
let candidate = self.db.lang_attr(def.into())?;
|
||||
// We want to execute these functions with special logic
|
||||
if [PanicFmt, BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
|
||||
return Some(candidate);
|
||||
|
@ -181,7 +181,7 @@ impl Evaluator<'_> {
|
|||
it: LangItem,
|
||||
generic_args: &Substitution,
|
||||
args: &[Vec<u8>],
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
span: MirSpan,
|
||||
) -> Result<Vec<u8>> {
|
||||
use LangItem::*;
|
||||
|
@ -201,7 +201,7 @@ impl Evaluator<'_> {
|
|||
not_supported!("std::fmt::format not found");
|
||||
};
|
||||
let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") };
|
||||
let message_string = self.interpret_mir(&*self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.cloned())?;
|
||||
let message_string = self.interpret_mir(self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())))?;
|
||||
let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?;
|
||||
let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]);
|
||||
Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned())
|
||||
|
@ -245,7 +245,7 @@ impl Evaluator<'_> {
|
|||
args: &[IntervalAndTy],
|
||||
_generic_args: &Substitution,
|
||||
destination: Interval,
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
_span: MirSpan,
|
||||
) -> Result<()> {
|
||||
match as_str {
|
||||
|
@ -353,7 +353,7 @@ impl Evaluator<'_> {
|
|||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
destination: Interval,
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
span: MirSpan,
|
||||
) -> Result<()> {
|
||||
if let Some(name) = name.strip_prefix("simd_") {
|
||||
|
@ -368,7 +368,7 @@ impl Evaluator<'_> {
|
|||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
destination: Interval,
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
span: MirSpan,
|
||||
) -> Result<()> {
|
||||
if let Some(name) = name.strip_prefix("atomic_") {
|
||||
|
@ -873,15 +873,17 @@ impl Evaluator<'_> {
|
|||
.as_trait()
|
||||
.and_then(|it| self.db.trait_data(it).method_by_name(&name![call_once]))
|
||||
{
|
||||
return self.exec_fn_trait(
|
||||
self.exec_fn_trait(
|
||||
def,
|
||||
&args,
|
||||
// FIXME: wrong for manual impls of `FnOnce`
|
||||
Substitution::empty(Interner),
|
||||
locals,
|
||||
destination,
|
||||
None,
|
||||
span,
|
||||
);
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
not_supported!("FnOnce was not available for executing const_eval_select");
|
||||
|
@ -894,7 +896,7 @@ impl Evaluator<'_> {
|
|||
&mut self,
|
||||
ty: &Ty,
|
||||
metadata: Interval,
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
) -> Result<(usize, usize)> {
|
||||
Ok(match ty.kind(Interner) {
|
||||
TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1),
|
||||
|
@ -948,7 +950,7 @@ impl Evaluator<'_> {
|
|||
args: &[IntervalAndTy],
|
||||
generic_args: &Substitution,
|
||||
destination: Interval,
|
||||
locals: &Locals<'_>,
|
||||
locals: &Locals,
|
||||
_span: MirSpan,
|
||||
) -> Result<()> {
|
||||
// We are a single threaded runtime with no UB checking and no optimization, so
|
||||
|
|
|
@ -50,7 +50,7 @@ impl Evaluator<'_> {
|
|||
args: &[IntervalAndTy],
|
||||
_generic_args: &Substitution,
|
||||
destination: Interval,
|
||||
_locals: &Locals<'_>,
|
||||
_locals: &Locals,
|
||||
_span: MirSpan,
|
||||
) -> Result<()> {
|
||||
match name {
|
||||
|
|
|
@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
|
|||
db.trait_environment(func_id.into()),
|
||||
)
|
||||
.map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?;
|
||||
let (result, stdout, stderr) = interpret_mir(db, &body, false);
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false);
|
||||
result?;
|
||||
Ok((stdout, stderr))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! MIR lowering for places
|
||||
|
||||
use super::*;
|
||||
use hir_def::{lang_item::lang_attr, FunctionId};
|
||||
use hir_def::FunctionId;
|
||||
use hir_expand::name;
|
||||
|
||||
macro_rules! not_supported {
|
||||
|
@ -162,7 +162,7 @@ impl MirLowerCtx<'_> {
|
|||
let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) {
|
||||
TyKind::Ref(..) | TyKind::Raw(..) => true,
|
||||
TyKind::Adt(id, _) => {
|
||||
if let Some(lang_item) = lang_attr(self.db.upcast(), id.0) {
|
||||
if let Some(lang_item) = self.db.lang_attr(id.0.into()) {
|
||||
lang_item == LangItem::OwnedBox
|
||||
} else {
|
||||
false
|
||||
|
|
|
@ -1986,7 +1986,7 @@ impl Function {
|
|||
return r;
|
||||
}
|
||||
};
|
||||
let (result, stdout, stderr) = interpret_mir(db, &body, false);
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false);
|
||||
let mut text = match result {
|
||||
Ok(_) => "pass".to_string(),
|
||||
Err(e) => {
|
||||
|
|
|
@ -832,7 +832,7 @@ impl SourceAnalyzer {
|
|||
None => return func,
|
||||
};
|
||||
let env = db.trait_environment_for_body(owner);
|
||||
method_resolution::lookup_impl_method(db, env, func, substs).0
|
||||
db.lookup_impl_method(env, func, substs).0
|
||||
}
|
||||
|
||||
fn resolve_impl_const_or_trait_def(
|
||||
|
|
Loading…
Reference in a new issue