From 766cae6ca70243940829b25d577dbc2da8dbec06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lennard=20G=C3=A4her?= <l.gaeher@posteo.de>
Date: Thu, 2 Jan 2025 15:31:58 +0100
Subject: [PATCH] clean up utils

---
 rr_frontend/translation/src/attrs.rs          |  82 ++++
 rr_frontend/translation/src/base.rs           |   9 +
 .../translation/src/environment/mod.rs        |  12 +-
 rr_frontend/translation/src/function_body.rs  |  17 +-
 rr_frontend/translation/src/lib.rs            |  40 +-
 rr_frontend/translation/src/search.rs         | 323 +++++++++++++++
 rr_frontend/translation/src/shims/flat.rs     |  12 +-
 .../translation/src/traits/registry.rs        |  14 +-
 .../translation/src/traits/requirements.rs    |  12 +-
 rr_frontend/translation/src/types/local.rs    |   4 +-
 rr_frontend/translation/src/types/mod.rs      |   6 +-
 rr_frontend/translation/src/types/scope.rs    |   8 +-
 .../translation/src/types/translator.rs       |  30 +-
 rr_frontend/translation/src/utils.rs          | 390 +-----------------
 14 files changed, 496 insertions(+), 463 deletions(-)
 create mode 100644 rr_frontend/translation/src/attrs.rs
 create mode 100644 rr_frontend/translation/src/search.rs

diff --git a/rr_frontend/translation/src/attrs.rs b/rr_frontend/translation/src/attrs.rs
new file mode 100644
index 0000000..43040e5
--- /dev/null
+++ b/rr_frontend/translation/src/attrs.rs
@@ -0,0 +1,82 @@
+// © 2023, The RefinedRust Develcpers and Contributors
+//
+// This Source Code Form is subject to the terms of the BSD-3-clause License.
+// If a copy of the BSD-3-clause license was not distributed with this
+// file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
+
+//! Utility functions for obtaining relevant attributes.
+
+use std::mem;
+
+use log::{info, trace};
+use rr_rustc_interface::ast::ast;
+use rr_rustc_interface::data_structures::fx::FxHashSet;
+use rr_rustc_interface::hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rr_rustc_interface::middle::mir;
+use rr_rustc_interface::middle::ty::{self, TyCtxt};
+use rr_rustc_interface::{hir, middle, span};
+use serde::{Deserialize, Serialize};
+
+use crate::spec_parsers::get_export_as_attr;
+use crate::{force_matches, types, Environment};
+
+/// Check if `<tool>::<name>` is among the attributes, where `tool` is determined by the
+/// `spec_hotword` config.
+/// Any arguments of the attribute are ignored.
+pub fn has_tool_attr(attrs: &[ast::Attribute], name: &str) -> bool {
+    get_tool_attr(attrs, name).is_some()
+}
+
+/// Get the arguments for a tool attribute, if it exists.
+pub fn get_tool_attr<'a>(attrs: &'a [ast::Attribute], name: &str) -> Option<&'a ast::AttrArgs> {
+    attrs.iter().find_map(|attr| match &attr.kind {
+        ast::AttrKind::Normal(na) => {
+            let segments = &na.item.path.segments;
+            let args = &na.item.args;
+            (segments.len() == 2
+                && segments[0].ident.as_str() == rrconfig::spec_hotword().as_str()
+                && segments[1].ident.as_str() == name)
+                .then_some(args)
+        },
+        _ => None,
+    })
+}
+
+/// Check if `<tool>::name` is among the filtered attributes.
+pub fn has_tool_attr_filtered(attrs: &[&ast::AttrItem], name: &str) -> bool {
+    attrs.iter().any(|item| {
+        let segments = &item.path.segments;
+        segments.len() == 2
+            && segments[0].ident.as_str() == rrconfig::spec_hotword().as_str()
+            && segments[1].ident.as_str() == name
+    })
+}
+
+/// Check if any attribute starting with `<tool>` is among the attributes.
+pub fn has_any_tool_attr(attrs: &[ast::Attribute]) -> bool {
+    attrs.iter().any(|attr| match &attr.kind {
+        ast::AttrKind::Normal(na) => {
+            let segments = &na.item.path.segments;
+            segments[0].ident.as_str() == rrconfig::spec_hotword().as_str()
+        },
+        _ => false,
+    })
+}
+
+/// Get all tool attributes, i.e. attributes of the shape `<tool>::attr`, where `tool` is
+/// determined by the `spec_hotword` config.
+pub fn filter_for_tool(attrs: &[ast::Attribute]) -> Vec<&ast::AttrItem> {
+    attrs
+        .iter()
+        .filter_map(|attr| match &attr.kind {
+            ast::AttrKind::Normal(na) => {
+                let item = &na.item;
+
+                let seg = item.path.segments.get(0)?;
+
+                (seg.ident.name.as_str() == rrconfig::spec_hotword()).then_some(item)
+            },
+            _ => None,
+        })
+        .collect()
+}
diff --git a/rr_frontend/translation/src/base.rs b/rr_frontend/translation/src/base.rs
index d4ef60a..2d61977 100644
--- a/rr_frontend/translation/src/base.rs
+++ b/rr_frontend/translation/src/base.rs
@@ -13,6 +13,15 @@ use rr_rustc_interface::polonius_engine::FactTypes;
 use crate::environment::borrowck::facts;
 use crate::traits;
 
+/// Strip symbols from an identifier to be compatible with Coq.
+/// In particular things like ' or ::.
+pub fn strip_coq_ident(s: &str) -> String {
+    String::from(s)
+        .replace('\'', "")
+        .replace("::", "_")
+        .replace(|c: char| !(c.is_alphanumeric() || c == '_'), "")
+}
+
 pub type Region = <RustcFacts as FactTypes>::Origin;
 pub type Loan = <RustcFacts as FactTypes>::Loan;
 pub type PointIndex = <RustcFacts as FactTypes>::Point;
diff --git a/rr_frontend/translation/src/environment/mod.rs b/rr_frontend/translation/src/environment/mod.rs
index e46f060..65f8997 100644
--- a/rr_frontend/translation/src/environment/mod.rs
+++ b/rr_frontend/translation/src/environment/mod.rs
@@ -32,13 +32,13 @@ use rr_rustc_interface::span::Span;
 use rr_rustc_interface::trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
 use rr_rustc_interface::{ast, span};
 
+use crate::attrs;
 use crate::data::ProcedureDefId;
 use crate::environment::borrowck::facts;
 use crate::environment::collect_closure_defs_visitor::CollectClosureDefsVisitor;
 use crate::environment::collect_prusti_spec_visitor::CollectPrustiSpecVisitor;
 use crate::environment::loops::{PlaceAccess, PlaceAccessKind, ProcedureLoops};
 use crate::environment::procedure::{BasicBlockIndex, Procedure};
-use crate::utils;
 
 /// Facade to the Rust compiler.
 // #[derive(Copy, Clone)]
@@ -211,7 +211,7 @@ impl<'tcx> Environment<'tcx> {
     pub fn has_tool_attribute(&self, def_id: ProcedureDefId, name: &str) -> bool {
         let tcx = self.tcx();
         // TODO: migrate to get_attrs
-        utils::has_tool_attr(tcx.get_attrs_unchecked(def_id), name)
+        attrs::has_tool_attr(tcx.get_attrs_unchecked(def_id), name)
     }
 
     /// Find whether the procedure has a particular `[tool]::<name>` attribute; if so, return its
@@ -219,14 +219,14 @@ impl<'tcx> Environment<'tcx> {
     pub fn get_tool_attribute<'a>(&'a self, def_id: ProcedureDefId, name: &str) -> Option<&'a ast::AttrArgs> {
         let tcx = self.tcx();
         // TODO: migrate to get_attrs
-        utils::get_tool_attr(tcx.get_attrs_unchecked(def_id), name)
+        attrs::get_tool_attr(tcx.get_attrs_unchecked(def_id), name)
     }
 
     /// Check whether the procedure has any `[tool]` attribute.
     pub fn has_any_tool_attribute(&self, def_id: ProcedureDefId) -> bool {
         let tcx = self.tcx();
         // TODO: migrate to get_attrs
-        utils::has_any_tool_attr(tcx.get_attrs_unchecked(def_id))
+        attrs::has_any_tool_attr(tcx.get_attrs_unchecked(def_id))
     }
 
     /// Get the attributes of an item (e.g. procedures).
