refactor try_resolve_did and also support resolving crates/modules

This commit is contained in:
Ralf Jung 2022-11-26 15:58:28 +01:00
parent 0822c311fb
commit 245857beb7

View File

@ -74,38 +74,66 @@ const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
}; };
/// Gets an instance for a path. /// Gets an instance for a path.
fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str], namespace: Namespace) -> Option<DefId> { ///
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( /// A `None` namespace indicates we are looking for a module.
|krate| { fn try_resolve_did<'tcx>(
let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; tcx: TyCtxt<'tcx>,
let mut items = tcx.module_children(krate); path: &[&str],
namespace: Option<Namespace>,
) -> Option<DefId> {
/// Yield all children of the given item, that have the given name.
fn find_children<'tcx: 'a, 'a>(
tcx: TyCtxt<'tcx>,
item: DefId,
name: &'a str,
) -> impl Iterator<Item = DefId> + 'a {
tcx.module_children(item)
.iter()
.filter(move |item| item.ident.name.as_str() == name)
.map(move |item| item.res.def_id())
}
for &segment in &path[1..path.len() - 1] { // Take apart the path: leading crate, a sequence of modules, and potentially a final item.
let next_mod = items.iter().find(|item| { let (&crate_name, path) = path.split_first().expect("paths must have at least one segment");
item.ident.name.as_str() == segment let (modules, item) = if let Some(namespace) = namespace {
&& tcx.def_kind(item.res.def_id()) == DefKind::Mod let (&item_name, modules) =
})?; path.split_last().expect("non-module paths must have at least 2 segments");
(modules, Some((item_name, namespace)))
} else {
(path, None)
};
items = tcx.module_children(next_mod.res.def_id()); // First find the crate.
} let krate =
tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == crate_name)?;
let item_name = *path.last().unwrap(); let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX };
// Then go over the modules.
let item = items.iter().find(|item| { for &segment in modules {
item.ident.name.as_str() == item_name cur_item = find_children(tcx, cur_item, segment)
&& tcx.def_kind(item.res.def_id()).ns() == Some(namespace) .find(|item| tcx.def_kind(item) == DefKind::Mod)?;
})?; }
// Finally, look up the desired item in this module, if any.
Some(item.res.def_id()) match item {
}, Some((item_name, namespace)) =>
) Some(
find_children(tcx, cur_item, item_name)
.find(|item| tcx.def_kind(item).ns() == Some(namespace))?,
),
None => Some(cur_item),
}
} }
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
/// Checks if the given crate/module exists.
fn have_module(&self, path: &[&str]) -> bool {
try_resolve_did(*self.eval_context_ref().tcx, path, None).is_some()
}
/// Gets an instance for a path; fails gracefully if the path does not exist. /// Gets an instance for a path; fails gracefully if the path does not exist.
fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> { fn try_resolve_path(&self, path: &[&str], namespace: Namespace) -> Option<ty::Instance<'tcx>> {
let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path, namespace)?; let tcx = self.eval_context_ref().tcx.tcx;
Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did)) let did = try_resolve_did(tcx, path, Some(namespace))?;
Some(ty::Instance::mono(tcx, did))
} }
/// Gets an instance for a path. /// Gets an instance for a path.