use hax_frontend_exporter::{DefKind, DefPathItem, DisambiguatedDefPathItem};
use hax_rust_engine_macros::*;
use crate::interning::{Internable, Interned, InterningTable};
mod compact_serialization;
pub(crate) mod generated_names;
pub mod view;
#[derive_group_for_ast]
struct DefIdInner {
krate: String,
path: Vec<DisambiguatedDefPathItem>,
parent: Option<DefId>,
kind: DefKind,
}
impl DefIdInner {
fn to_debug_string(&self) -> String {
fn disambiguator_suffix(disambiguator: u32) -> String {
if disambiguator == 0 {
"".into()
} else {
format!("__{disambiguator}")
}
}
use itertools::Itertools;
std::iter::once(self.krate.clone())
.chain(self.path.iter().map(|item| match &item.data {
DefPathItem::TypeNs(s)
| DefPathItem::ValueNs(s)
| DefPathItem::MacroNs(s)
| DefPathItem::LifetimeNs(s) => s.clone(),
DefPathItem::Impl => "impl".into(),
other => format!("{other:?}"),
} + &disambiguator_suffix(item.disambiguator)))
.join("::")
}
}
use std::{
cell::{LazyCell, RefCell},
collections::HashMap,
sync::{LazyLock, Mutex},
};
impl Internable for DefIdInner {
fn interning_table() -> &'static Mutex<InterningTable<Self>> {
static TABLE: LazyLock<Mutex<InterningTable<DefIdInner>>> =
LazyLock::new(|| Mutex::new(InterningTable::default()));
&TABLE
}
}
type DefId = Interned<DefIdInner>;
#[derive_group_for_ast]
struct ExplicitDefId {
is_constructor: bool,
def_id: DefId,
}
impl ExplicitDefId {
fn parent(&self) -> Option<Self> {
let def_id = &self.def_id;
let is_constructor = matches!(&def_id.kind, DefKind::Field);
Some(Self {
is_constructor,
def_id: def_id.parent?,
})
}
fn parents(&self) -> impl Iterator<Item = Self> {
std::iter::successors(Some(self.clone()), |id| id.parent())
}
fn into_global_id_inner(self) -> GlobalIdInner {
GlobalIdInner::Concrete(ConcreteId {
def_id: self,
moved: None,
suffix: None,
})
}
}
#[derive_group_for_ast]
pub struct FreshModule {
id: usize,
hints: Vec<ExplicitDefId>,
label: String,
}
#[derive_group_for_ast]
pub enum ReservedSuffix {
Pre,
Post,
Cast,
}
#[derive_group_for_ast]
pub struct ConcreteId {
def_id: ExplicitDefId,
moved: Option<FreshModule>,
suffix: Option<ReservedSuffix>,
}
#[derive_group_for_ast]
enum GlobalIdInner {
Concrete(ConcreteId),
Tuple(TupleId),
}
#[derive_group_for_ast]
#[derive(Copy)]
pub enum TupleId {
Type {
length: usize,
},
Constructor {
length: usize,
},
Field {
length: usize,
field: usize,
},
}
impl From<TupleId> for GlobalId {
fn from(tuple_id: TupleId) -> Self {
Self(GlobalIdInner::Tuple(tuple_id).intern())
}
}
impl From<TupleId> for ConcreteId {
fn from(value: TupleId) -> Self {
fn patch_def_id(template: GlobalId, length: usize, field: usize) -> ConcreteId {
let GlobalIdInner::Concrete(mut concrete_id) = template.0.get().clone() else {
unreachable!()
};
fn inner(did: &mut DefIdInner, length: usize, field: usize) {
for DisambiguatedDefPathItem { data, .. } in &mut did.path {
if let DefPathItem::ValueNs(s) = data
&& s == "1"
{
*s = field.to_string()
}
if let DefPathItem::TypeNs(s) = data
&& s.starts_with("Tuple")
{
*s = format!("Tuple{length}")
}
}
if let Some(parent) = did.parent {
let mut parent = parent.get().clone();
inner(&mut parent, length, field);
did.parent = Some(parent.intern());
}
}
let mut did = concrete_id.def_id.def_id.get().clone();
inner(&mut did, length, field);
concrete_id.def_id.def_id = did.intern();
concrete_id
}
use crate::names::rust_primitives::hax;
match value {
TupleId::Type { length } => patch_def_id(hax::Tuple2, length, 0),
TupleId::Constructor { length } => patch_def_id(hax::Tuple2::Constructor, length, 0),
TupleId::Field { length, field } => patch_def_id(hax::Tuple2::_1, length, field),
}
}
}
#[derive_group_for_ast]
#[derive(Copy)]
pub struct GlobalId(Interned<GlobalIdInner>);
impl GlobalId {
pub fn krate(self) -> &'static str {
&ConcreteId::from_global_id(self).def_id.def_id.krate
}
pub fn to_debug_string(self) -> String {
ConcreteId::from_global_id(self).to_debug_string()
}
pub fn is_constructor(self) -> bool {
self.0.get().is_constructor()
}
pub fn is_projector(self) -> bool {
self.0.get().is_projector()
}
pub fn is_precondition(self) -> bool {
self.0.get().is_precondition()
}
pub fn is_postcondition(self) -> bool {
self.0.get().is_postcondition()
}
pub fn view(self) -> view::View {
ConcreteId::from_global_id(self).view()
}
pub fn expect_tuple(self) -> Option<TupleId> {
match self.0.get() {
GlobalIdInner::Concrete(..) => None,
GlobalIdInner::Tuple(tuple_id) => Some(*tuple_id),
}
}
pub fn mod_only_closest_parent(self) -> Self {
let concrete_id = ConcreteId::from_global_id(self).mod_only_closest_parent();
Self(GlobalIdInner::Concrete(concrete_id).intern())
}
}
impl GlobalIdInner {
fn def_id(&self) -> DefId {
ConcreteId::from_global_id(GlobalId(self.intern()))
.def_id
.def_id
}
fn explicit_def_id(&self) -> Option<ExplicitDefId> {
match self {
GlobalIdInner::Concrete(concrete_id) => Some(concrete_id.def_id.clone()),
GlobalIdInner::Tuple(_) => None,
}
}
pub fn is_constructor(&self) -> bool {
match self {
GlobalIdInner::Concrete(concrete_id) => concrete_id.def_id.is_constructor,
GlobalIdInner::Tuple(TupleId::Constructor { .. }) => true,
_ => false,
}
}
pub fn is_projector(&self) -> bool {
match self {
GlobalIdInner::Concrete(concrete_id) => {
matches!(concrete_id.def_id.def_id.get().kind, DefKind::Field)
}
GlobalIdInner::Tuple(TupleId::Field { .. }) => true,
_ => false,
}
}
pub fn is_precondition(&self) -> bool {
matches!(self, GlobalIdInner::Concrete(concrete_id) if matches!(concrete_id.suffix, Some(ReservedSuffix::Pre)))
}
pub fn is_postcondition(&self) -> bool {
matches!(self, GlobalIdInner::Concrete(concrete_id) if matches!(concrete_id.suffix, Some(ReservedSuffix::Post)))
}
}
impl ConcreteId {
fn view(&self) -> view::View {
self.def_id.clone().into()
}
fn mod_only_closest_parent(&self) -> Self {
let mut parents = self.def_id.parents().collect::<Vec<_>>();
parents.reverse();
let def_id = parents
.into_iter()
.take_while(|id| matches!(id.def_id.kind, DefKind::Mod))
.next()
.expect("Invariant broken: a DefId must always contain at least on `mod` segment (the crate)");
Self {
def_id,
moved: self.moved.clone(),
suffix: None,
}
}
fn from_global_id(value: GlobalId) -> &'static ConcreteId {
thread_local! {
static MEMO: LazyCell<RefCell<HashMap<GlobalId, &'static ConcreteId>>> =
LazyCell::new(|| RefCell::new(HashMap::new()));
}
MEMO.with(|memo| {
let mut memo = memo.borrow_mut();
let reference: &'static ConcreteId =
memo.entry(value).or_insert_with(|| match value.0.get() {
GlobalIdInner::Concrete(concrete_id) => concrete_id,
GlobalIdInner::Tuple(tuple_id) => {
match GlobalIdInner::Concrete((*tuple_id).into()).intern().get() {
GlobalIdInner::Concrete(concrete_id) => concrete_id,
GlobalIdInner::Tuple(_) => unreachable!(),
}
}
});
reference
})
}
fn to_debug_string(&self) -> String {
self.def_id.def_id.get().to_debug_string()
}
}
impl PartialEq<DefId> for GlobalId {
fn eq(&self, other: &DefId) -> bool {
if let GlobalIdInner::Concrete(concrete) = self.0.get() {
&concrete.def_id.def_id == other
} else {
false
}
}
}
impl PartialEq<GlobalId> for DefId {
fn eq(&self, other: &GlobalId) -> bool {
other == self
}
}
impl PartialEq<ExplicitDefId> for GlobalId {
fn eq(&self, other: &ExplicitDefId) -> bool {
self == &other.def_id
}
}
impl PartialEq<GlobalId> for ExplicitDefId {
fn eq(&self, other: &GlobalId) -> bool {
other == &self.def_id
}
}