@@ -245,11 +245,11 @@ impl<'tcx> Environment<'tcx> {
         F: for<'a> Fn(&'a ast::ast::AttrItem) -> bool,
     {
         let attrs = self.get_attributes(did);
-        let mut filtered_attrs = utils::filter_tool_attrs(attrs);
+        let mut filtered_attrs = attrs::filter_for_tool(attrs);
         // also add selected attributes from the surrounding impl
         if let Some(impl_did) = self.tcx().impl_of_method(did) {
             let impl_attrs = self.get_attributes(impl_did);
-            let filtered_impl_attrs = utils::filter_tool_attrs(impl_attrs);
+            let filtered_impl_attrs = attrs::filter_for_tool(impl_attrs);
             filtered_attrs.extend(filtered_impl_attrs.into_iter().filter(|x| propagate_from_impl(x)));
         }
 
diff --git a/rr_frontend/translation/src/function_body.rs b/rr_frontend/translation/src/function_body.rs
index e1b0fb6..2a1f4b3 100644
--- a/rr_frontend/translation/src/function_body.rs
+++ b/rr_frontend/translation/src/function_body.rs
@@ -35,7 +35,7 @@ use crate::spec_parsers::verbose_function_spec_parser::{
     ClosureMetaInfo, FunctionRequirements, FunctionSpecParser, VerboseFunctionSpecParser,
 };
 use crate::traits::{registry, resolution};
-use crate::{regions, traits, types, utils};
+use crate::{base, regions, search, traits, types};
 
 /// Get the syntypes of function arguments for a procedure call.
 pub fn get_arg_syntypes_for_procedure_call<'tcx, 'def>(
@@ -950,7 +950,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> FunctionTranslator<'a, 'def, 'tcx> {
 
                 match *r {
                     ty::RegionKind::ReEarlyBound(r) => {
-                        let name = utils::strip_coq_ident(r.name.as_str());
+                        let name = base::strip_coq_ident(r.name.as_str());
                         universal_lifetimes.insert(next_id, format!("ulft_{}", name));
                         lifetime_names.insert(name, next_id);
                     },
@@ -981,7 +981,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> FunctionTranslator<'a, 'def, 'tcx> {
 
             match r {
                 ty::BoundRegionKind::BrNamed(_, sym) => {
-                    let mut region_name = utils::strip_coq_ident(sym.as_str());
+                    let mut region_name = base::strip_coq_ident(sym.as_str());
                     if region_name == "_" {
                         region_name = next_id.as_usize().to_string();
                         universal_lifetimes.insert(next_id, format!("ulft_{}", region_name));
@@ -1351,7 +1351,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> FunctionTranslator<'a, 'def, 'tcx> {
                     .trait_registry
                     .lookup_trait(trait_did)
                     .ok_or_else(|| TranslationError::TraitResolution(format!("{trait_did:?}")))?;
-                let fn_name = utils::strip_coq_ident(self.env.tcx().item_name(self.proc.get_id()).as_str());
+                let fn_name = base::strip_coq_ident(self.env.tcx().item_name(self.proc.get_id()).as_str());
 
                 let trait_info = self.trait_registry.get_trait_impl_info(impl_did)?;
                 //self.trait_registry.lookup_impl(impl_did)?;
@@ -1403,7 +1403,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> FunctionTranslator<'a, 'def, 'tcx> {
     /// `used_names` keeps track of the Rust source code names that have already been used.
     fn make_local_name(mir_body: &Body<'tcx>, local: Local, used_names: &mut HashSet<String>) -> String {
         if let Some(mir_name) = Self::find_name_for_local(mir_body, local, used_names) {
-            let name = utils::strip_coq_ident(&mir_name);
+            let name = base::strip_coq_ident(&mir_name);
             used_names.insert(mir_name);
             name
         } else {
@@ -2159,7 +2159,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
         };
 
         if let Some(panic_id_std) =
-            utils::try_resolve_did(self.env.tcx(), &["std", "panicking", "begin_panic"])
+            search::try_resolve_did(self.env.tcx(), &["std", "panicking", "begin_panic"])
         {
             if panic_id_std == *did {
                 return true;
@@ -2168,7 +2168,8 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
             warn!("Failed to determine DefId of std::panicking::begin_panic");
         }
 
-        if let Some(panic_id_core) = utils::try_resolve_did(self.env.tcx(), &["core", "panicking", "panic"]) {
+        if let Some(panic_id_core) = search::try_resolve_did(self.env.tcx(), &["core", "panicking", "panic"])
+        {
             if panic_id_core == *did {
                 return true;
             }
@@ -2183,7 +2184,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
     #[allow(clippy::unused_self)]
     const fn register_drop_shim_for(&self, _ty: Ty<'tcx>) {
         // TODO!
-        //let drop_in_place_did: DefId = utils::try_resolve_did(self.env.tcx(), &["std", "ptr",
+        //let drop_in_place_did: DefId = search::try_resolve_did(self.env.tcx(), &["std", "ptr",
         // "drop_in_place"]).unwrap();
 
         //let x: ty::InstanceDef = ty::InstanceDef::DropGlue(drop_in_place_did, Some(ty));
diff --git a/rr_frontend/translation/src/lib.rs b/rr_frontend/translation/src/lib.rs
index 942c4c6..00cefaa 100644
--- a/rr_frontend/translation/src/lib.rs
+++ b/rr_frontend/translation/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(let_chains)]
 #![feature(rustc_private)]
 mod arg_folder;
+mod attrs;
 mod base;
 mod checked_op_analysis;
 mod data;
@@ -17,6 +18,7 @@ mod force_matches_macro;
 mod function_body;
 mod inclusion_tracker;
 mod regions;
+mod search;
 mod shims;
 mod spec_parsers;
 mod traits;
@@ -124,7 +126,7 @@ impl<'tcx, 'rcx> VerificationCtxt<'tcx, 'rcx> {
         let is_method = self.env.tcx().impl_of_method(did).is_some();
         let interned_path = self.get_path_for_shim(did);
 
-        let name = utils::strip_coq_ident(&self.env.get_item_name(did));
+        let name = base::strip_coq_ident(&self.env.get_item_name(did));
         info!("Found function path {:?} for did {:?} with name {:?}", interned_path, did, name);
 
         Some(shim_registry::FunctionShim {
@@ -193,7 +195,7 @@ impl<'tcx, 'rcx> VerificationCtxt<'tcx, 'rcx> {
                 };
 
                 let method_ident = ident.as_str().to_owned();
-                let name = utils::strip_coq_ident(&self.env.get_item_name(did));
+                let name = base::strip_coq_ident(&self.env.get_item_name(did));
 
                 trace!("leave make_shim_trait_method_entry (success)");
                 Some(shim_registry::TraitMethodImplShim {
@@ -296,7 +298,7 @@ impl<'tcx, 'rcx> VerificationCtxt<'tcx, 'rcx> {
         if did.is_local() && ty::Visibility::Public == self.env.tcx().visibility(did) {
             // only export public items
             let interned_path = self.get_path_for_shim(did);
-            let name = utils::strip_coq_ident(&self.env.get_item_name(did));
+            let name = base::strip_coq_ident(&self.env.get_item_name(did));
 
             info!("Found adt path {:?} for did {:?} with name {:?}", interned_path, did, name);
 
@@ -913,9 +915,9 @@ impl<'tcx, 'rcx> VerificationCtxt<'tcx, 'rcx> {
 fn register_shims<'tcx>(vcx: &mut VerificationCtxt<'tcx, '_>) -> Result<(), base::TranslationError<'tcx>> {
     for shim in vcx.shim_registry.get_function_shims() {
         let did = if shim.is_method {
-            utils::try_resolve_method_did(vcx.env.tcx(), &shim.path)
+            search::try_resolve_method_did(vcx.env.tcx(), &shim.path)
         } else {
-            utils::try_resolve_did(vcx.env.tcx(), &shim.path)
+            search::try_resolve_did(vcx.env.tcx(), &shim.path)
         };
 
         match did {
@@ -936,7 +938,7 @@ fn register_shims<'tcx>(vcx: &mut VerificationCtxt<'tcx, '_>) -> Result<(), base
     }
 
     for shim in vcx.shim_registry.get_adt_shims() {
-        let Some(did) = utils::try_resolve_did(vcx.env.tcx(), &shim.path) else {
+        let Some(did) = search::try_resolve_did(vcx.env.tcx(), &shim.path) else {
             println!("Warning: cannot find defid for shim {:?}, skipping", shim.path);
             continue;
         };
@@ -956,7 +958,7 @@ fn register_shims<'tcx>(vcx: &mut VerificationCtxt<'tcx, '_>) -> Result<(), base
     }
 
     for shim in vcx.shim_registry.get_trait_shims() {
-        if let Some(did) = utils::try_resolve_did(vcx.env.tcx(), &shim.path) {
+        if let Some(did) = search::try_resolve_did(vcx.env.tcx(), &shim.path) {
             let assoc_tys = vcx.trait_registry.get_associated_type_names(did);
             let spec = radium::LiteralTraitSpec {
                 assoc_tys,
@@ -994,7 +996,7 @@ fn register_shims<'tcx>(vcx: &mut VerificationCtxt<'tcx, '_>) -> Result<(), base
             continue;
         };
 
-        let trait_impl_did = utils::try_resolve_trait_impl_did(vcx.env.tcx(), trait_did, &args, for_type);
+        let trait_impl_did = search::try_resolve_trait_impl_did(vcx.env.tcx(), trait_did, &args, for_type);
 
         let Some(did) = trait_impl_did else {
             println!(
@@ -1056,19 +1058,19 @@ fn get_most_restrictive_function_mode(
     let attrs = vcx.env.get_attributes_of_function(did, &propagate_method_attr_from_impl);
 
     // check if this is a purely spec function; if so, skip.
-    if utils::has_tool_attr_filtered(attrs.as_slice(), "shim") {
+    if attrs::has_tool_attr_filtered(attrs.as_slice(), "shim") {
         return function_body::ProcedureMode::Shim;
     }
 
-    if utils::has_tool_attr_filtered(attrs.as_slice(), "trust_me") {
+    if attrs::has_tool_attr_filtered(attrs.as_slice(), "trust_me") {
         return function_body::ProcedureMode::TrustMe;
     }
 
-    if utils::has_tool_attr_filtered(attrs.as_slice(), "only_spec") {
+    if attrs::has_tool_attr_filtered(attrs.as_slice(), "only_spec") {
         return function_body::ProcedureMode::OnlySpec;
     }
 
-    if utils::has_tool_attr_filtered(attrs.as_slice(), "ignore") {
+    if attrs::has_tool_attr_filtered(attrs.as_slice(), "ignore") {
         info!("Function {:?} will be ignored", did);
         return function_body::ProcedureMode::Ignore;
     }
@@ -1086,7 +1088,7 @@ fn register_functions<'tcx>(
         if mode == function_body::ProcedureMode::Shim {
             // TODO better error message
             let attrs = vcx.env.get_attributes(f.to_def_id());
-            let v = utils::filter_tool_attrs(attrs);
+            let v = attrs::filter_for_tool(attrs);
             let annot = spec_parsers::get_shim_attrs(v.as_slice()).unwrap();
 
             info!(
@@ -1114,7 +1116,7 @@ fn register_functions<'tcx>(
             mode = function_body::ProcedureMode::Prove;
         }
 
-        let fname = utils::strip_coq_ident(&vcx.env.get_item_name(f.to_def_id()));
+        let fname = base::strip_coq_ident(&vcx.env.get_item_name(f.to_def_id()));
         let spec_name = format!("type_of_{}", fname);
 
         let meta = function_body::ProcedureMeta::new(spec_name, fname, mode);
@@ -1273,7 +1275,7 @@ pub fn register_consts<'rcx, 'tcx>(vcx: &mut VerificationCtxt<'tcx, 'rcx>) -> Re
     for s in &statics {
         let ty: ty::EarlyBinder<ty::Ty<'tcx>> = vcx.env.tcx().type_of(s.to_def_id());
 
-        let const_attrs = utils::filter_tool_attrs(vcx.env.get_attributes(s.to_def_id()));
+        let const_attrs = attrs::filter_for_tool(vcx.env.get_attributes(s.to_def_id()));
         if const_attrs.is_empty() {
             continue;
         }
@@ -1282,7 +1284,7 @@ pub fn register_consts<'rcx, 'tcx>(vcx: &mut VerificationCtxt<'tcx, 'rcx>) -> Re
         let scope = scope::Params::default();
         match vcx.type_translator.translate_type_in_scope(&scope, ty).map_err(|x| format!("{:?}", x)) {
             Ok(translated_ty) => {
-                let _full_name = utils::strip_coq_ident(&vcx.env.get_item_name(s.to_def_id()));
+                let _full_name = base::strip_coq_ident(&vcx.env.get_item_name(s.to_def_id()));
 
                 let mut const_parser = VerboseConstAttrParser::new();
                 let const_spec = const_parser.parse_const_attrs(*s, &const_attrs)?;
@@ -1377,7 +1379,7 @@ fn register_trait_impls(vcx: &VerificationCtxt<'_, '_>) -> Result<(), String> {
             }
 
             // make names for the spec and inclusion proof
-            let base_name = utils::strip_coq_ident(&vcx.env.get_item_name(did));
+            let base_name = base::strip_coq_ident(&vcx.env.get_item_name(did));
             let spec_name = format!("{base_name}_spec");
             let spec_params_name = format!("{base_name}_spec_params");
             let spec_attrs_name = format!("{base_name}_spec_attrs");
@@ -1459,7 +1461,7 @@ pub fn get_module_attributes(env: &Environment<'_>) -> Result<HashMap<LocalDefId
     info!("collected modules: {:?}", modules);
 
     for m in &modules {
-        let module_attrs = utils::filter_tool_attrs(env.get_attributes(m.to_def_id()));
+        let module_attrs = attrs::filter_for_tool(env.get_attributes(m.to_def_id()));
         let mut module_parser = VerboseModuleAttrParser::new();
         let module_spec = module_parser.parse_module_attrs(*m, &module_attrs)?;
         attrs.insert(*m, module_spec);
@@ -1478,7 +1480,7 @@ where
 
     // get crate attributes
     let crate_attrs = tcx.hir().krate_attrs();
-    let crate_attrs = utils::filter_tool_attrs(crate_attrs);
+    let crate_attrs = attrs::filter_for_tool(crate_attrs);
     info!("Found crate attributes: {:?}", crate_attrs);
     // parse crate attributes
     let mut crate_parser = VerboseCrateAttrParser::new();
diff --git a/rr_frontend/translation/src/search.rs b/rr_frontend/translation/src/search.rs
new file mode 100644
index 0000000..82d7381
--- /dev/null
+++ b/rr_frontend/translation/src/search.rs
@@ -0,0 +1,323 @@
+// These functions have been adapted from Miri (https://github.com/rust-lang/miri/blob/31fb32e49f42df19b45baccb6aa80c3d726ed6d5/src/helpers.rs#L48) under the MIT license.
+
+//! Utility functions for finding Rust source objects.
+
+use std::mem;
+
+use log::{info, trace};
+use rr_rustc_interface::ast::ast;
+use rr_rustc_interface::data_structures::fx::FxHashSet;
+use rr_rustc_interface::hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rr_rustc_interface::middle::mir;
+use rr_rustc_interface::middle::ty::{self, TyCtxt};
+use rr_rustc_interface::{hir, middle, span};
+use serde::{Deserialize, Serialize};
+
+use crate::spec_parsers::get_export_as_attr;
+use crate::{force_matches, types, Environment};
+
+/// Gets an instance for a path.
+/// Taken from Miri <https://github.com/rust-lang/miri/blob/31fb32e49f42df19b45baccb6aa80c3d726ed6d5/src/helpers.rs#L48>.
+pub fn try_resolve_did_direct<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
+where
+    T: AsRef<str>,
+{
+    tcx.crates(())
+        .iter()
+        .find(|&&krate| tcx.crate_name(krate).as_str() == path[0].as_ref())
+        .and_then(|krate| {
+            let krate = DefId {
+                krate: *krate,
+                index: CRATE_DEF_INDEX,
+            };
+
+            let mut items: &[middle::metadata::ModChild] = tcx.module_children(krate);
+            let mut path_it = path.iter().skip(1).peekable();
+
+            while let Some(segment) = path_it.next() {
+                for item in mem::take(&mut items) {
+                    let item: &middle::metadata::ModChild = item;
+                    if item.ident.name.as_str() == segment.as_ref() {
+                        if path_it.peek().is_none() {
+                            return Some(item.res.def_id());
+                        }
+
+                        items = tcx.module_children(item.res.def_id());
+                        break;
+                    }
+                }
+            }
+            None
+        })
+}
+
+pub fn try_resolve_did<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
+where
+    T: AsRef<str>,
+{
+    if let Some(did) = try_resolve_did_direct(tcx, path) {
+        return Some(did);
+    }
+
+    // if the first component is "std", try if we can replace it with "alloc" or "core"
+    if path[0].as_ref() == "std" {
+        let mut components: Vec<_> = path.iter().map(|x| x.as_ref().to_owned()).collect();
+        components[0] = "core".to_owned();
+        if let Some(did) = try_resolve_did_direct(tcx, &components) {
+            return Some(did);
+        }
+        // try "alloc"
+        components[0] = "alloc".to_owned();
+        try_resolve_did_direct(tcx, &components)
+    } else {
+        None
+    }
+}
+
+/// Determine whether the two argument lists match for the type positions (ignoring consts and regions).
+/// The first argument is the authority determining which argument positions are types.
+/// The second argument may contain `None` for non-type positions.
+fn args_match_types<'tcx>(
+    reference: &[ty::GenericArg<'tcx>],
+    compare: &[Option<ty::GenericArg<'tcx>>],
+) -> bool {
+    if reference.len() != compare.len() {
+        return false;
+    }
+
+    for (arg1, arg2) in reference.iter().zip(compare.iter()) {
+        if let Some(ty1) = arg1.as_type() {
+            if let Some(arg2) = arg2 {
+                if let Some(ty2) = arg2.as_type() {
+                    if ty1 != ty2 {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        }
+    }
+    true
+}
+
+/// Try to resolve the `DefId` of an implementation of a trait for a particular type.
+/// Note that this does not, in general, find a unique solution, in case there are complex things
+/// with different where clauses going on.
+pub fn try_resolve_trait_impl_did<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_did: DefId,
+    trait_args: &[Option<ty::GenericArg<'tcx>>],
+    for_type: ty::Ty<'tcx>,
+) -> Option<DefId> {
+    // get all impls of this trait
+    let impls: &ty::trait_def::TraitImpls = tcx.trait_impls_of(trait_did);
+
+    let simplified_type =
+        middle::ty::fast_reject::simplify_type(tcx, for_type, ty::fast_reject::TreatParams::AsCandidateKey)?;
+    let defs = impls.non_blanket_impls().get(&simplified_type)?;
+    info!("found implementations: {:?}", impls);
+
+    let mut solution = None;
+    for did in defs {
+        let impl_self_ty: ty::Ty<'tcx> = tcx.type_of(did).instantiate_identity();
+        let impl_self_ty = types::normalize_in_function(*did, tcx, impl_self_ty).unwrap();
+
+        // check if this is an implementation for the right type
+        // TODO: is this the right way to compare the types?
+        if impl_self_ty == for_type {
+            let impl_ref: Option<ty::EarlyBinder<ty::TraitRef<'_>>> = tcx.impl_trait_ref(did);
+
+            if let Some(impl_ref) = impl_ref {
+                let impl_ref = types::normalize_in_function(*did, tcx, impl_ref.skip_binder()).unwrap();
+
+                let this_impl_args = impl_ref.args;
+                // filter by the generic instantiation for the trait
+                info!("found impl with args {:?}", this_impl_args);
+                // args has self at position 0 and generics of the trait at position 1..
+
+                // check if the generic argument types match up
+                if !args_match_types(&this_impl_args.as_slice()[1..], trait_args) {
+                    continue;
+                }
+
+                info!("found impl {:?}", impl_ref);
+                if solution.is_some() {
+                    println!(
+                        "Warning: Ambiguous resolution for impl of trait {:?} on type {:?}; solution {:?} but found also {:?}",
+                        trait_did,
+                        for_type,
+                        solution.unwrap(),
+                        impl_ref.def_id,
+                    );
+                } else {
+                    solution = Some(*did);
+                }
+            }
+        }
+    }
+
+    solution
+}
+
+/// Try to resolve the `DefId` of a method in an implementation of a trait for a particular type.
+/// Note that this does not, in general, find a unique solution, in case there are complex things
+/// with different where clauses going on.
+pub fn try_resolve_trait_method_did<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_did: DefId,
+    trait_args: &[Option<ty::GenericArg<'tcx>>],
+    method_name: &str,
+    for_type: ty::Ty<'tcx>,
+) -> Option<DefId> {
+    // get all impls of this trait
+    let impls: &ty::trait_def::TraitImpls = tcx.trait_impls_of(trait_did);
+
+    let simplified_type =
+        middle::ty::fast_reject::simplify_type(tcx, for_type, ty::fast_reject::TreatParams::AsCandidateKey)?;
+    let defs = impls.non_blanket_impls().get(&simplified_type)?;
+    info!("found implementations: {:?}", impls);
+
+    let mut solution = None;
+    for did in defs {
+        let impl_self_ty: ty::Ty<'tcx> = tcx.type_of(did).instantiate_identity();
+        let impl_self_ty = types::normalize_in_function(*did, tcx, impl_self_ty).unwrap();
+
+        // check if this is an implementation for the right type
+        // TODO: is this the right way to compare the types?
+        if impl_self_ty == for_type {
+            let impl_ref: Option<ty::EarlyBinder<ty::TraitRef<'_>>> = tcx.impl_trait_ref(did);
+
+            if let Some(impl_ref) = impl_ref {
+                let impl_ref = types::normalize_in_function(*did, tcx, impl_ref.skip_binder()).unwrap();
+
+                let this_impl_args = impl_ref.args;
+                // filter by the generic instantiation for the trait
+                info!("found impl with args {:?}", this_impl_args);
+                // args has self at position 0 and generics of the trait at position 1..
+
+                // check if the generic argument types match up
+                if !args_match_types(&this_impl_args.as_slice()[1..], trait_args) {
+                    continue;
+                }
+
+                let impl_assoc_items: &ty::AssocItems = tcx.associated_items(did);
+                // find the right item
+                if let Some(item) = impl_assoc_items.find_by_name_and_kind(
+                    tcx,
+                    span::symbol::Ident::from_str(method_name),
+                    ty::AssocKind::Fn,
+                    trait_did,
+                ) {
+                    info!("found impl {:?} with item {:?}", impl_ref, item);
+                    if solution.is_some() {
+                        println!(
+                            "Warning: Ambiguous resolution for method {method_name} of trait {:?} on type {:?}; solution {:?} but found also {:?}",
+                            trait_did,
+                            for_type,
+                            solution.unwrap(),
+                            item.def_id
+                        );
+                    } else {
+                        solution = Some(item.def_id);
+                    }
+                }
+            }
+        }
+    }
+
+    solution
+}
+
+/// Try to get a defid of a method at the given path.
+/// This does not handle trait methods.
+/// This also does not handle overlapping method definitions/specialization well.
+pub fn try_resolve_method_did_direct<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
+where
+    T: AsRef<str>,
+{
+    tcx.crates(())
+        .iter()
+        .find(|&&krate| tcx.crate_name(krate).as_str() == path[0].as_ref())
+        .and_then(|krate| {
+            let krate = DefId {
+                krate: *krate,
+                index: CRATE_DEF_INDEX,
+            };
+
+            let mut items: &[middle::metadata::ModChild] = tcx.module_children(krate);
+            let mut path_it = path.iter().skip(1).peekable();
+
+            while let Some(segment) = path_it.next() {
+                //info!("items to look at: {:?}", items);
+                for item in mem::take(&mut items) {
+                    let item: &middle::metadata::ModChild = item;
+
+                    if item.ident.name.as_str() != segment.as_ref() {
+                        continue;
+                    }
+
+                    info!("taking path: {:?}", segment.as_ref());
+                    if path_it.peek().is_none() {
+                        return Some(item.res.def_id());
+                    }
+
+                    // just the method remaining
+                    if path_it.len() != 1 {
+                        items = tcx.module_children(item.res.def_id());
+                        break;
+                    }
+
+                    let did: DefId = item.res.def_id();
+                    let impls: &[DefId] = tcx.inherent_impls(did);
+                    info!("trying to find method among impls {:?}", impls);
+
+                    let find = path_it.next().unwrap();
+                    for impl_did in impls {
+                        //let ty = tcx.type_of(*impl_did);
+                        //info!("type of impl: {:?}", ty);
+                        let items: &ty::AssocItems = tcx.associated_items(impl_did);
+                        //info!("items here: {:?}", items);
+                        // TODO more robust error handling if there are multiple matches.
+                        for item in items.in_definition_order() {
+                            //info!("comparing: {:?} with {:?}", item.name.as_str(), find);
+                            if item.name.as_str() == find.as_ref() {
+                                return Some(item.def_id);
+                            }
+                        }
+                        //info!("impl items: {:?}", items);
+                    }
+
+                    //info!("inherent impls for {:?}: {:?}", did, impls);
+                    return None;
+                }
+            }
+
+            None
+        })
+}
+
+pub fn try_resolve_method_did<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
+where
+    T: AsRef<str>,
+{
+    if let Some(did) = try_resolve_method_did_direct(tcx, path) {
+        return Some(did);
+    }
+
+    // if the first component is "std", try if we can replace it with "alloc" or "core"
+    if path[0].as_ref() == "std" {
+        let mut components: Vec<_> = path.iter().map(|x| x.as_ref().to_owned()).collect();
+        components[0] = "core".to_owned();
+        if let Some(did) = try_resolve_method_did_direct(tcx, &components) {
+            return Some(did);
+        }
+        // try "alloc"
+        components[0] = "alloc".to_owned();
+        try_resolve_method_did_direct(tcx, &components)
+    } else {
+        None
+    }
+}
diff --git a/rr_frontend/translation/src/shims/flat.rs b/rr_frontend/translation/src/shims/flat.rs
index 3700acc..2d792f0 100644
--- a/rr_frontend/translation/src/shims/flat.rs
+++ b/rr_frontend/translation/src/shims/flat.rs
@@ -18,7 +18,7 @@ use rr_rustc_interface::{hir, middle, span};
 use serde::{Deserialize, Serialize};
 
 use crate::spec_parsers::get_export_as_attr;
-use crate::{types, utils, Environment};
+use crate::{attrs, search, types, Environment};
 
 /// An item path that receives generic arguments.
 #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
@@ -33,7 +33,7 @@ pub struct PathWithArgs {
 
 impl PathWithArgs {
     pub fn to_item<'tcx>(&self, tcx: ty::TyCtxt<'tcx>) -> Option<(DefId, Vec<Option<ty::GenericArg<'tcx>>>)> {
-        let did = utils::try_resolve_did(tcx, self.path.as_slice())?;
+        let did = search::try_resolve_did(tcx, self.path.as_slice())?;
 
         let mut ty_args = Vec::new();
 
@@ -208,8 +208,8 @@ fn extract_def_path(path: &hir::definitions::DefPath) -> Vec<String> {
 pub fn get_export_path_for_did(env: &Environment, did: DefId) -> Vec<String> {
     let attrs = env.get_attributes(did);
 
-    if utils::has_tool_attr(attrs, "export_as") {
-        let filtered_attrs = utils::filter_tool_attrs(attrs);
+    if attrs::has_tool_attr(attrs, "export_as") {
+        let filtered_attrs = attrs::filter_for_tool(attrs);
 
         return get_export_as_attr(filtered_attrs.as_slice()).unwrap();
     }
@@ -218,8 +218,8 @@ pub fn get_export_path_for_did(env: &Environment, did: DefId) -> Vec<String> {
     if let Some(impl_did) = env.tcx().impl_of_method(did) {
         let attrs = env.get_attributes(impl_did);
 
-        if utils::has_tool_attr(attrs, "export_as") {
-            let filtered_attrs = utils::filter_tool_attrs(attrs);
+        if attrs::has_tool_attr(attrs, "export_as") {
+            let filtered_attrs = attrs::filter_for_tool(attrs);
             let mut path_prefix = get_export_as_attr(filtered_attrs.as_slice()).unwrap();
 
             // push the last component of this path
diff --git a/rr_frontend/translation/src/traits/registry.rs b/rr_frontend/translation/src/traits/registry.rs
index 882d67e..43aaee3 100644
--- a/rr_frontend/translation/src/traits/registry.rs
+++ b/rr_frontend/translation/src/traits/registry.rs
@@ -24,7 +24,7 @@ use crate::spec_parsers::propagate_method_attr_from_impl;
 use crate::spec_parsers::trait_attr_parser::{TraitAttrParser, VerboseTraitAttrParser};
 use crate::spec_parsers::trait_impl_attr_parser::{TraitImplAttrParser, VerboseTraitImplAttrParser};
 use crate::types::scope;
-use crate::{traits, types, utils};
+use crate::{attrs, base, traits, types};
 
 pub struct TR<'tcx, 'def> {
     /// environment
@@ -185,10 +185,10 @@ impl<'tcx, 'def> TR<'tcx, 'def> {
         let mut param_scope = scope::Params::from(trait_generics.params.as_slice());
         param_scope.add_param_env(did.to_def_id(), self.env, self.type_translator, self)?;
 
-        let trait_name = utils::strip_coq_ident(&self.env.get_absolute_item_name(did.to_def_id()));
+        let trait_name = base::strip_coq_ident(&self.env.get_absolute_item_name(did.to_def_id()));
 
         // parse trait spec
-        let trait_attrs = utils::filter_tool_attrs(self.env.get_attributes(did.into()));
+        let trait_attrs = attrs::filter_for_tool(self.env.get_attributes(did.into()));
         // As different attributes of the spec may depend on each other, we need to pass a closure
         // determining under which Coq name we are going to introduce them
         // Note: This needs to match up with `radium::LiteralTraitSpec.make_spec_attr_name`!
@@ -219,7 +219,7 @@ impl<'tcx, 'def> TR<'tcx, 'def> {
                 // get function name
                 let method_name =
                     self.env.get_assoc_item_name(c.def_id).ok_or(Error::NotATraitMethod(c.def_id))?;
-                let method_name = utils::strip_coq_ident(&method_name);
+                let method_name = base::strip_coq_ident(&method_name);
 
                 let name = format!("{trait_name}_{method_name}");
                 let spec_name = format!("{name}_base_spec");
@@ -241,7 +241,7 @@ impl<'tcx, 'def> TR<'tcx, 'def> {
                 // get name
                 let type_name =
                     self.env.get_assoc_item_name(c.def_id).ok_or(Error::NotATraitMethod(c.def_id))?;
-                let type_name = utils::strip_coq_ident(&type_name);
+                let type_name = base::strip_coq_ident(&type_name);
                 let lit = radium::LiteralTyParam::new(&type_name, &type_name);
                 assoc_types.push(lit);
             }
@@ -563,7 +563,7 @@ impl<'tcx, 'def> TR<'tcx, 'def> {
         param_scope.add_param_env(trait_impl_did, self.env, self.type_translator, self)?;
 
         // parse specification
-        let trait_impl_attrs = utils::filter_tool_attrs(self.env.get_attributes(trait_impl_did));
+        let trait_impl_attrs = attrs::filter_for_tool(self.env.get_attributes(trait_impl_did));
         let mut attr_parser = VerboseTraitImplAttrParser::new(&param_scope);
         let impl_spec = attr_parser
             .parse_trait_impl_attrs(&trait_impl_attrs)
@@ -660,7 +660,7 @@ impl<'def> GenericTraitUse<'def> {
             let ty_name = env.get_assoc_item_name(*ty_did).unwrap();
             let trait_use_ref = self.trait_use.borrow();
             let trait_use = trait_use_ref.as_ref().unwrap();
-            let lit = trait_use.make_assoc_type_use(&utils::strip_coq_ident(&ty_name));
+            let lit = trait_use.make_assoc_type_use(&base::strip_coq_ident(&ty_name));
             assoc_tys.push(lit);
         }
         assoc_tys
diff --git a/rr_frontend/translation/src/traits/requirements.rs b/rr_frontend/translation/src/traits/requirements.rs
index c9667e3..1d4875d 100644
--- a/rr_frontend/translation/src/traits/requirements.rs
+++ b/rr_frontend/translation/src/traits/requirements.rs
@@ -12,7 +12,7 @@ use log::{info, trace};
 use rr_rustc_interface::hir::def_id::DefId;
 use rr_rustc_interface::middle::ty;
 
-use crate::{shims, utils};
+use crate::{search, shims};
 
 /// Get non-trivial trait requirements of a `ParamEnv`,
 /// ordered deterministically.
@@ -58,15 +58,15 @@ pub fn get_nontrivial<'tcx>(
 
 /// Check if this is a built-in trait
 fn is_builtin_trait(tcx: ty::TyCtxt<'_>, trait_did: DefId) -> Option<bool> {
-    let sized_did = utils::try_resolve_did(tcx, &["core", "marker", "Sized"])?;
+    let sized_did = search::try_resolve_did(tcx, &["core", "marker", "Sized"])?;
 
     // TODO: for these, should instead require the primitive encoding of our Coq formalization
-    let send_did = utils::try_resolve_did(tcx, &["core", "marker", "Send"])?;
-    let sync_did = utils::try_resolve_did(tcx, &["core", "marker", "Sync"])?;
-    let copy_did = utils::try_resolve_did(tcx, &["core", "marker", "Copy"])?;
+    let send_did = search::try_resolve_did(tcx, &["core", "marker", "Send"])?;
+    let sync_did = search::try_resolve_did(tcx, &["core", "marker", "Sync"])?;
+    let copy_did = search::try_resolve_did(tcx, &["core", "marker", "Copy"])?;
 
     // used for closures
-    let tuple_did = utils::try_resolve_did(tcx, &["core", "marker", "Tuple"])?;
+    let tuple_did = search::try_resolve_did(tcx, &["core", "marker", "Tuple"])?;
 
     Some(
         trait_did == sized_did
diff --git a/rr_frontend/translation/src/types/local.rs b/rr_frontend/translation/src/types/local.rs
index 7b65af8..daa9aeb 100644
--- a/rr_frontend/translation/src/types/local.rs
+++ b/rr_frontend/translation/src/types/local.rs
@@ -24,7 +24,7 @@ use crate::traits::resolution;
 use crate::types::translator::*;
 use crate::types::tyvars::*;
 use crate::types::{self, scope};
-use crate::{regions, traits, utils};
+use crate::{base, regions, traits};
 
 /// Information we compute when calling a function from another function.
 /// Determines how to specialize the callee's generics in our spec assumption.
@@ -257,7 +257,7 @@ impl<'def, 'tcx> LocalTX<'def, 'tcx> {
         // get name of the method
         let method_name = env.get_assoc_item_name(trait_method_did).unwrap();
         let mangled_method_name =
-            types::mangle_name_with_args(&utils::strip_coq_ident(&method_name), method_args.as_slice());
+            types::mangle_name_with_args(&base::strip_coq_ident(&method_name), method_args.as_slice());
 
         let method_loc_name = trait_spec_use.make_loc_name(&mangled_method_name);
 
diff --git a/rr_frontend/translation/src/types/mod.rs b/rr_frontend/translation/src/types/mod.rs
index 6738373..77ab789 100644
--- a/rr_frontend/translation/src/types/mod.rs
+++ b/rr_frontend/translation/src/types/mod.rs
@@ -19,7 +19,7 @@ use rr_rustc_interface::middle::ty;
 pub use scope::{generate_args_inst_key, GenericsKey};
 pub use translator::{AdtState, CalleeState, FunctionState, STInner, ST, TX};
 
-use crate::utils;
+use crate::base;
 
 /// Mangle a name by appending type parameters to it.
 pub fn mangle_name_with_tys(method_name: &str, args: &[ty::Ty<'_>]) -> String {
@@ -28,7 +28,7 @@ pub fn mangle_name_with_tys(method_name: &str, args: &[ty::Ty<'_>]) -> String {
     for arg in args {
         mangled_name.push_str(format!("_{}", arg).as_str());
     }
-    utils::strip_coq_ident(&mangled_name)
+    base::strip_coq_ident(&mangled_name)
 }
 
 /// Mangle a name by appending generic args to it.
@@ -36,7 +36,7 @@ pub fn mangle_name_with_args(name: &str, args: &[ty::GenericArg<'_>]) -> String
     let mut mangled_base = name.to_owned();
     for arg in args {
         if let ty::GenericArgKind::Type(ty) = arg.unpack() {
-            write!(mangled_base, "_{}", utils::strip_coq_ident(&format!("{ty}"))).unwrap();
+            write!(mangled_base, "_{}", base::strip_coq_ident(&format!("{ty}"))).unwrap();
         }
     }
     mangled_base
diff --git a/rr_frontend/translation/src/types/scope.rs b/rr_frontend/translation/src/types/scope.rs
index 9734296..5ed043e 100644
--- a/rr_frontend/translation/src/types/scope.rs
+++ b/rr_frontend/translation/src/types/scope.rs
@@ -15,6 +15,7 @@ use rr_rustc_interface::hir::def_id::DefId;
 use rr_rustc_interface::middle::ty;
 use rr_rustc_interface::middle::ty::TypeFoldable;
 
+use crate::base;
 use crate::base::*;
 use crate::environment::Environment;
 use crate::spec_parsers::parse_utils::ParamLookup;
@@ -22,7 +23,6 @@ use crate::traits::registry::GenericTraitUse;
 use crate::traits::{self, registry};
 use crate::types::translator::*;
 use crate::types::tyvars::*;
-use crate::utils::strip_coq_ident;
 
 /// Key used for resolving early-bound parameters for function calls.
 /// Invariant: All regions contained in these types should be erased, as type parameter instantiation is
@@ -178,7 +178,7 @@ impl<'tcx, 'def> Params<'tcx, 'def> {
             if let Some(r) = p.as_region() {
                 if let Some(name) = r.get_name() {
                     lft_names.insert(name.as_str().to_owned(), scope.len());
-                    scope.push(Param::Region(strip_coq_ident(name.as_str())));
+                    scope.push(Param::Region(base::strip_coq_ident(name.as_str())));
                 } else {
                     let name = format!("ulft_{region_count}");
                     region_count += 1;
@@ -187,7 +187,7 @@ impl<'tcx, 'def> Params<'tcx, 'def> {
             } else if let Some(ty) = p.as_type() {
                 if let ty::TyKind::Param(x) = ty.kind() {
                     ty_names.insert(x.name.as_str().to_owned(), scope.len());
-                    let name = strip_coq_ident(x.name.as_str());
+                    let name = base::strip_coq_ident(x.name.as_str());
 
                     let lit = if let Some((tcx, of_did)) = with_origin {
                         let origin = Self::determine_origin_of_param(of_did, tcx, *x);
@@ -494,7 +494,7 @@ impl<'a, 'tcx, 'def> From<&'a [ty::GenericParamDef]> for Params<'tcx, 'def> {
         let mut lft_names = HashMap::new();
 
         for p in x {
-            let name = strip_coq_ident(p.name.as_str());
+            let name = base::strip_coq_ident(p.name.as_str());
             match p.kind {
                 ty::GenericParamDefKind::Const { .. } => {
                     scope.push(Param::Const);
diff --git a/rr_frontend/translation/src/types/translator.rs b/rr_frontend/translation/src/types/translator.rs
index 753ad77..9cdf7ab 100644
--- a/rr_frontend/translation/src/types/translator.rs
+++ b/rr_frontend/translation/src/types/translator.rs
@@ -29,7 +29,7 @@ use crate::spec_parsers::struct_spec_parser::{self, InvariantSpecParser, StructF
 use crate::traits::{self, registry};
 use crate::types::scope;
 use crate::types::tyvars::*;
-use crate::utils;
+use crate::{attrs, base, search};
 
 /// A scope tracking the type translation state when translating the body of a function.
 /// This also includes the state needed for tracking trait constraints, as type translation for
@@ -285,7 +285,7 @@ impl<'a, 'def, 'tcx> STInner<'a, 'def, 'tcx> {
                 // TODO: ?
                 if region.has_name() {
                     let name = region.name.as_str();
-                    return Ok(format!("ulft_{}", utils::strip_coq_ident(name)));
+                    return Ok(format!("ulft_{}", base::strip_coq_ident(name)));
                 }
                 return Err(TranslationError::UnknownEarlyRegion(*region));
             },
@@ -954,14 +954,14 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
         let struct_def_init = self.struct_arena.alloc(OnceCell::new());
 
         let tcx = self.env.tcx();
-        let struct_name = utils::strip_coq_ident(&ty.ident(tcx).to_string());
+        let struct_name = base::strip_coq_ident(&ty.ident(tcx).to_string());
 
         self.variant_registry
             .borrow_mut()
             .insert(ty.def_id, (struct_name, struct_def_init, ty, false, None));
 
         let translate_adt = || {
-            let struct_name = utils::strip_coq_ident(&ty.ident(tcx).to_string());
+            let struct_name = base::strip_coq_ident(&ty.ident(tcx).to_string());
             let (variant_def, invariant_def) =
                 self.make_adt_variant(&struct_name, ty, adt, AdtState::new(&mut deps, &scope, &param_env))?;
 
@@ -1021,10 +1021,10 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
 
         let expect_refinement;
         let mut invariant_spec;
-        if utils::has_tool_attr(outer_attrs, "refined_by") {
-            let outer_attrs = utils::filter_tool_attrs(outer_attrs);
+        if attrs::has_tool_attr(outer_attrs, "refined_by") {
+            let outer_attrs = attrs::filter_for_tool(outer_attrs);
             let mut spec_parser = struct_spec_parser::VerboseInvariantSpecParser::new(adt_deps.scope);
-            let ty_name = utils::strip_coq_ident(format!("{}_inv_t", struct_name).as_str());
+            let ty_name = base::strip_coq_ident(format!("{}_inv_t", struct_name).as_str());
             let res = spec_parser
                 .parse_invariant_spec(&ty_name, &outer_attrs)
                 .map_err(TranslationError::FatalError)?;
@@ -1043,7 +1043,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
             let f_name = f.ident(tcx).to_string();
 
             let attrs = self.env.get_attributes(f.did);
-            let attrs = utils::filter_tool_attrs(attrs);
+            let attrs = attrs::filter_for_tool(attrs);
 
             let f_ty = self.env.tcx().type_of(f.did).instantiate_identity();
             let mut ty = self.translate_type_in_state(
@@ -1176,7 +1176,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
     }
 
     fn does_did_match(&self, did: DefId, path: &[&str]) -> bool {
-        let lookup_did = utils::try_resolve_did(self.env.tcx(), path);
+        let lookup_did = search::try_resolve_did(self.env.tcx(), path);
         if let Some(lookup_did) = lookup_did {
             if lookup_did == did {
                 return true;
@@ -1286,7 +1286,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
         let enum_def_init = self.enum_arena.alloc(OnceCell::new());
 
         // TODO: currently a hack, I don't know how to query the name properly
-        let enum_name = utils::strip_coq_ident(format!("{:?}", def).as_str());
+        let enum_name = base::strip_coq_ident(format!("{:?}", def).as_str());
 
         // first thing: figure out the generics we are using here.
         // we need to search all of the variant types for that.
@@ -1315,7 +1315,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
                 // now generate the variant
                 let struct_def_init = self.struct_arena.alloc(OnceCell::new());
 
-                let struct_name = utils::strip_coq_ident(format!("{}_{}", enum_name, v.ident(tcx)).as_str());
+                let struct_name = base::strip_coq_ident(format!("{}_{}", enum_name, v.ident(tcx)).as_str());
                 self.variant_registry
                     .borrow_mut()
                     .insert(v.def_id, (struct_name.clone(), &*struct_def_init, v, true, None));
@@ -1334,7 +1334,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
 
                 // also remember the attributes for additional processing
                 let outer_attrs = self.env.get_attributes(v.def_id);
-                let outer_attrs = utils::filter_tool_attrs(outer_attrs);
+                let outer_attrs = attrs::filter_for_tool(outer_attrs);
                 variant_attrs.push(outer_attrs);
 
                 // finalize the definition
@@ -1368,7 +1368,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
                 enum_spec = spec;
             } else if self.env.has_tool_attribute(def.did(), "refined_by") {
                 let attributes = self.env.get_attributes(def.did());
-                let attributes = utils::filter_tool_attrs(attributes);
+                let attributes = attrs::filter_for_tool(attributes);
 
                 let mut parser = VerboseEnumSpecParser::new(&scope);
 
@@ -1398,7 +1398,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
             // now build the enum itself
             for v in def.variants() {
                 let (variant_ref, _) = self.lookup_adt_variant(v.def_id)?;
-                let variant_name = utils::strip_coq_ident(&v.ident(tcx).to_string());
+                let variant_name = base::strip_coq_ident(&v.ident(tcx).to_string());
                 let discriminant = discrs[&variant_name];
                 enum_builder.add_variant(&variant_name, variant_ref, discriminant);
             }
@@ -1608,7 +1608,7 @@ impl<'def, 'tcx: 'def> TX<'def, 'tcx> {
                             .env
                             .get_assoc_item_name(alias_ty.def_id)
                             .ok_or(traits::Error::NotAnAssocType(alias_ty.def_id))?;
-                        let assoc_type = trait_use.make_assoc_type_use(&utils::strip_coq_ident(&type_name));
+                        let assoc_type = trait_use.make_assoc_type_use(&base::strip_coq_ident(&type_name));
 
                         info!("Resolved projection to {assoc_type:?}");
 
diff --git a/rr_frontend/translation/src/utils.rs b/rr_frontend/translation/src/utils.rs
index ac0ecc2..58af65e 100644
--- a/rr_frontend/translation/src/utils.rs
+++ b/rr_frontend/translation/src/utils.rs
@@ -1,10 +1,9 @@
-// Except for the exceptions specified below, this code is © 2019, ETH Zurich
+// © 2019, ETH Zurich
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
-//
-// The following functions have been adapted from Miri (https://github.com/rust-lang/miri/blob/31fb32e49f42df19b45baccb6aa80c3d726ed6d5/src/helpers.rs#L48) under the MIT license;
-// - `try_resolve_did`
+
+//! Utility functions for manipulating places.
 
 use std::mem;
 
@@ -20,328 +19,6 @@ use serde::{Deserialize, Serialize};
 use crate::spec_parsers::get_export_as_attr;
 use crate::{force_matches, types, Environment};
 
-/// Strip symbols from an identifier to be compatible with Coq.
-/// In particular things like ' or ::.
-pub fn strip_coq_ident(s: &str) -> String {
-    String::from(s)
-        .replace('\'', "")
-        .replace("::", "_")
-        .replace(|c: char| !(c.is_alphanumeric() || c == '_'), "")
-}
-
-/// Gets an instance for a path.
-/// Taken from Miri <https://github.com/rust-lang/miri/blob/31fb32e49f42df19b45baccb6aa80c3d726ed6d5/src/helpers.rs#L48>.
-pub fn try_resolve_did_direct<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
-where
-    T: AsRef<str>,
-{
-    tcx.crates(())
-        .iter()
-        .find(|&&krate| tcx.crate_name(krate).as_str() == path[0].as_ref())
-        .and_then(|krate| {
-            let krate = DefId {
-                krate: *krate,
-                index: CRATE_DEF_INDEX,
-            };
-
-            let mut items: &[middle::metadata::ModChild] = tcx.module_children(krate);
-            let mut path_it = path.iter().skip(1).peekable();
-
-            while let Some(segment) = path_it.next() {
-                for item in mem::take(&mut items) {
-                    let item: &middle::metadata::ModChild = item;
-                    if item.ident.name.as_str() == segment.as_ref() {
-                        if path_it.peek().is_none() {
-                            return Some(item.res.def_id());
-                        }
-
-                        items = tcx.module_children(item.res.def_id());
-                        break;
-                    }
-                }
-            }
-            None
-        })
-}
-
-pub fn try_resolve_did<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
-where
-    T: AsRef<str>,
-{
-    if let Some(did) = try_resolve_did_direct(tcx, path) {
-        return Some(did);
-    }
-
-    // if the first component is "std", try if we can replace it with "alloc" or "core"
-    if path[0].as_ref() == "std" {
-        let mut components: Vec<_> = path.iter().map(|x| x.as_ref().to_owned()).collect();
-        components[0] = "core".to_owned();
-        if let Some(did) = try_resolve_did_direct(tcx, &components) {
-            return Some(did);
-        }
-        // try "alloc"
-        components[0] = "alloc".to_owned();
-        try_resolve_did_direct(tcx, &components)
-    } else {
-        None
-    }
-}
-
-/// Determine whether the two argument lists match for the type positions (ignoring consts and regions).
-/// The first argument is the authority determining which argument positions are types.
-/// The second argument may contain `None` for non-type positions.
-fn args_match_types<'tcx>(
-    reference: &[ty::GenericArg<'tcx>],
-    compare: &[Option<ty::GenericArg<'tcx>>],
-) -> bool {
-    if reference.len() != compare.len() {
-        return false;
-    }
-
-    for (arg1, arg2) in reference.iter().zip(compare.iter()) {
-        if let Some(ty1) = arg1.as_type() {
-            if let Some(arg2) = arg2 {
-                if let Some(ty2) = arg2.as_type() {
-                    if ty1 != ty2 {
-                        return false;
-                    }
-                } else {
-                    return false;
-                }
-            } else {
-                return false;
-            }
-        }
-    }
-    true
-}
-
-// Useful queries:
-//tcx.trait_id_of_impl
-//tcx.associated_items
-//tcx.impl_trait_parent
-//tcx.implementations_of_trait
-//tcx.trait_impls_of
-//tcx.trait_impls_in_crate
-/// Try to resolve the `DefId` of an implementation of a trait for a particular type.
-/// Note that this does not, in general, find a unique solution, in case there are complex things
-/// with different where clauses going on.
-pub fn try_resolve_trait_impl_did<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_did: DefId,
-    trait_args: &[Option<ty::GenericArg<'tcx>>],
-    for_type: ty::Ty<'tcx>,
-) -> Option<DefId> {
-    // get all impls of this trait
-    let impls: &ty::trait_def::TraitImpls = tcx.trait_impls_of(trait_did);
-
-    let simplified_type =
-        middle::ty::fast_reject::simplify_type(tcx, for_type, ty::fast_reject::TreatParams::AsCandidateKey)?;
-    let defs = impls.non_blanket_impls().get(&simplified_type)?;
-    info!("found implementations: {:?}", impls);
-
-    let mut solution = None;
-    for did in defs {
-        let impl_self_ty: ty::Ty<'tcx> = tcx.type_of(did).instantiate_identity();
-        let impl_self_ty = types::normalize_in_function(*did, tcx, impl_self_ty).unwrap();
-
-        // check if this is an implementation for the right type
-        // TODO: is this the right way to compare the types?
-        if impl_self_ty == for_type {
-            let impl_ref: Option<ty::EarlyBinder<ty::TraitRef<'_>>> = tcx.impl_trait_ref(did);
-
-            if let Some(impl_ref) = impl_ref {
-                let impl_ref = types::normalize_in_function(*did, tcx, impl_ref.skip_binder()).unwrap();
-
-                let this_impl_args = impl_ref.args;
-                // filter by the generic instantiation for the trait
-                info!("found impl with args {:?}", this_impl_args);
-                // args has self at position 0 and generics of the trait at position 1..
-
-                // check if the generic argument types match up
-                if !args_match_types(&this_impl_args.as_slice()[1..], trait_args) {
-                    continue;
-                }
-
-                info!("found impl {:?}", impl_ref);
-                if solution.is_some() {
-                    println!(
-                        "Warning: Ambiguous resolution for impl of trait {:?} on type {:?}; solution {:?} but found also {:?}",
-                        trait_did,
-                        for_type,
-                        solution.unwrap(),
-                        impl_ref.def_id,
-                    );
-                } else {
-                    solution = Some(*did);
-                }
-            }
-        }
-    }
-
-    solution
-}
-
-/// Try to resolve the `DefId` of a method in an implementation of a trait for a particular type.
-/// Note that this does not, in general, find a unique solution, in case there are complex things
-/// with different where clauses going on.
-pub fn try_resolve_trait_method_did<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_did: DefId,
-    trait_args: &[Option<ty::GenericArg<'tcx>>],
-    method_name: &str,
-    for_type: ty::Ty<'tcx>,
-) -> Option<DefId> {
-    // get all impls of this trait
-    let impls: &ty::trait_def::TraitImpls = tcx.trait_impls_of(trait_did);
-
-    let simplified_type =
-        middle::ty::fast_reject::simplify_type(tcx, for_type, ty::fast_reject::TreatParams::AsCandidateKey)?;
-    let defs = impls.non_blanket_impls().get(&simplified_type)?;
-    info!("found implementations: {:?}", impls);
-
-    let mut solution = None;
-    for did in defs {
-        let impl_self_ty: ty::Ty<'tcx> = tcx.type_of(did).instantiate_identity();
-        let impl_self_ty = types::normalize_in_function(*did, tcx, impl_self_ty).unwrap();
-
-        // check if this is an implementation for the right type
-        // TODO: is this the right way to compare the types?
-        if impl_self_ty == for_type {
-            let impl_ref: Option<ty::EarlyBinder<ty::TraitRef<'_>>> = tcx.impl_trait_ref(did);
-
-            if let Some(impl_ref) = impl_ref {
-                let impl_ref = types::normalize_in_function(*did, tcx, impl_ref.skip_binder()).unwrap();
-
-                let this_impl_args = impl_ref.args;
-                // filter by the generic instantiation for the trait
-                info!("found impl with args {:?}", this_impl_args);
-                // args has self at position 0 and generics of the trait at position 1..
-
-                // check if the generic argument types match up
-                if !args_match_types(&this_impl_args.as_slice()[1..], trait_args) {
-                    continue;
-                }
-
-                let impl_assoc_items: &ty::AssocItems = tcx.associated_items(did);
-                // find the right item
-                if let Some(item) = impl_assoc_items.find_by_name_and_kind(
-                    tcx,
-                    span::symbol::Ident::from_str(method_name),
-                    ty::AssocKind::Fn,
-                    trait_did,
-                ) {
-                    info!("found impl {:?} with item {:?}", impl_ref, item);
-                    if solution.is_some() {
-                        println!(
-                            "Warning: Ambiguous resolution for method {method_name} of trait {:?} on type {:?}; solution {:?} but found also {:?}",
-                            trait_did,
-                            for_type,
-                            solution.unwrap(),
-                            item.def_id
-                        );
-                    } else {
-                        solution = Some(item.def_id);
-                    }
-                }
-            }
-        }
-    }
-
-    solution
-}
-
-/// Try to get a defid of a method at the given path.
-/// This does not handle trait methods.
-/// This also does not handle overlapping method definitions/specialization well.
-pub fn try_resolve_method_did_direct<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
-where
-    T: AsRef<str>,
-{
-    tcx.crates(())
-        .iter()
-        .find(|&&krate| tcx.crate_name(krate).as_str() == path[0].as_ref())
-        .and_then(|krate| {
-            let krate = DefId {
-                krate: *krate,
-                index: CRATE_DEF_INDEX,
-            };
-
-            let mut items: &[middle::metadata::ModChild] = tcx.module_children(krate);
-            let mut path_it = path.iter().skip(1).peekable();
-
-            while let Some(segment) = path_it.next() {
-                //info!("items to look at: {:?}", items);
-                for item in mem::take(&mut items) {
-                    let item: &middle::metadata::ModChild = item;
-
-                    if item.ident.name.as_str() != segment.as_ref() {
-                        continue;
-                    }
-
-                    info!("taking path: {:?}", segment.as_ref());
-                    if path_it.peek().is_none() {
-                        return Some(item.res.def_id());
-                    }
-
-                    // just the method remaining
-                    if path_it.len() != 1 {
-                        items = tcx.module_children(item.res.def_id());
-                        break;
-                    }
-
-                    let did: DefId = item.res.def_id();
-                    let impls: &[DefId] = tcx.inherent_impls(did);
-                    info!("trying to find method among impls {:?}", impls);
-
-                    let find = path_it.next().unwrap();
-                    for impl_did in impls {
-                        //let ty = tcx.type_of(*impl_did);
-                        //info!("type of impl: {:?}", ty);
-                        let items: &ty::AssocItems = tcx.associated_items(impl_did);
-                        //info!("items here: {:?}", items);
-                        // TODO more robust error handling if there are multiple matches.
-                        for item in items.in_definition_order() {
-                            //info!("comparing: {:?} with {:?}", item.name.as_str(), find);
-                            if item.name.as_str() == find.as_ref() {
-                                return Some(item.def_id);
-                            }
-                        }
-                        //info!("impl items: {:?}", items);
-                    }
-
-                    //info!("inherent impls for {:?}: {:?}", did, impls);
-                    return None;
-                }
-            }
-
-            None
-        })
-}
-
-pub fn try_resolve_method_did<T>(tcx: TyCtxt<'_>, path: &[T]) -> Option<DefId>
-where
-    T: AsRef<str>,
-{
-    if let Some(did) = try_resolve_method_did_direct(tcx, path) {
-        return Some(did);
-    }
-
-    // if the first component is "std", try if we can replace it with "alloc" or "core"
-    if path[0].as_ref() == "std" {
-        let mut components: Vec<_> = path.iter().map(|x| x.as_ref().to_owned()).collect();
-        components[0] = "core".to_owned();
-        if let Some(did) = try_resolve_method_did_direct(tcx, &components) {
-            return Some(did);
-        }
-        // try "alloc"
-        components[0] = "alloc".to_owned();
-        try_resolve_method_did_direct(tcx, &components)
-    } else {
-        None
-    }
-}
-
 /// Check if the place `potential_prefix` is a prefix of `place`. For example:
 ///
 /// + `is_prefix(x.f, x.f) == true`
@@ -569,64 +246,3 @@ impl<'tcx> VecPlace<'tcx> {
         self.components.len()
     }
 }
-
-/// Check if `<tool>::<name>` is among the attributes, where `tool` is determined by the
-/// `spec_hotword` config.
-/// Any arguments of the attribute are ignored.
-pub fn has_tool_attr(attrs: &[ast::Attribute], name: &str) -> bool {
-    get_tool_attr(attrs, name).is_some()
-}
-
-/// Get the arguments for a tool attribute, if it exists.
-pub fn get_tool_attr<'a>(attrs: &'a [ast::Attribute], name: &str) -> Option<&'a ast::AttrArgs> {
-    attrs.iter().find_map(|attr| match &attr.kind {
-        ast::AttrKind::Normal(na) => {
-            let segments = &na.item.path.segments;
-            let args = &na.item.args;
-            (segments.len() == 2
-                && segments[0].ident.as_str() == rrconfig::spec_hotword().as_str()
-                && segments[1].ident.as_str() == name)
-                .then_some(args)
-        },
-        _ => None,
-    })
-}
-
-/// Check if `<tool>::name` is among the filtered attributes.
-pub fn has_tool_attr_filtered(attrs: &[&ast::AttrItem], name: &str) -> bool {
-    attrs.iter().any(|item| {
-        let segments = &item.path.segments;
-        segments.len() == 2
-            && segments[0].ident.as_str() == rrconfig::spec_hotword().as_str()
-            && segments[1].ident.as_str() == name
-    })
-}
-
-/// Check if any attribute starting with `<tool>` is among the attributes.
-pub fn has_any_tool_attr(attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(|attr| match &attr.kind {
-        ast::AttrKind::Normal(na) => {
-            let segments = &na.item.path.segments;
-            segments[0].ident.as_str() == rrconfig::spec_hotword().as_str()
-        },
-        _ => false,
-    })
-}
-
-/// Get all tool attributes, i.e. attributes of the shape `<tool>::attr`, where `tool` is
-/// determined by the `spec_hotword` config.
-pub fn filter_tool_attrs(attrs: &[ast::Attribute]) -> Vec<&ast::AttrItem> {
-    attrs
-        .iter()
-        .filter_map(|attr| match &attr.kind {
-            ast::AttrKind::Normal(na) => {
-                let item = &na.item;
-
-                let seg = item.path.segments.get(0)?;
-
-                (seg.ident.name.as_str() == rrconfig::spec_hotword()).then_some(item)
-            },
-            _ => None,
-        })
-        .collect()
-}
-- 
GitLab