Skip to main content

mago_codex/metadata/
ttype.rs

1use mago_span::Span;
2
3use crate::ttype::union::TUnion;
4
5/// Contains metadata associated with a specific type instance within the type system.
6///
7/// This struct combines the core type information (`TUnion`) with contextual details
8/// about *how* and *where* this type information was determined or declared in the source code
9/// or related documentation.
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[non_exhaustive]
13pub struct TypeMetadata {
14    /// The specific location (span) in the source code or documentation
15    /// that this type metadata corresponds to.
16    ///
17    /// This could be:
18    /// - The span of a type annotation (e.g., `: string`).
19    /// - The span of an expression whose type was inferred (e.g., `$x = 10` -> span of `10`).
20    /// - The span of a type mentioned in a documentation block (e.g., `@param int` -> span of `int`).
21    pub span: Span,
22
23    /// The core representation of the type itself.
24    pub type_union: TUnion,
25
26    /// Distinguishes whether this type information originated from analyzing
27    /// executable code constructs (e.g., type declarations, assignments)
28    /// or from documentation blocks.
29    ///
30    /// - `true` if the type information was extracted from a docblock comment.
31    /// - `false` if the type information came from actual code analysis.
32    pub from_docblock: bool,
33
34    /// Indicates whether this type was explicitly declared in the source
35    /// or deduced ("inferred") by the type checker based on context.
36    ///
37    /// - `true` if the type checker inferred this type (e.g., from a variable initialization like `$x = 10;`).
38    /// - `false` if the type was explicitly written by the user (e.g., `int $x;`).
39    pub inferred: bool,
40}
41
42impl TypeMetadata {
43    /// Creates new `TypeMetadata` for an explicitly declared type from code.
44    ///
45    /// This is a convenience constructor assuming the common case where a type
46    /// is directly specified in the code, and wasn't just inferred or from a docblock.
47    ///
48    /// # Arguments
49    ///
50    /// * `type_union`: The core type information (`TUnion`).
51    /// * `span`: The source code location associated with this type.
52    ///
53    /// # Returns
54    ///
55    /// A new `TypeMetadata` instance with `is_nullable`, `from_docblock`, and `inferred` set to `false`.
56    #[must_use]
57    pub fn new(type_union: TUnion, span: Span) -> Self {
58        Self { span, type_union, from_docblock: false, inferred: false }
59    }
60
61    /// Creates new `TypeMetadata` for a type extracted from a documentation block.
62    ///
63    /// This constructor is used when type information is sourced from
64    /// docblock comments rather than executable code.
65    ///
66    /// # Arguments
67    ///
68    /// * `type_union`: The core type information (`TUnion`).
69    /// * `span`: The source code location associated with this docblock type.
70    ///
71    /// # Returns
72    ///
73    /// A new `TypeMetadata` instance with `from_docblock` set to `true` and `inferred` set to `false`.
74    #[must_use]
75    pub fn from_docblock(type_union: TUnion, span: Span) -> Self {
76        Self { span, type_union, from_docblock: true, inferred: false }
77    }
78
79    /// Creates a new `TypeMetadata` by applying a function to the inner `TUnion`.
80    ///
81    /// This allows transforming the core type while preserving the surrounding metadata.
82    ///
83    /// # Arguments
84    ///
85    /// * `f`: A function that takes the current `TUnion` and returns a new `TUnion`.
86    ///
87    /// # Returns
88    ///
89    /// A new `TypeMetadata` instance with the transformed `TUnion` and the same metadata flags and span.
90    #[must_use]
91    pub fn map_type_union<F>(self, f: F) -> Self
92    where
93        F: FnOnce(TUnion) -> TUnion,
94    {
95        Self {
96            span: self.span,
97            type_union: f(self.type_union),
98            from_docblock: self.from_docblock,
99            inferred: self.inferred,
100        }
101    }
102}