hax_rust_engine/ast/identifiers/global_id/view.rs
1//! Helpers to view and reason about **path segments** in Rust items.
2//!
3//! This module encodes a number of rustc invariants about which items are named vs.
4//! unnamed and which items have parents. Those invariants are enforced at runtime and
5//! will emit diagnostic if the invariants are broken.
6//!
7//! # What is a path segment?
8//!
9//! In Rust, every item lives inside a path. Every path begins with a crate root
10//! (the crate where the item is defined).
11//!
12//! For example, imagine a crate called `my_crate` with this code:
13//!
14//! ```ignore
15//! mod a {
16//! mod b {
17//! fn hello() {}
18//! }
19//! }
20//! ```
21//!
22//! The function `hello` has the full path `my_crate::a::b::hello`.
23//! This path is made up of segments: `my_crate`, `a`, `b`, and `hello`.
24//!
25//! This module represents those segments as typed values, enriched with extra
26//! information such as:
27//! - whether the segment is named or unnamed (e.g. anonymous const or impl blocks),
28//! - what kind of item it points to (a crate, module, struct, field, associated fn, etc.),
29//! - its parent segment in the hierarchy (e.g. a field belongs to a constructor,
30//! which belongs to a type, which belongs to a module, which belongs to a crate).
31//!
32//! # Hierarchical nature of segments
33//!
34//! Segments form a hierarchy of ownership, starting from the crate root.
35//! For example, in a crate called `my_crate`:
36//!
37//! ```ignore
38//! struct Foo {
39//! bar: u32,
40//! }
41//! ```
42//!
43//! The field `bar` is represented as a `Field` segment. It knows its parent is
44//! the constructor of `Foo`, which knows its parent is the type definition `Foo`,
45//! which in turn belongs to the crate `my_crate`.
46//!
47//! The hierarchy looks like this:
48//!
49//! ```text
50//! my_crate (crate)
51//! └── Foo (type)
52//! └── Foo (constructor)
53//! └── bar (field)
54//! ```
55//!
56//! Similarly, with associated items in a crate `my_crate`:
57//!
58//! ```ignore
59//! trait T {
60//! fn f();
61//! }
62//! ```
63//!
64//! The function `f` is represented as an `AssocItem` segment, whose parent is the
65//! container `T` (a `Trait` segment), and ultimately the crate root:
66//!
67//! ```text
68//! my_crate (crate)
69//! └── T (trait)
70//! └── f (assoc fn)
71//! ```
72//!
73//! This hierarchical model makes it possible to:
74//! - reliably find the **parent** of any segment (`bar` → constructor → type → crate),
75//! - disambiguate names in backends (e.g. when two crates define constructors with the
76//! same name, the crate root keeps them separate),
77//! - traverse full paths in a strongly-typed way (using [`View`] or [`PathSegment::parents`]).
78//!
79//! # Examples
80//!
81//! For this Rust code in crate `my_crate`:
82//!
83//! ```ignore
84//! mod a {
85//! trait Foo {
86//! fn f() {
87//! enum T {
88//! C { field: u8 },
89//! }
90//! }
91//! }
92//! }
93//! ```
94//!
95//! We can represent various identifiers as hierarchical segments:
96//!
97//! | Path | Segments |
98//! |------------------------------------|----------------------------------------------|
99//! | `my_crate` | `[my_crate]` |
100//! | `my_crate::a` | `[my_crate], [a]` |
101//! | `my_crate::a::b::hello` | `[my_crate], [a], [b], [hello]` |
102//! | `my_crate::a::Foo` | `[my_crate], [a], [Foo]` |
103//! | `my_crate::a::Foo::f` | `[my_crate], [a], [Foo::f]` |
104//! | `my_crate::a::Foo::f::T` | `[my_crate], [a], [Foo::f], [T]` |
105//! | `my_crate::a::Foo::f::T::C` | `[my_crate], [a], [Foo::f], [T::C]` |
106//! | `my_crate::a::Foo::f::T::C::field` | `[my_crate], [a], [Foo::f], [T::C::field]` |
107//!
108
109use hax_frontend_exporter::{CtorOf, DefKind, DefPathItem, ImplInfos};
110
111use crate::{
112 ast::identifiers::global_id::{DefId, ExplicitDefId},
113 symbol::Symbol,
114};
115
116#[derive(Debug, Clone)]
117/// The kind of a type definition: `struct`, `enum`, or `union`.
118pub enum TypeDefKind {
119 /// A `struct` definition.
120 Struct,
121 /// An `enum` definition.
122 Enum,
123 /// A `union` definition.
124 Union,
125}
126
127#[derive(Debug, Clone)]
128/// The kind of a container for associated items (i.e., a `trait` or an `impl` block).
129pub enum AssocItemContainerKind {
130 /// An `impl` block.
131 Impl {
132 /// `true` if this is an inherent `impl` (no trait), `false` if it implements a trait.
133 inherent: bool,
134 /// Optional extra information about the impl (if available from the frontend).
135 ///
136 /// `None` when such information is not provided/collected.
137 impl_infos: Option<ImplInfos>,
138 },
139 /// A `trait` definition.
140 Trait {
141 /// `true` if this is a trait alias (a type alias to a trait).
142 trait_alias: bool,
143 },
144}
145
146#[derive(Debug, Clone)]
147/// The kind of a constructo (tuple struct/variant/struct-ctor function).
148pub enum ConstructorKind {
149 /// A constructor associated to a concrete type definition `ty`.
150 Constructor {
151 /// The type constructed
152 ty: PathSegment<TypeDefKind>,
153 },
154}
155
156#[derive(Debug, Clone)]
157/// The kind of an associated item within a trait or impl.
158pub enum AssocItemKind {
159 /// An associated function.
160 Fn,
161 /// An associated constant.
162 Const,
163 /// An associated type.
164 Ty,
165}
166
167#[derive(Debug, Clone)]
168/// The kind of any item that can occur as a path segment.
169///
170/// This is a sum type that makes [`PathSegment<AnyKind>`] expressive enough to encode
171/// precise parents (e.g., a field always has a constructor parent, an associated item
172/// always has a trait/impl container, etc.).
173pub enum AnyKind {
174 /// A type definition (`struct`, `enum`, or `union`).
175 TypeDef(TypeDefKind),
176 /// A container of associated items (`trait` or `impl`).
177 AssocItemContainer(AssocItemContainerKind),
178 /// A constructor (for a struct or enum variant).
179 Constructor(ConstructorKind),
180
181 /// An associated item.
182 AssocItem {
183 /// Which associated item kind this is.
184 kind: AssocItemKind,
185 /// The parent container (trait or impl) of this associated item.
186 container: PathSegment<AssocItemContainerKind>,
187 },
188
189 /// A standalone function.
190 Fn,
191 /// A standalone constant.
192 Const,
193 /// A `use` item.
194 Use,
195 /// An anonymous constant (e.g., `const _: T = ...;`).
196 AnonConst,
197 /// An inline constant (e.g., `let x = { const Y: i32 = 0; Y };`).
198 InlineConst,
199 /// A trait alias.
200 TraitAlias,
201 /// A foreign module (`extern "C" { ... }`).
202 Foreign,
203 /// A foreign type (`extern type T;`).
204 ForeignTy,
205 /// A type alias (`type Foo = Bar;`).
206 TyAlias,
207 /// An `extern crate` item.
208 ExternCrate,
209 /// An opaque item (e.g., `type Foo = impl Trait;`).
210 Opaque,
211 /// A `static` item.
212 Static,
213 /// A macro definition or export.
214 Macro,
215 /// A module or crate.
216 Mod,
217 /// A global assembly block.
218 GlobalAsm,
219
220 /// A field of a struct or a struct-like enum variant.
221 Field {
222 /// `true` if the field is *named* (e.g., `x` in `struct S { x: u8 }`);
223 /// `false` if it is *unnamed* (tuple field like `0` in `struct T(u8)`).
224 named: bool,
225 /// The parent constructor that owns this field.
226 ///
227 /// Example: The parent of `x` is the constructor of `Foo` in:
228 /// `struct Foo { x: u8 }`.
229 parent: PathSegment<ConstructorKind>,
230 },
231
232 /// A closure expression item.
233 Closure,
234}
235
236#[derive(Debug, Clone)]
237/// Payloads used when a path segment is **unnamed**.
238///
239/// These correspond to items that do not contribute a user-facing identifier in the path.
240pub enum UnnamedPathSegmentPayload {
241 /// An `impl` block.
242 Impl,
243 /// An anonymous constant.
244 AnonConst,
245 /// An inline constant.
246 InlineConst,
247 /// A foreign module or crate.
248 Foreign,
249 /// A global assembly code block.
250 GlobalAsm,
251 /// A `use` item.
252 Use,
253 /// An opaque item (e.g., `type Foo = impl Trait;`).
254 Opaque,
255 /// A closure.
256 Closure,
257}
258
259/// Each path segment carries a payload:
260/// - [`PathSegmentPayload::Named`] with a user-decided name, or
261/// - [`PathSegmentPayload::Unnamed`] for items that are anonymous in the path.
262#[derive(Debug, Clone)]
263pub enum PathSegmentPayload {
264 /// A named segment (holds the name as a [`Symbol`]).
265 Named(Symbol),
266 /// An unnamed segment with a categorized payload.
267 Unnamed(UnnamedPathSegmentPayload),
268}
269
270mod rustc_invariant_handling {
271 //! This modules provides the function `error_dummy_value`, which emits errors.
272
273 use std::any::{Any, type_name};
274 use std::fmt::Debug;
275
276 use super::*;
277 use crate::{
278 ast::{
279 diagnostics::{Context, DiagnosticInfo},
280 span::Span,
281 },
282 names,
283 };
284 use hax_types::diagnostics::Kind;
285
286 #[derive(Clone, Copy)]
287 /// Restrict [`ErrorDummyValue`] callers
288 pub struct Permit(());
289
290 pub trait ErrorDummyValue {
291 fn error_dummy_value(_: Permit) -> Self;
292 }
293
294 impl ErrorDummyValue for PathSegmentPayload {
295 fn error_dummy_value(_: Permit) -> Self {
296 Self::Named(Symbol::new("hax_engine_view_fatal_error"))
297 }
298 }
299
300 impl ErrorDummyValue for TypeDefKind {
301 fn error_dummy_value(_: Permit) -> Self {
302 TypeDefKind::Enum
303 }
304 }
305 impl ErrorDummyValue for ConstructorKind {
306 fn error_dummy_value(permit: Permit) -> Self {
307 ConstructorKind::Constructor {
308 ty: PathSegment::<TypeDefKind>::error_dummy_value(permit),
309 }
310 }
311 }
312
313 impl<K: ErrorDummyValue> ErrorDummyValue for PathSegment<K> {
314 fn error_dummy_value(permit: Permit) -> Self {
315 Self {
316 identifier: DefId::error_dummy_value(permit),
317 payload: PathSegmentPayload::error_dummy_value(permit),
318 disambiguator: 0,
319 kind: K::error_dummy_value(permit),
320 }
321 }
322 }
323
324 impl ErrorDummyValue for AnyKind {
325 fn error_dummy_value(_: Permit) -> Self {
326 Self::Fn
327 }
328 }
329
330 impl ErrorDummyValue for DefId {
331 fn error_dummy_value(_: Permit) -> Self {
332 match names::rust_primitives::hax::failure.0.get() {
333 crate::ast::identifiers::global_id::GlobalIdInner::Concrete(concrete_id) => {
334 concrete_id.def_id.def_id
335 }
336 // The error dummy value is generated by hax, with a concrete identifier
337 _ => unreachable!("Hax generated name for failure is concrete"),
338 }
339 }
340 }
341
342 impl ErrorDummyValue for AssocItemContainerKind {
343 fn error_dummy_value(_: Permit) -> Self {
344 AssocItemContainerKind::Trait { trait_alias: false }
345 }
346 }
347
348 impl ErrorDummyValue for bool {
349 fn error_dummy_value(_: Permit) -> Self {
350 true
351 }
352 }
353
354 pub(super) fn error_dummy_value<T: ErrorDummyValue, V: Debug + Any>(
355 message: &str,
356 value: &V,
357 ) -> T {
358 let details = format!(
359 "A rustc invariant about `DefId` was violated.\nContext: {message}.\nValue (type {}) is:\n{value:#?}",
360 type_name::<T>()
361 );
362 DiagnosticInfo {
363 context: Context::NameView,
364 span: Span::dummy(),
365 kind: Kind::AssertionFailure { details },
366 }
367 .emit();
368 T::error_dummy_value(Permit(()))
369 }
370}
371use rustc_invariant_handling::error_dummy_value;
372
373impl PathSegmentPayload {
374 /// Constructs a [`PathSegmentPayload`] from an [`ExplicitDefId`], assuming its last
375 /// path segment is named.
376 fn from_named(def_id: &ExplicitDefId) -> Self {
377 Self::Named(match def_id.def_id.path.last() {
378 Some(last) => match &last.data {
379 DefPathItem::TypeNs(s)
380 | DefPathItem::ValueNs(s)
381 | DefPathItem::MacroNs(s)
382 | DefPathItem::LifetimeNs(s) => Symbol::new(s),
383 _ => return error_dummy_value("PathSegmentPayload::from_named", def_id),
384 },
385 None => Symbol::new(&def_id.def_id.krate),
386 })
387 }
388
389 /// Constructs a [`PathSegmentPayload`] from an [`ExplicitDefId`], assuming its last
390 /// path segment is unnamed.
391 fn from_unnamed(def_id: &ExplicitDefId) -> Result<Self, &'static str> {
392 match def_id.def_id.path.last() {
393 Some(last) => match &last.data {
394 DefPathItem::TypeNs(_)
395 | DefPathItem::ValueNs(_)
396 | DefPathItem::MacroNs(_)
397 | DefPathItem::LifetimeNs(_) => {
398 return Err("PathSegmentPayload::from_unnamed, got name");
399 }
400
401 _ => (),
402 },
403 None => return Err("PathSegmentPayload::from_unnamed, got a root crate"),
404 };
405 Ok(Self::Unnamed(match &def_id.def_id.kind {
406 DefKind::Use => UnnamedPathSegmentPayload::Use,
407 DefKind::ForeignMod => UnnamedPathSegmentPayload::Foreign,
408 DefKind::AnonConst => UnnamedPathSegmentPayload::AnonConst,
409 DefKind::InlineConst => UnnamedPathSegmentPayload::InlineConst,
410 DefKind::OpaqueTy => UnnamedPathSegmentPayload::Opaque,
411 DefKind::GlobalAsm => UnnamedPathSegmentPayload::GlobalAsm,
412 DefKind::Impl { .. } => UnnamedPathSegmentPayload::Impl,
413 DefKind::Closure => UnnamedPathSegmentPayload::Closure,
414 _ => return Err("PathSegmentPayload::from_unnamed, bad kind"),
415 }))
416 }
417
418 /// Constructs a [`PathSegmentPayload`] from an [`ExplicitDefId`], dispatching to
419 /// `from_named` or `from_unnamed` according to the item's [`DefKind`].
420 ///
421 /// This encodes rustc invariants about which kinds are name-bearing in paths.
422 fn from_def_id(def_id: &ExplicitDefId) -> Self {
423 match &def_id.def_id.kind {
424 DefKind::Mod
425 | DefKind::Struct
426 | DefKind::Union
427 | DefKind::Enum
428 | DefKind::Variant
429 | DefKind::Trait
430 | DefKind::TyAlias
431 | DefKind::ForeignTy
432 | DefKind::TraitAlias
433 | DefKind::AssocTy
434 | DefKind::Fn
435 | DefKind::Const
436 | DefKind::Static { .. }
437 | DefKind::Ctor { .. }
438 | DefKind::AssocFn
439 | DefKind::AssocConst
440 | DefKind::Macro { .. }
441 | DefKind::ExternCrate
442 | DefKind::Field => Self::from_named(def_id),
443
444 DefKind::Use
445 | DefKind::ForeignMod
446 | DefKind::AnonConst
447 | DefKind::InlineConst
448 | DefKind::OpaqueTy
449 | DefKind::GlobalAsm
450 | DefKind::Impl { .. }
451 | DefKind::Closure => Self::from_unnamed(def_id)
452 .unwrap_or_else(|message| error_dummy_value(message, def_id)),
453
454 DefKind::TyParam
455 | DefKind::ConstParam
456 | DefKind::PromotedConst
457 | DefKind::LifetimeParam
458 | DefKind::SyntheticCoroutineBody => error_dummy_value(
459 "PathSegmentPayload::from_def_id, kinds should never appear",
460 def_id,
461 ),
462 }
463 }
464}
465
466#[derive(Debug, Clone)]
467/// A typed path segment: one "piece" of a Rust path, with extra structure.
468///
469/// # What does that mean?
470///
471/// In Rust, every item (function, type, trait, field...) has a path starting at
472/// its crate root. For example, in a crate called `my_crate`:
473///
474/// ```ignore
475/// mod a {
476/// mod b {
477/// fn hello() {}
478/// }
479/// trait Foo {
480/// fn f() {
481/// enum T {
482/// C { field: u8 },
483/// }
484/// }
485/// }
486/// }
487/// ```
488///
489/// Some paths and their **segments** are:
490///
491/// | Path | Segments |
492/// |------------------------------------|----------------------------------------------|
493/// | `my_crate` | `[my_crate]` |
494/// | `my_crate::a` | `[my_crate], [a]` |
495/// | `my_crate::a::b::hello` | `[my_crate], [a], [b], [hello]` |
496/// | `my_crate::a::Foo` | `[my_crate], [a], [Foo]` |
497/// | `my_crate::a::Foo::f` | `[my_crate], [a], [Foo::f]` |
498/// | `my_crate::a::Foo::f::T` | `[my_crate], [a], [Foo::f], [T]` |
499/// | `my_crate::a::Foo::f::T::C` | `[my_crate], [a], [Foo::f], [T::C]` |
500/// | `my_crate::a::Foo::f::T::C::field` | `[my_crate], [a], [Foo::f], [T::C::field]` |
501///
502/// Each `[X]` here is a **path segment**.
503///
504/// # Hierarchy
505///
506/// Path segments form a hierarchy: each one knows its parent. For example, the
507/// field `my_field` is inside the constructor of `MyVariant`, which is inside
508/// the enum `MyEnum`, which lives inside the function `f`, and so on -- all the
509/// way up to the crate root.
510///
511/// This parenthood is important:
512/// - a field segment always has a constructor parent
513/// (e.g. `my_field → MyVariant`).
514/// - an associated item always has a trait/impl container parent
515/// (e.g. `f → Foo`).
516/// - everything ultimately has a **crate** as its top parent.
517///
518/// # Why does this matter?
519///
520/// This strong typing of segments lets tools:
521/// - disambiguate names across contexts (e.g. two types with the same
522/// constructor name),
523/// - generate unique, human-readable names in other languages/backends,
524/// - walk up the chain of parents to reconstruct full paths.
525///
526/// For example, with the F\* backend, constructors are not namespaced under the
527/// name of their type, but live directly at top-level. Thus, they need to be
528/// unique. Using the hierarchy, we can print them as `Foo_MyVariant` instead of
529/// `Foo.MyVariant`.
530pub struct PathSegment<Kind = AnyKind> {
531 identifier: DefId,
532 payload: PathSegmentPayload,
533 disambiguator: u32,
534 kind: Kind,
535}
536
537impl<K> PathSegment<K> {
538 /// Returns the payload of this path segment (named vs. unnamed and why).
539 pub fn payload(&self) -> PathSegmentPayload {
540 self.payload.clone()
541 }
542
543 /// Returns the rustc path disambiguator for this segment.
544 pub fn disambiguator(&self) -> u32 {
545 self.disambiguator
546 }
547
548 /// Returns the kind of this segment as an [`K`].
549 pub fn kind(&self) -> &K {
550 &self.kind
551 }
552
553 /// Maps the segment's `kind` while preserving all other fields.
554 fn map<U>(self, f: impl Fn(K, &DefId) -> U) -> PathSegment<U> {
555 let Self {
556 identifier,
557 payload,
558 disambiguator,
559 kind,
560 } = self;
561 let kind = f(kind, &identifier);
562 PathSegment {
563 identifier,
564 payload,
565 disambiguator,
566 kind,
567 }
568 }
569}
570
571impl PathSegment<ConstructorKind> {
572 /// Lift a `PathSegment` of kind `ConstructorKind` to a `PathSegment` of kind `AnyKind`.
573 pub fn lift(&self) -> PathSegment<AnyKind> {
574 self.clone().map(|kind, _| AnyKind::Constructor(kind))
575 }
576}
577impl PathSegment<TypeDefKind> {
578 /// Lift a `PathSegment` of kind `TypeDefKind` to a `PathSegment` of kind `AnyKind`.
579 pub fn lift(&self) -> PathSegment<AnyKind> {
580 self.clone().map(|kind, _| AnyKind::TypeDef(kind))
581 }
582}
583impl PathSegment<AssocItemContainerKind> {
584 /// Lift a `PathSegment` of kind `AssocItemContainerKind` to a `PathSegment` of kind `AnyKind`.
585 pub fn lift(&self) -> PathSegment<AnyKind> {
586 self.clone()
587 .map(|kind, _| AnyKind::AssocItemContainer(kind))
588 }
589}
590
591impl PartialEq<PathSegment> for PathSegment {
592 fn eq(&self, other: &PathSegment) -> bool {
593 self.identifier == other.identifier && self.disambiguator == other.disambiguator
594 }
595}
596
597impl PathSegment {
598 /// Asserts that this segment is a [`TypeDefKind`] and narrows the type.
599 ///
600 /// Emits a diagnostic if it doesn
601 fn assert_type_def(self) -> PathSegment<TypeDefKind> {
602 self.map(|kind, did| match kind {
603 AnyKind::TypeDef(inner) => inner,
604 _ => error_dummy_value(&format!("expected TypeDefKind, got {kind:#?}"), did),
605 })
606 }
607
608 /// Asserts that this segment is an [`AssocItemContainerKind`] and narrows the type.
609 fn assert_assoc_item_container(self) -> PathSegment<AssocItemContainerKind> {
610 self.map(|kind, did| match kind {
611 AnyKind::AssocItemContainer(inner) => inner,
612 _ => error_dummy_value(
613 &format!("expected AssocItemContainerKind, got {kind:#?}"),
614 did,
615 ),
616 })
617 }
618
619 /// Asserts that this segment is a [`ConstructorKind`] and narrows the type.
620 fn assert_constructor(self) -> PathSegment<ConstructorKind> {
621 self.map(|kind, did| match kind {
622 AnyKind::Constructor(inner) => inner,
623 _ => error_dummy_value(&format!("expected ConstructorKind, got {kind:#?}"), did),
624 })
625 }
626
627 /// Internal constructor that consumes an iterator of [`ExplicitDefId`]s (from child
628 /// to parents) and builds a single [`PathSegment`] at a time, honoring rustc
629 /// invariants and wiring proper parents for kinds that require them
630 /// (constructors, fields, associated items).
631 ///
632 /// Returns `None` when the iterator is exhausted.
633 fn from_iterator(it: &mut impl Iterator<Item = ExplicitDefId>) -> Option<Self> {
634 let def_id = it.next()?;
635 let mut from_iterator = |context: &str| match Self::from_iterator(it) {
636 Some(value) => value,
637 None => error_dummy_value(
638 &format!("PathSegment::from_iterator, expected parent for {context}."),
639 &def_id,
640 ),
641 };
642 let payload = PathSegmentPayload::from_def_id(&def_id);
643
644 let kind = match &def_id.def_id.kind {
645 // Struct constructor path segment special-casing (struct-as-ctor).
646 DefKind::Ctor(CtorOf::Struct, _) | DefKind::Struct if def_id.is_constructor => {
647 let parent_def_id = ExplicitDefId {
648 is_constructor: false,
649 def_id: def_id.def_id,
650 };
651 let parent = match Self::from_iterator(&mut std::iter::once(parent_def_id)) {
652 Some(value) => value,
653 None => error_dummy_value(
654 "PathSegment::from_iterator, expected parent for Struct/Ctor.",
655 &def_id,
656 ),
657 };
658 AnyKind::Constructor(ConstructorKind::Constructor {
659 ty: parent.assert_type_def(),
660 })
661 }
662 // Non-ctor struct item.
663 DefKind::Ctor(CtorOf::Struct, _) => AnyKind::TypeDef(TypeDefKind::Struct),
664 // Enum variants and non-struct ctors.
665 DefKind::Variant | DefKind::Ctor(_, _) => {
666 AnyKind::Constructor(ConstructorKind::Constructor {
667 ty: from_iterator("Variant/Ctor").assert_type_def(),
668 })
669 }
670 DefKind::Struct => AnyKind::TypeDef(TypeDefKind::Struct),
671 DefKind::Union => AnyKind::TypeDef(TypeDefKind::Union),
672 DefKind::Enum => AnyKind::TypeDef(TypeDefKind::Enum),
673 DefKind::Trait => {
674 AnyKind::AssocItemContainer(AssocItemContainerKind::Trait { trait_alias: false })
675 }
676 DefKind::Impl { of_trait } => AnyKind::AssocItemContainer(
677 AssocItemContainerKind::Impl { inherent: !of_trait, impl_infos: /* intentionally left None; fill where available */ None },
678 ),
679
680 // Simple leaf kinds.
681 DefKind::Mod => AnyKind::Mod,
682 DefKind::Fn => AnyKind::Fn,
683 DefKind::Const => AnyKind::Const,
684 DefKind::Static { .. } => AnyKind::Static,
685 DefKind::Use => AnyKind::Use,
686 DefKind::TyAlias => AnyKind::TyAlias,
687 DefKind::TraitAlias => AnyKind::TraitAlias,
688 DefKind::ForeignTy => AnyKind::ForeignTy,
689 DefKind::ForeignMod => AnyKind::Foreign,
690 DefKind::Macro { .. } => AnyKind::Macro,
691 DefKind::AnonConst => AnyKind::AnonConst,
692 DefKind::OpaqueTy => AnyKind::Opaque,
693 DefKind::GlobalAsm => AnyKind::GlobalAsm,
694 DefKind::Closure => AnyKind::Closure,
695 DefKind::ExternCrate => AnyKind::ExternCrate,
696
697 // Field: requires a constructor parent and conveys whether it's named.
698 DefKind::Field => AnyKind::Field {
699 parent: from_iterator("Field").assert_constructor(),
700 named: match &payload {
701 PathSegmentPayload::Named(symbol) => {
702 // Tuple fields are numbered; parse success => unnamed field.
703 str::parse::<usize>(symbol.as_ref()).is_ok()
704 }
705 PathSegmentPayload::Unnamed(_) => {
706 error_dummy_value("Field should carry a ValueNs payload.", &def_id)
707 }
708 },
709 },
710
711 // Associated items: require a container parent.
712 DefKind::AssocTy => AnyKind::AssocItem {
713 container: from_iterator("AssocTy").assert_assoc_item_container(),
714 kind: AssocItemKind::Ty,
715 },
716 DefKind::AssocFn => AnyKind::AssocItem {
717 container: from_iterator("AssocFn").assert_assoc_item_container(),
718 kind: AssocItemKind::Fn,
719 },
720 DefKind::AssocConst => AnyKind::AssocItem {
721 container: from_iterator("AssocConst").assert_assoc_item_container(),
722 kind: AssocItemKind::Const,
723 },
724
725 _ => error_dummy_value("PathSegment::from_iterator_opt", &def_id),
726 };
727 let identifier = def_id.def_id;
728 let disambiguator = identifier.path.last().map(|d| d.disambiguator).unwrap_or(0);
729 Some(Self {
730 identifier,
731 payload,
732 disambiguator,
733 kind,
734 })
735 }
736}
737
738impl PathSegment {
739 /// Returns the parent path segment, if any.
740 ///
741 /// Parents exist only for:
742 /// - [`AnyKind::Constructor`] (parent is its [`TypeDefKind`]),
743 /// - [`AnyKind::AssocItem`] (parent is its container `trait`/`impl`),
744 /// - [`AnyKind::Field`] (parent is its constructor).
745 ///
746 /// All other kinds return `None`.
747 pub fn parent(&self) -> Option<PathSegment> {
748 Some(match self.kind.clone() {
749 AnyKind::Constructor(ConstructorKind::Constructor { ty }) => {
750 ty.map(|kind, _| AnyKind::TypeDef(kind))
751 }
752 AnyKind::AssocItem { container, .. } => {
753 container.map(|kind, _| AnyKind::AssocItemContainer(kind))
754 }
755 AnyKind::Field { parent, .. } => parent.map(|kind, _| AnyKind::Constructor(kind)),
756 _ => return None,
757 })
758 }
759
760 /// Returns an iterator over `self` and all its ancestors, walking up via
761 /// [`Self::parent`] until no parent remains.
762 pub fn parents(&self) -> impl Iterator<Item = Self> {
763 std::iter::successors(Some(self.clone()), |seg| seg.parent())
764 }
765}
766
767mod view_encapsulation {
768 //! Encapsulation module to scope [`View`]'s invariants
769 use crate::ast::{
770 identifiers::global_id::{FreshModule, ReservedSuffix},
771 span::Span,
772 };
773
774 use super::*;
775 /// A view for an [`ExplicitDefId`], materialized as a list of typed
776 /// [`PathSegment`]s ordered from the crate root/module towards the item.
777 pub struct View(Vec<PathSegment>, Option<ReservedSuffix>);
778
779 impl View {
780 /// Returns the full list of segments (non-empty).
781 pub fn segments(&self) -> &[PathSegment] {
782 &self.0
783 }
784
785 /// Returns the last (most specific) segment.
786 pub fn last(&self) -> &PathSegment {
787 self.0
788 .last()
789 .expect("Broken invariant: a view always contains at least one path path segments.")
790 }
791
792 /// Returns the first (outermost) segment.
793 pub fn first(&self) -> &PathSegment {
794 self.0
795 .first()
796 .expect("Broken invariant: a view always contains at least one path path segments.")
797 }
798
799 /// Splits the view at the boundary between (Rust) modules and the first non-module
800 /// segment.
801 ///
802 /// Returns `(modules, rest)`, where `modules` is the (non empty) prefix of
803 /// `mod` segments (e.g., the crate/module path), and `rest` is the remaining
804 /// segments starting at the first non-`mod`.
805 pub fn split_at_module(&self) -> (&[PathSegment], &[PathSegment]) {
806 let position = self
807 .segments()
808 .iter()
809 .enumerate()
810 .find(|(_, seg)| !matches!(seg.kind(), AnyKind::Mod))
811 .map(|(i, _)| i)
812 .unwrap_or(self.segments().len());
813 self.segments().split_at(position)
814 }
815
816 /// Get the first parent which is a proper module (all its parent are modules as well).
817 pub fn module(&self) -> &PathSegment {
818 self.0
819 .iter()
820 .take_while(|seg| !matches!(seg.kind(), AnyKind::Mod))
821 .last()
822 .expect("Broken invariant, a name has at least a crate")
823 }
824
825 /// Get the optional suffix of this view
826 pub fn suffix(&self) -> &Option<ReservedSuffix> {
827 &self.1
828 }
829
830 /// Add a suffix to a view
831 pub fn with_suffix(mut self, suffix: Option<ReservedSuffix>) -> Self {
832 self.1 = suffix;
833 self
834 }
835 }
836
837 impl From<ExplicitDefId> for View {
838 /// Builds a [`View`] from an [`ExplicitDefId`], reconstructing segments by walking
839 /// up the parent chain and then reversing to obtain the canonical outer→inner order.
840 fn from(value: ExplicitDefId) -> Self {
841 let mut it = value.parents();
842 let mut inner =
843 std::iter::from_fn(|| PathSegment::from_iterator(&mut it)).collect::<Vec<_>>();
844 inner.reverse();
845 debug_assert!(!inner.is_empty()); // invariant: non-empty
846 Self(inner, None)
847 }
848 }
849
850 impl From<FreshModule> for View {
851 fn from(value: FreshModule) -> Self {
852 use crate::ast::diagnostics::{Context, DiagnosticInfo};
853 (DiagnosticInfo {
854 context: Context::NameView,
855 span: Span::dummy(),
856 kind: hax_types::diagnostics::Kind::Unimplemented {
857 issue_id: Some(1779),
858 details: Some(
859 "Fresh modules are not implemented yet in the Rust engine".into(),
860 ),
861 },
862 })
863 .emit();
864 // dummy value
865 value
866 .hints
867 .first()
868 .expect("The list of hints should be non-empty")
869 .clone()
870 .into()
871 }
872 }
873}
874pub use view_encapsulation::View;