hax_rust_engine/ast/identifiers/
global_id.rs1use hax_frontend_exporter::{DefKind, DefPathItem, DisambiguatedDefPathItem};
35use hax_rust_engine_macros::*;
36
37use crate::interning::{Internable, Interned, InterningTable};
38
39mod compact_serialization;
40pub(crate) mod generated_names;
41pub mod view;
42
43#[derive_group_for_ast]
45struct DefIdInner {
46 krate: String,
48 path: Vec<DisambiguatedDefPathItem>,
50 parent: Option<DefId>,
53 kind: DefKind,
55}
56
57impl From<hax_frontend_exporter::DefId> for DefIdInner {
58 fn from(value: hax_frontend_exporter::DefId) -> Self {
59 Self {
60 krate: value.krate.clone(),
61 path: value.path.clone(),
62 parent: value
63 .parent
64 .clone()
65 .map(|def_id| DefIdInner::from(def_id).intern()),
66 kind: value.kind.clone(),
67 }
68 }
69}
70
71impl DefIdInner {
72 fn rename_krate(&self, name: &str) -> Self {
74 let mut def_id = self.clone();
75 def_id.krate = name.into();
76 def_id.parent = def_id.parent.map(|parent: DefId| parent.rename_krate(name));
77 def_id
78 }
79
80 fn to_debug_string(&self) -> String {
81 fn disambiguator_suffix(disambiguator: u32) -> String {
82 if disambiguator == 0 {
83 "".into()
84 } else {
85 format!("__{disambiguator}")
86 }
87 }
88 use itertools::Itertools;
89 std::iter::once(self.krate.clone())
90 .chain(self.path.iter().map(|item| match &item.data {
91 DefPathItem::TypeNs(s)
92 | DefPathItem::ValueNs(s)
93 | DefPathItem::MacroNs(s)
94 | DefPathItem::LifetimeNs(s) => s.clone(),
95 DefPathItem::Impl => "impl".into(),
96 other => format!("{other:?}"),
97 } + &disambiguator_suffix(item.disambiguator)))
98 .join("::")
99 }
100}
101
102use std::{
103 cell::{LazyCell, RefCell},
104 collections::HashMap,
105 sync::{LazyLock, Mutex},
106};
107impl Internable for DefIdInner {
108 fn interning_table() -> &'static Mutex<InterningTable<Self>> {
109 static TABLE: LazyLock<Mutex<InterningTable<DefIdInner>>> =
110 LazyLock::new(|| Mutex::new(InterningTable::default()));
111 &TABLE
112 }
113}
114
115type DefId = Interned<DefIdInner>;
117
118impl DefId {
119 fn rename_krate(&self, name: &str) -> Self {
121 (*self).get().rename_krate(name).intern()
122 }
123}
124
125#[derive_group_for_ast]
141struct ExplicitDefId {
142 is_constructor: bool,
144 def_id: DefId,
146}
147
148impl ExplicitDefId {
149 fn parent(&self) -> Option<Self> {
151 let def_id = &self.def_id;
152 let is_constructor = matches!(&def_id.kind, DefKind::Field);
153 Some(Self {
154 is_constructor,
155 def_id: def_id.parent?,
156 })
157 }
158 fn parents(&self) -> impl Iterator<Item = Self> {
161 std::iter::successors(Some(self.clone()), |id| id.parent())
162 }
163
164 fn rename_krate(&mut self, name: &str) {
166 self.def_id = self.def_id.rename_krate(name);
167 }
168
169 fn into_global_id_inner(self) -> GlobalIdInner {
171 GlobalIdInner::Concrete(ConcreteId {
172 def_id: self,
173 moved: None,
174 suffix: None,
175 })
176 }
177}
178
179#[derive_group_for_ast]
181pub struct FreshModule {
182 id: usize,
184 hints: Vec<ExplicitDefId>,
186 label: String,
188}
189
190impl FreshModule {
191 fn view(&self) -> view::View {
193 self.clone().into()
194 }
195
196 fn rename_krate(&self, name: &str) -> Self {
198 let hints = self
199 .hints
200 .iter()
201 .map(|hint| {
202 let mut hint = hint.clone();
203 hint.rename_krate(name);
204 hint
205 })
206 .collect();
207 Self {
208 hints,
209 id: self.id,
210 label: self.label.clone(),
211 }
212 }
213
214 fn to_debug_string(&self) -> String {
215 format!("fresh_module_{}_{}", self.id, self.label)
216 }
217}
218
219#[derive_group_for_ast]
221pub enum ReservedSuffix {
222 Pre,
224 Post,
226 Cast,
228}
229
230#[derive_group_for_ast]
232pub struct ConcreteId {
233 def_id: ExplicitDefId,
235 moved: Option<FreshModule>,
237 suffix: Option<ReservedSuffix>,
239}
240
241#[derive_group_for_ast]
243enum GlobalIdInner {
244 Concrete(ConcreteId),
246 FreshModule(FreshModule),
248 Tuple(TupleId),
250}
251
252#[derive_group_for_ast]
253#[derive(Copy)]
254pub enum TupleId {
266 Type {
270 length: usize,
272 },
273
274 Constructor {
279 length: usize,
281 },
282
283 Field {
287 length: usize,
289 field: usize,
291 },
292}
293
294impl From<TupleId> for GlobalId {
295 fn from(tuple_id: TupleId) -> Self {
296 Self(GlobalIdInner::Tuple(tuple_id).intern())
297 }
298}
299
300impl TupleId {
301 fn into_owned_concrete_id(self) -> ConcreteId {
303 fn patch_def_id(template: GlobalId, length: usize, field: usize) -> ConcreteId {
304 let GlobalIdInner::Concrete(mut concrete_id) = template.0.get().clone() else {
305 unreachable!()
313 };
314 fn inner(did: &mut DefIdInner, length: usize, field: usize) {
315 for DisambiguatedDefPathItem { data, .. } in &mut did.path {
316 if let DefPathItem::ValueNs(s) = data
318 && s == "1"
319 {
320 *s = field.to_string()
321 }
322 if let DefPathItem::TypeNs(s) = data
324 && s.starts_with("Tuple")
325 {
326 *s = format!("Tuple{length}")
327 }
328 }
329 if let Some(parent) = did.parent {
330 let mut parent = parent.get().clone();
331 inner(&mut parent, length, field);
332 did.parent = Some(parent.intern());
333 }
334 }
335 let mut did = concrete_id.def_id.def_id.get().clone();
336 inner(&mut did, length, field);
337 concrete_id.def_id.def_id = did.intern();
338 concrete_id
339 }
340
341 use crate::names::rust_primitives::hax;
342
343 match self {
344 TupleId::Type { length } => patch_def_id(hax::Tuple2, length, 0),
345 TupleId::Constructor { length } => patch_def_id(hax::Tuple2::Constructor, length, 0),
346 TupleId::Field { length, field } => patch_def_id(hax::Tuple2::_1, length, field),
347 }
348 }
349
350 pub fn as_concreteid(self) -> &'static ConcreteId {
354 thread_local! {
355 static MEMO: LazyCell<RefCell<HashMap<TupleId, &'static ConcreteId>>> =
356 LazyCell::new(|| RefCell::new(HashMap::new()));
357 }
358
359 MEMO.with(|memo| {
360 let mut memo = memo.borrow_mut();
361 let reference: &'static ConcreteId = memo.entry(self).or_insert_with(|| {
362 match GlobalIdInner::Concrete(self.into_owned_concrete_id())
363 .intern()
364 .get()
365 {
366 GlobalIdInner::Concrete(concrete_id) => concrete_id,
367 GlobalIdInner::FreshModule(_) | GlobalIdInner::Tuple(_) => {
368 unreachable!()
371 }
372 }
373 });
374 reference
375 })
376 }
377}
378
379#[derive_group_for_ast]
381#[derive(Copy)]
382pub struct GlobalId(Interned<GlobalIdInner>);
383
384impl GlobalId {
385 pub fn from_frontend(id: hax_frontend_exporter::DefId, is_value: bool) -> Self {
387 let mut def_id: DefIdInner = id.into();
388 use hax_frontend_exporter::DefKind as DK;
389
390 let mut popped_ctor = false;
391 if let Some(last) = def_id.path.last()
392 && matches!(&last.data, DefPathItem::Ctor)
393 {
394 def_id.path.pop();
395 popped_ctor = true;
396 if let Some(parent) = def_id.parent.as_ref() {
397 def_id.parent = parent.parent;
398 }
399 }
400
401 let is_constructor = is_value
402 && (matches!(&def_id.kind, DK::Variant | DK::Union | DK::Struct) || popped_ctor);
403 let inner = GlobalIdInner::Concrete(ConcreteId {
404 def_id: ExplicitDefId {
405 is_constructor,
406 def_id: def_id.intern(),
407 },
408 moved: None,
409 suffix: None,
410 });
411 Self(inner.intern())
412 }
413
414 pub fn krate(self) -> &'static str {
416 match self.0.get() {
417 GlobalIdInner::FreshModule(fresh_module) => {
418 &fresh_module
419 .hints
420 .first()
421 .expect("The hint list should always be non-empty")
422 .def_id
423 .krate
424 }
425 GlobalIdInner::Concrete(concrete_id) => &concrete_id.def_id.def_id.krate,
426 GlobalIdInner::Tuple(tuple_id) => &tuple_id.as_concreteid().def_id.def_id.krate,
427 }
428 }
429
430 pub fn to_debug_string(self) -> String {
433 match self.0.get() {
434 GlobalIdInner::Concrete(id) => id.to_debug_string(),
435 GlobalIdInner::FreshModule(id) => id.to_debug_string(),
436 GlobalIdInner::Tuple(id) => id.as_concreteid().to_debug_string(),
437 }
438 }
439
440 pub fn is_constructor(self) -> bool {
442 self.0.get().is_constructor()
443 }
444
445 pub fn is_projector(self) -> bool {
447 self.0.get().is_projector()
448 }
449
450 pub fn is_precondition(self) -> bool {
453 self.0.get().is_precondition()
454 }
455
456 pub fn is_postcondition(self) -> bool {
459 self.0.get().is_postcondition()
460 }
461
462 pub fn view(self) -> view::View {
464 match self.0.get() {
465 GlobalIdInner::FreshModule(id) => id.view(),
466 GlobalIdInner::Concrete(id) => id.view(),
467 GlobalIdInner::Tuple(id) => id.as_concreteid().view(),
468 }
469 }
470
471 pub fn expect_tuple(self) -> Option<TupleId> {
473 match self.0.get() {
474 GlobalIdInner::Tuple(tuple_id) => Some(*tuple_id),
475 _ => None,
476 }
477 }
478
479 pub fn mod_only_closest_parent(self) -> Self {
482 match self.0.get() {
483 GlobalIdInner::FreshModule(_) => self,
484 GlobalIdInner::Concrete(concrete_id) => concrete_id.mod_only_closest_parent().into(),
485 GlobalIdInner::Tuple(tuple_id) => {
486 tuple_id.as_concreteid().mod_only_closest_parent().into()
487 }
488 }
489 }
490
491 pub fn rename_krate(self, name: &str) -> Self {
493 match self.0.get() {
494 GlobalIdInner::FreshModule(fresh_module) => {
495 Self(GlobalIdInner::FreshModule(fresh_module.rename_krate(name)).intern())
496 }
497 GlobalIdInner::Concrete(concrete_id) => {
498 let mut concrete_id = concrete_id.clone();
499 concrete_id.rename_krate(name);
500 Self(GlobalIdInner::Concrete(concrete_id).intern())
501 }
502 GlobalIdInner::Tuple(tuple_id) => {
503 let mut concrete_id = tuple_id.as_concreteid().clone();
504 concrete_id.rename_krate(name);
505 Self(GlobalIdInner::Concrete(concrete_id).intern())
506 }
507 }
508 }
509
510 pub fn with_suffix(self, suffix: ReservedSuffix) -> Self {
512 match self.0.get() {
513 GlobalIdInner::Concrete(concrete_id) => Self(
514 GlobalIdInner::Concrete(ConcreteId {
515 suffix: Some(suffix),
516 ..concrete_id.clone()
517 })
518 .intern(),
519 ),
520 GlobalIdInner::Tuple(_) | GlobalIdInner::FreshModule(_) => self,
521 }
522 }
523}
524
525impl GlobalIdInner {
526 fn explicit_def_id(&self) -> Option<ExplicitDefId> {
528 match self {
529 GlobalIdInner::Concrete(concrete_id) => Some(concrete_id.def_id.clone()),
530 _ => None,
531 }
532 }
533
534 pub fn is_constructor(&self) -> bool {
536 match self {
537 GlobalIdInner::Concrete(concrete_id) => concrete_id.def_id.is_constructor,
538 GlobalIdInner::Tuple(TupleId::Constructor { .. }) => true,
539 _ => false,
540 }
541 }
542
543 pub fn is_projector(&self) -> bool {
545 match self {
546 GlobalIdInner::Concrete(concrete_id) => {
547 matches!(concrete_id.def_id.def_id.get().kind, DefKind::Field)
548 }
549 GlobalIdInner::Tuple(TupleId::Field { .. }) => true,
550 _ => false,
551 }
552 }
553
554 pub fn is_precondition(&self) -> bool {
557 matches!(self, GlobalIdInner::Concrete(concrete_id) if matches!(concrete_id.suffix, Some(ReservedSuffix::Pre)))
558 }
559
560 pub fn is_postcondition(&self) -> bool {
563 matches!(self, GlobalIdInner::Concrete(concrete_id) if matches!(concrete_id.suffix, Some(ReservedSuffix::Post)))
564 }
565}
566
567impl From<ConcreteId> for GlobalId {
568 fn from(concrete_id: ConcreteId) -> Self {
569 Self(GlobalIdInner::Concrete(concrete_id).intern())
570 }
571}
572
573impl ConcreteId {
574 fn view(&self) -> view::View {
576 view::View::from(self.def_id.clone()).with_suffix(self.suffix.clone())
577 }
578
579 fn mod_only_closest_parent(&self) -> Self {
582 let mut parents = self.def_id.parents().collect::<Vec<_>>();
583 parents.reverse();
584 let def_id = parents
585 .into_iter()
586 .take_while(|id| matches!(id.def_id.kind, DefKind::Mod))
587 .last()
588 .expect("Invariant broken: a DefId must always contain at least on `mod` segment (the crate)");
589 Self {
590 def_id,
591 moved: self.moved.clone(),
592 suffix: None,
593 }
594 }
595
596 fn rename_krate(&mut self, name: &str) {
597 self.def_id.rename_krate(name);
598 }
599
600 fn to_debug_string(&self) -> String {
601 self.def_id.def_id.get().to_debug_string()
602 }
603}
604
605impl PartialEq<DefId> for GlobalId {
606 fn eq(&self, other: &DefId) -> bool {
607 if let GlobalIdInner::Concrete(concrete) = self.0.get() {
608 &concrete.def_id.def_id == other
609 } else {
610 false
611 }
612 }
613}
614impl PartialEq<GlobalId> for DefId {
615 fn eq(&self, other: &GlobalId) -> bool {
616 other == self
617 }
618}
619
620impl PartialEq<ExplicitDefId> for GlobalId {
621 fn eq(&self, other: &ExplicitDefId) -> bool {
622 self == &other.def_id
623 }
624}
625
626impl PartialEq<GlobalId> for ExplicitDefId {
627 fn eq(&self, other: &GlobalId) -> bool {
628 other == &self.def_id
629 }
630}