Skip to main content

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;