Skip to main content

morphir_core/ir/v4/
value.rs

1//! Value expressions and definitions for Morphir IR V4.
2//!
3//! This module defines the complete value layer of the Morphir IR, including:
4//! - Value expressions (`Value` enum) representing term-level computations
5//! - Value specifications (`ValueSpecification`) representing type signatures
6//! - Value definitions (`ValueDefinition`) with various body types
7//!
8//! Values use `TypeAttributes` for type nodes and `ValueAttributes` for value nodes (V4 format).
9//!
10//! # Examples
11//!
12//! ```rust,ignore
13//! // Create a simple unit value
14//! let v: Value = Value::Unit(ValueAttributes::default());
15//!
16//! // Create a value definition
17//! let def: ValueDefinition = ValueDefinition::new(
18//!     vec![],
19//!     Type::unit(TypeAttributes::default()),
20//!     Value::unit(ValueAttributes::default()),
21//! );
22//! ```
23
24use indexmap::IndexMap;
25use serde::de::Deserializer;
26use serde::ser::{SerializeMap, Serializer};
27use serde::{Deserialize, Serialize};
28
29use super::attributes::ValueAttributes;
30use super::literal::Literal;
31use super::pattern::Pattern;
32use super::types::{Incompleteness, Type};
33use crate::naming::{FQName, Name};
34
35// ============================================================================
36// VALUE EXPRESSIONS
37// ============================================================================
38
39/// A value expression with V4 attributes.
40///
41/// Value expressions form the term-level representation in Morphir IR.
42/// Each variant carries `ValueAttributes`, and types within
43/// carry `TypeAttributes`.
44///
45/// # Examples
46///
47/// ```rust,ignore
48/// let v: Value = Value::Unit(ValueAttributes::default());
49/// ```
50#[derive(Debug, Clone, PartialEq)]
51pub enum Value {
52    // === Core expressions (all versions) ===
53    /// Literal constant value
54    ///
55    /// Example: `42`, `"hello"`, `true`
56    Literal(ValueAttributes, Literal),
57
58    /// Data constructor reference
59    ///
60    /// Example: `Just` in `Just 42`
61    Constructor(ValueAttributes, FQName),
62
63    /// Tuple construction
64    ///
65    /// Example: `(1, "hello", true)`
66    Tuple(ValueAttributes, Vec<Value>),
67
68    /// List construction
69    ///
70    /// Example: `[1, 2, 3]`
71    List(ValueAttributes, Vec<Value>),
72
73    /// Record construction
74    ///
75    /// Example: `{ name = "Alice", age = 30 }`
76    Record(ValueAttributes, Vec<RecordFieldEntry>),
77
78    /// Variable reference
79    ///
80    /// Example: `x` in `let x = 1 in x + 1`
81    Variable(ValueAttributes, Name),
82
83    /// Reference to a named value
84    ///
85    /// Example: `List.map` referencing a module function
86    Reference(ValueAttributes, FQName),
87
88    /// Field access on a record
89    ///
90    /// Example: `person.name`
91    Field(ValueAttributes, Box<Value>, Name),
92
93    /// Field accessor function
94    ///
95    /// Example: `.name` as a function
96    FieldFunction(ValueAttributes, Name),
97
98    /// Function application
99    ///
100    /// Example: `f x` applies function `f` to argument `x`
101    Apply(ValueAttributes, Box<Value>, Box<Value>),
102
103    /// Lambda abstraction
104    ///
105    /// Example: `\x -> x + 1`
106    Lambda(ValueAttributes, Pattern, Box<Value>),
107
108    /// Let binding with a value definition
109    ///
110    /// Example: `let x = 1 in x + 1`
111    LetDefinition(ValueAttributes, Name, Box<ValueDefinition>, Box<Value>),
112
113    /// Recursive let bindings
114    ///
115    /// Example: `let rec f = ... and g = ... in ...`
116    LetRecursion(ValueAttributes, Vec<LetBinding>, Box<Value>),
117
118    /// Pattern destructuring in let
119    ///
120    /// Example: `let (a, b) = tuple in a + b`
121    Destructure(ValueAttributes, Pattern, Box<Value>, Box<Value>),
122
123    /// Conditional expression
124    ///
125    /// Example: `if cond then a else b`
126    IfThenElse(ValueAttributes, Box<Value>, Box<Value>, Box<Value>),
127
128    /// Pattern matching
129    ///
130    /// Example: `case x of Just v -> v; Nothing -> 0`
131    PatternMatch(ValueAttributes, Box<Value>, Vec<PatternCase>),
132
133    /// Record update
134    ///
135    /// Example: `{ person | name = "Bob" }`
136    UpdateRecord(ValueAttributes, Box<Value>, Vec<RecordFieldEntry>),
137
138    /// Unit value
139    ///
140    /// Example: `()`
141    Unit(ValueAttributes),
142
143    // === V4-only constructs ===
144    /// Incomplete/broken value placeholder (V4 only)
145    ///
146    /// Represents values that couldn't be fully resolved or compiled.
147    /// Used for incremental compilation and error recovery.
148    ///
149    /// Decision 0008 keeps the hole a value expression, with an optional expected type:
150    /// `{ "Hole": { "reason": { "UnresolvedReference": { "target": "my/pkg:mod#gone" } },
151    /// "expectedType": "morphir/SDK:basics#int" } }`.
152    /// It is the only V4-only value expression: a native operation and an external binding are
153    /// properties of a *definition*, so they live in [`ValueBody`] and a reader refuses
154    /// `{ "Native": … }` or `{ "External": … }` where a value expression belongs.
155    Hole(ValueAttributes, HoleReason, Option<Box<Type>>),
156}
157
158/// Reason why a value is incomplete/broken (V4 only)
159///
160/// The three reasons are the ones definitions-0014, 0016 and 0026 pin. `Draft` is the other
161/// [`Incompleteness`] kind rather than a reason: a draft is deliberately unfinished and names no
162/// reason at all, so a reader refuses `{ "Draft": {} }` where a reason belongs.
163#[derive(Debug, Clone, PartialEq)]
164pub enum HoleReason {
165    /// Reference couldn't be resolved
166    UnresolvedReference { target: FQName },
167    /// Value was removed during refactoring
168    DeletedDuringRefactor {
169        /// Transaction ID of the refactoring that deleted this reference
170        tx_id: String,
171    },
172    /// Type checking failed
173    TypeMismatch {
174        /// Expected type description
175        expected: String,
176        /// Actual type found
177        found: String,
178    },
179}
180
181/// Category hint for native operations (V4 only)
182#[derive(Debug, Clone, PartialEq)]
183pub enum NativeHint {
184    Arithmetic,
185    Comparison,
186    StringOp,
187    CollectionOp,
188    PlatformSpecific {
189        /// Platform identifier (e.g., "wasm", "javascript", "native")
190        platform: String,
191    },
192}
193
194/// Information about a native operation (V4 only)
195///
196/// `{ "hint": { "Arithmetic": {} } }`. A description is optional and is written only when the
197/// definition has one.
198#[derive(Debug, Clone, PartialEq, Serialize)]
199pub struct NativeInfo {
200    pub hint: NativeHint,
201    #[serde(skip_serializing_if = "Option::is_none")]
202    pub description: Option<String>,
203}
204
205impl<'de> Deserialize<'de> for NativeInfo {
206    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
207    where
208        D: Deserializer<'de>,
209    {
210        super::serde_document::deserialize_with(
211            deserializer,
212            super::serde_document::decode_native_info,
213        )
214    }
215}
216
217/// Input parameter tuple struct: (name, type)
218///
219/// The contract gives each parameter a bare type; there is no v4 home for a parameter's own
220/// attributes.
221#[derive(Debug, Clone, PartialEq)]
222pub struct InputType(pub Name, pub Type);
223
224/// Record field entry tuple struct: (name, value)
225///
226/// Used in Record and UpdateRecord value variants.
227#[derive(Debug, Clone, PartialEq)]
228pub struct RecordFieldEntry(pub Name, pub Value);
229
230/// Pattern match case tuple struct: (pattern, body)
231#[derive(Debug, Clone, PartialEq)]
232pub struct PatternCase(pub Pattern, pub Value);
233
234/// Let-recursion binding tuple struct: (name, definition)
235#[derive(Debug, Clone, PartialEq)]
236pub struct LetBinding(pub Name, pub ValueDefinition);
237
238/// One target platform's binding for an external definition.
239///
240/// `{ "targetPlatform": "javascript", "externalName": "console.log" }`. Decision 0008 makes a
241/// target platform unique within a definition's bindings.
242#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
243#[serde(rename_all = "camelCase")]
244pub struct ExternalBinding {
245    pub target_platform: String,
246    pub external_name: String,
247}
248
249/// The body of a value definition.
250///
251/// Decision 0008: a native operation, an external binding and an incompleteness are properties
252/// of a definition rather than expressions, so these four bodies are where they live. An
253/// external definition carries one binding per target platform and may still carry a fallback
254/// body, which is what lets a Gleam-style external with a body encode without loss.
255#[derive(Debug, Clone, PartialEq)]
256#[allow(clippy::large_enum_variant)]
257pub enum ValueBody {
258    /// Normal expression body (all versions)
259    Expression(Value),
260
261    /// Native/builtin operation - no IR body (V4 only)
262    Native { native_info: NativeInfo },
263
264    /// External FFI definition (V4 only)
265    External {
266        externals: Vec<ExternalBinding>,
267        fallback: Option<Box<Value>>,
268    },
269
270    /// Incomplete value definition (V4 only)
271    ///
272    /// The output type lives on the [`ValueDefinition`], where every body's does; it is optional
273    /// there because an incomplete definition may not have one yet, and required on the wire for
274    /// the three complete bodies. `partial_body` is what the author had written when the
275    /// definition stopped being complete (definitions-0025); it is written only when present.
276    Incomplete {
277        incompleteness: Incompleteness,
278        partial_body: Option<Box<Value>>,
279    },
280}
281
282impl Value {
283    /// Get the attributes of this value
284    pub fn attributes(&self) -> &ValueAttributes {
285        match self {
286            Value::Literal(a, _) => a,
287            Value::Constructor(a, _) => a,
288            Value::Tuple(a, _) => a,
289            Value::List(a, _) => a,
290            Value::Record(a, _) => a,
291            Value::Variable(a, _) => a,
292            Value::Reference(a, _) => a,
293            Value::Field(a, _, _) => a,
294            Value::FieldFunction(a, _) => a,
295            Value::Apply(a, _, _) => a,
296            Value::Lambda(a, _, _) => a,
297            Value::LetDefinition(a, _, _, _) => a,
298            Value::LetRecursion(a, _, _) => a,
299            Value::Destructure(a, _, _, _) => a,
300            Value::IfThenElse(a, _, _, _) => a,
301            Value::PatternMatch(a, _, _) => a,
302            Value::UpdateRecord(a, _, _) => a,
303            Value::Unit(a) => a,
304            Value::Hole(a, _, _) => a,
305        }
306    }
307
308    /// Create a literal value
309    pub fn literal(attrs: ValueAttributes, lit: Literal) -> Self {
310        Value::Literal(attrs, lit)
311    }
312
313    /// Create a variable reference
314    pub fn variable(attrs: ValueAttributes, name: Name) -> Self {
315        Value::Variable(attrs, name)
316    }
317
318    /// Create a constructor reference
319    pub fn constructor(attrs: ValueAttributes, name: FQName) -> Self {
320        Value::Constructor(attrs, name)
321    }
322
323    /// Create a tuple
324    pub fn tuple(attrs: ValueAttributes, elements: Vec<Value>) -> Self {
325        Value::Tuple(attrs, elements)
326    }
327
328    /// Create a list
329    pub fn list(attrs: ValueAttributes, elements: Vec<Value>) -> Self {
330        Value::List(attrs, elements)
331    }
332
333    /// Create a record
334    pub fn record(attrs: ValueAttributes, fields: Vec<RecordFieldEntry>) -> Self {
335        Value::Record(attrs, fields)
336    }
337
338    /// Create a function application
339    pub fn apply(attrs: ValueAttributes, function: Value, argument: Value) -> Self {
340        Value::Apply(attrs, Box::new(function), Box::new(argument))
341    }
342
343    /// Create a lambda expression
344    pub fn lambda(attrs: ValueAttributes, pattern: Pattern, body: Value) -> Self {
345        Value::Lambda(attrs, pattern, Box::new(body))
346    }
347
348    /// Create an if-then-else expression
349    pub fn if_then_else(
350        attrs: ValueAttributes,
351        condition: Value,
352        then_branch: Value,
353        else_branch: Value,
354    ) -> Self {
355        Value::IfThenElse(
356            attrs,
357            Box::new(condition),
358            Box::new(then_branch),
359            Box::new(else_branch),
360        )
361    }
362
363    /// Create a unit value
364    pub fn unit(attrs: ValueAttributes) -> Self {
365        Value::Unit(attrs)
366    }
367}
368
369// Convenience constructors for tuple structs
370impl InputType {
371    /// Create a new input type
372    pub fn new(name: Name, tpe: Type) -> Self {
373        InputType(name, tpe)
374    }
375
376    /// Get the name
377    pub fn name(&self) -> &Name {
378        &self.0
379    }
380
381    /// Get the type
382    pub fn tpe(&self) -> &Type {
383        &self.1
384    }
385}
386
387impl RecordFieldEntry {
388    /// Create a new record field entry
389    pub fn new(name: Name, value: Value) -> Self {
390        RecordFieldEntry(name, value)
391    }
392
393    /// Get the name
394    pub fn name(&self) -> &Name {
395        &self.0
396    }
397
398    /// Get the value
399    pub fn value(&self) -> &Value {
400        &self.1
401    }
402}
403
404impl PatternCase {
405    /// Create a new pattern case
406    pub fn new(pattern: Pattern, body: Value) -> Self {
407        PatternCase(pattern, body)
408    }
409
410    /// Get the pattern
411    pub fn pattern(&self) -> &Pattern {
412        &self.0
413    }
414
415    /// Get the body
416    pub fn body(&self) -> &Value {
417        &self.1
418    }
419}
420
421impl LetBinding {
422    /// Create a new let binding
423    pub fn new(name: Name, definition: ValueDefinition) -> Self {
424        LetBinding(name, definition)
425    }
426
427    /// Get the name
428    pub fn name(&self) -> &Name {
429        &self.0
430    }
431
432    /// Get the definition
433    pub fn definition(&self) -> &ValueDefinition {
434        &self.1
435    }
436}
437
438impl NativeInfo {
439    /// Create a new NativeInfo
440    pub fn new(hint: NativeHint, description: Option<String>) -> Self {
441        NativeInfo { hint, description }
442    }
443}
444
445// ============================================================================
446// VALUE SPECIFICATIONS (Public API)
447// ============================================================================
448
449/// Value specification (just the signature)
450///
451/// `{ "inputs": { "a": "morphir/SDK:basics#int" }, "output": "morphir/SDK:basics#int" }`. The
452/// inputs are an object keyed by parameter name, whose order is the parameter order; an array of
453/// `[name, type]` pairs is accepted beside it. `inputTypes` and `outputType` belong to a value
454/// *definition*'s bodies, not here.
455#[derive(Debug, Clone, PartialEq)]
456pub struct ValueSpecification {
457    /// The annotations on the value's public face, written first and only when non-empty
458    /// (definitions-0021).
459    pub annotations: super::annotation::Annotations,
460    pub inputs: IndexMap<String, Type>,
461    pub output: Type,
462}
463
464impl Serialize for ValueSpecification {
465    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
466    where
467        S: Serializer,
468    {
469        let mut map = serializer.serialize_map(None)?;
470        if !self.annotations.is_empty() {
471            map.serialize_entry("annotations", &self.annotations)?;
472        }
473        // definitions-0029: `inputs` is omitted when empty and accepted when written empty.
474        if !self.inputs.is_empty() {
475            map.serialize_entry("inputs", &self.inputs)?;
476        }
477        map.serialize_entry("output", &self.output)?;
478        map.end()
479    }
480}
481
482impl<'de> Deserialize<'de> for ValueSpecification {
483    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
484    where
485        D: Deserializer<'de>,
486    {
487        super::serde_document::deserialize_standalone_with(
488            deserializer,
489            super::serde_document::decode_value_specification,
490        )
491    }
492}
493
494// ============================================================================
495// VALUE DEFINITIONS
496// ============================================================================
497
498/// A value definition (function or constant)
499///
500/// V4 format supports multiple body types (Expression, Native, External, Incomplete).
501#[derive(Debug, Clone, PartialEq)]
502pub struct ValueDefinition {
503    pub input_types: IndexMap<String, Type>,
504    pub output_type: Option<Type>,
505    pub body: ValueBody,
506}
507
508#[derive(Serialize)]
509#[serde(rename_all = "camelCase")]
510struct ExpressionDefinitionContent<'a> {
511    input_types: &'a IndexMap<String, Type>,
512    output_type: &'a Type,
513    body: &'a Value,
514}
515
516#[derive(Serialize)]
517#[serde(rename_all = "camelCase")]
518struct NativeDefinitionContent<'a> {
519    input_types: &'a IndexMap<String, Type>,
520    output_type: &'a Type,
521    native_info: &'a NativeInfo,
522}
523
524#[derive(Serialize)]
525#[serde(rename_all = "camelCase")]
526struct ExternalDefinitionContent<'a> {
527    input_types: &'a IndexMap<String, Type>,
528    output_type: &'a Type,
529    externals: &'a [ExternalBinding],
530    #[serde(skip_serializing_if = "Option::is_none")]
531    body: Option<&'a Value>,
532}
533
534#[derive(Serialize)]
535#[serde(rename_all = "camelCase")]
536struct IncompleteDefinitionContent<'a> {
537    input_types: &'a IndexMap<String, Type>,
538    #[serde(skip_serializing_if = "Option::is_none")]
539    output_type: Option<&'a Type>,
540    incompleteness: &'a Incompleteness,
541    #[serde(rename = "partialBody", skip_serializing_if = "Option::is_none")]
542    partial_body: Option<&'a Value>,
543}
544
545impl Serialize for ValueDefinition {
546    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
547    where
548        S: Serializer,
549    {
550        let mut map = serializer.serialize_map(Some(1))?;
551        match &self.body {
552            ValueBody::Expression(body) => map.serialize_entry(
553                "ExpressionBody",
554                &ExpressionDefinitionContent {
555                    input_types: &self.input_types,
556                    output_type: self.output_type.as_ref().ok_or_else(|| {
557                        serde::ser::Error::custom("ExpressionBody requires outputType")
558                    })?,
559                    body,
560                },
561            )?,
562            ValueBody::Native { native_info } => map.serialize_entry(
563                "NativeBody",
564                &NativeDefinitionContent {
565                    input_types: &self.input_types,
566                    output_type: self.output_type.as_ref().ok_or_else(|| {
567                        serde::ser::Error::custom("NativeBody requires outputType")
568                    })?,
569                    native_info,
570                },
571            )?,
572            ValueBody::External {
573                externals,
574                fallback,
575            } => map.serialize_entry(
576                "ExternalBody",
577                &ExternalDefinitionContent {
578                    input_types: &self.input_types,
579                    output_type: self.output_type.as_ref().ok_or_else(|| {
580                        serde::ser::Error::custom("ExternalBody requires outputType")
581                    })?,
582                    externals,
583                    body: fallback.as_deref(),
584                },
585            )?,
586            ValueBody::Incomplete {
587                incompleteness,
588                partial_body,
589            } => map.serialize_entry(
590                "IncompleteBody",
591                &IncompleteDefinitionContent {
592                    input_types: &self.input_types,
593                    output_type: self.output_type.as_ref(),
594                    incompleteness,
595                    partial_body: partial_body.as_deref(),
596                },
597            )?,
598        }
599        map.end()
600    }
601}
602
603impl<'de> Deserialize<'de> for ValueDefinition {
604    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
605    where
606        D: Deserializer<'de>,
607    {
608        super::serde_document::deserialize_standalone_with(
609            deserializer,
610            super::serde_document::decode_value_definition,
611        )
612    }
613}
614impl ValueDefinition {
615    /// Create a new value definition with an expression body
616    pub fn new(input_types: Vec<InputType>, output_type: Type, body: Value) -> Self {
617        let inputs = input_types
618            .into_iter()
619            .map(|InputType(name, tpe)| (name.to_string(), tpe))
620            .collect();
621
622        ValueDefinition {
623            input_types: inputs,
624            output_type: Some(output_type),
625            body: ValueBody::Expression(body),
626        }
627    }
628
629    /// Create a value definition with a native body (V4 only)
630    pub fn native(input_types: Vec<InputType>, output_type: Type, info: NativeInfo) -> Self {
631        let inputs = input_types
632            .into_iter()
633            .map(|InputType(name, tpe)| (name.to_string(), tpe))
634            .collect();
635
636        ValueDefinition {
637            input_types: inputs,
638            output_type: Some(output_type),
639            body: ValueBody::Native { native_info: info },
640        }
641    }
642}
643
644// ============================================================================
645// SERIALIZATION SUPPORT FOR VALUE BODY
646// ============================================================================
647
648impl Serialize for ValueBody {
649    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
650    where
651        S: Serializer,
652    {
653        let mut map = serializer.serialize_map(Some(1))?;
654        match self {
655            ValueBody::Expression(body) => {
656                map.serialize_entry("ExpressionBody", &ExpressionBodySerContent { body })?;
657            }
658            ValueBody::Native { native_info } => {
659                map.serialize_entry("NativeBody", &NativeBodySerContent { native_info })?;
660            }
661            ValueBody::External {
662                externals,
663                fallback,
664            } => {
665                map.serialize_entry(
666                    "ExternalBody",
667                    &ExternalBodySerContent {
668                        externals,
669                        body: fallback.as_deref(),
670                    },
671                )?;
672            }
673            ValueBody::Incomplete {
674                incompleteness,
675                partial_body,
676            } => {
677                map.serialize_entry(
678                    "IncompleteBody",
679                    &IncompleteBodySerContent {
680                        incompleteness,
681                        partial_body: partial_body.as_deref(),
682                    },
683                )?;
684            }
685        }
686        map.end()
687    }
688}
689
690#[derive(Serialize)]
691#[serde(rename_all = "camelCase")]
692struct ExpressionBodySerContent<'a> {
693    body: &'a Value,
694}
695
696#[derive(Serialize)]
697#[serde(rename_all = "camelCase")]
698struct NativeBodySerContent<'a> {
699    native_info: &'a NativeInfo,
700}
701
702#[derive(Serialize)]
703#[serde(rename_all = "camelCase")]
704struct ExternalBodySerContent<'a> {
705    externals: &'a [ExternalBinding],
706    #[serde(skip_serializing_if = "Option::is_none")]
707    body: Option<&'a Value>,
708}
709
710#[derive(Serialize)]
711#[serde(rename_all = "camelCase")]
712struct IncompleteBodySerContent<'a> {
713    incompleteness: &'a Incompleteness,
714    #[serde(rename = "partialBody", skip_serializing_if = "Option::is_none")]
715    partial_body: Option<&'a Value>,
716}
717
718impl<'de> Deserialize<'de> for ValueBody {
719    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
720    where
721        D: Deserializer<'de>,
722    {
723        super::serde_document::deserialize_standalone_with(
724            deserializer,
725            super::serde_document::decode_value_body,
726        )
727    }
728}
729// ============================================================================
730// SERIALIZATION SUPPORT FOR NATIVE HINT
731// ============================================================================
732
733impl Serialize for NativeHint {
734    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
735    where
736        S: Serializer,
737    {
738        let mut map = serializer.serialize_map(Some(1))?;
739        match self {
740            NativeHint::Arithmetic => map.serialize_entry("Arithmetic", &serde_json::json!({}))?,
741            NativeHint::Comparison => map.serialize_entry("Comparison", &serde_json::json!({}))?,
742            NativeHint::StringOp => map.serialize_entry("StringOp", &serde_json::json!({}))?,
743            NativeHint::CollectionOp => {
744                map.serialize_entry("CollectionOp", &serde_json::json!({}))?
745            }
746            NativeHint::PlatformSpecific { platform } => map.serialize_entry(
747                "PlatformSpecific",
748                &serde_json::json!({ "platform": platform }),
749            )?,
750        }
751        map.end()
752    }
753}
754
755impl<'de> Deserialize<'de> for NativeHint {
756    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
757    where
758        D: Deserializer<'de>,
759    {
760        super::serde_document::deserialize_with(
761            deserializer,
762            super::serde_document::decode_native_hint,
763        )
764    }
765}
766
767// ============================================================================
768// SERIALIZATION SUPPORT FOR HOLE REASON
769// ============================================================================
770
771impl Serialize for HoleReason {
772    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
773    where
774        S: Serializer,
775    {
776        let mut map = serializer.serialize_map(Some(1))?;
777        match self {
778            HoleReason::TypeMismatch { expected, found } => map.serialize_entry(
779                "TypeMismatch",
780                &serde_json::json!({ "expected": expected, "found": found }),
781            )?,
782            HoleReason::DeletedDuringRefactor { tx_id } => map.serialize_entry(
783                "DeletedDuringRefactor",
784                &serde_json::json!({ "tx-id": tx_id }),
785            )?,
786            HoleReason::UnresolvedReference { target } => map.serialize_entry(
787                "UnresolvedReference",
788                &serde_json::json!({ "target": target.to_canonical_string() }),
789            )?,
790        }
791        map.end()
792    }
793}
794
795impl<'de> Deserialize<'de> for HoleReason {
796    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
797    where
798        D: Deserializer<'de>,
799    {
800        super::serde_document::deserialize_with(
801            deserializer,
802            super::serde_document::decode_hole_reason,
803        )
804    }
805}
806
807// ============================================================================
808// TESTS
809// ============================================================================
810
811#[cfg(test)]
812mod tests {
813    use super::super::attributes::TypeAttributes;
814    use super::*;
815
816    // Tests from value_expr.rs
817    #[test]
818    fn test_literal_value() {
819        let val: Value = Value::literal(ValueAttributes::default(), Literal::Integer(42.into()));
820        assert!(matches!(
821            val,
822            Value::Literal(_, Literal::Integer(n)) if n == num_bigint::BigInt::from(42)
823        ));
824    }
825
826    #[test]
827    fn test_variable_value() {
828        let val: Value = Value::variable(ValueAttributes::default(), Name::from("x"));
829        assert!(matches!(val, Value::Variable(_, _)));
830    }
831
832    #[test]
833    fn test_unit_value() {
834        let val: Value = Value::unit(ValueAttributes::default());
835        assert!(matches!(val, Value::Unit(_)));
836    }
837
838    #[test]
839    fn test_tuple_value() {
840        let val: Value = Value::tuple(
841            ValueAttributes::default(),
842            vec![
843                Value::unit(ValueAttributes::default()),
844                Value::unit(ValueAttributes::default()),
845            ],
846        );
847        assert!(matches!(val, Value::Tuple(_, elements) if elements.len() == 2));
848    }
849
850    #[test]
851    fn test_lambda_value() {
852        let val: Value = Value::lambda(
853            ValueAttributes::default(),
854            Pattern::wildcard(ValueAttributes::default()),
855            Value::unit(ValueAttributes::default()),
856        );
857        assert!(matches!(val, Value::Lambda(_, _, _)));
858    }
859
860    #[test]
861    fn test_value_definition() {
862        let def: ValueDefinition = ValueDefinition::new(
863            vec![],
864            Type::unit(TypeAttributes::default()),
865            Value::unit(ValueAttributes::default()),
866        );
867        assert!(matches!(def.body, ValueBody::Expression(_)));
868    }
869
870    #[test]
871    fn test_hole_value() {
872        let val: Value = Value::Hole(
873            ValueAttributes::default(),
874            HoleReason::TypeMismatch {
875                expected: "Int".to_string(),
876                found: "String".to_string(),
877            },
878            None,
879        );
880        assert!(matches!(
881            val,
882            Value::Hole(_, HoleReason::TypeMismatch { .. }, None)
883        ));
884    }
885
886    #[test]
887    fn test_native_value_definition() {
888        let def: ValueDefinition = ValueDefinition::native(
889            vec![],
890            Type::unit(TypeAttributes::default()),
891            NativeInfo::new(NativeHint::Arithmetic, Some("add operation".to_string())),
892        );
893        assert!(matches!(def.body, ValueBody::Native { .. }));
894    }
895
896    // Tests from value_def.rs
897    #[test]
898    fn test_native_hint_wrapper_format() {
899        let hint = NativeHint::Arithmetic;
900        let json = serde_json::to_string(&hint).unwrap();
901        assert!(json.contains("\"Arithmetic\""));
902        assert!(json.contains("{}"));
903    }
904
905    #[test]
906    fn test_hole_reason_with_target() {
907        let reason = HoleReason::UnresolvedReference {
908            target: FQName::from_canonical_string("my/pkg:mod#func").unwrap(),
909        };
910        let json = serde_json::to_string(&reason).unwrap();
911        assert!(json.contains("\"UnresolvedReference\""));
912        assert!(json.contains("\"target\""));
913        // FQName serializes to canonical format with # separator
914        assert!(json.contains("my/pkg:mod#func"));
915    }
916
917    #[test]
918    fn test_value_body_expression_wrapper() {
919        let body = ValueBody::Expression(Value::Unit(ValueAttributes::default()));
920        let json = serde_json::to_string(&body).unwrap();
921        assert!(json.contains("\"ExpressionBody\""));
922        assert!(json.contains("\"body\""));
923    }
924}