Skip to main content

shape_runtime/type_system/
semantic.rs

1//! Semantic Types
2//!
3//! Defines the types that users see and work with in Shape code.
4//! These are separate from storage types (how data is physically represented).
5//!
6//! Key design:
7//! - `Option<f64>` is a semantic type - user sees it as nullable
8//! - Storage may use NaN sentinel instead of tagged union
9//! - `Result<T>` defaults to universal Error (no explicit E required)
10
11use shape_wire::metadata::{FieldInfo, TypeInfo, TypeKind};
12use std::fmt;
13use std::hash::Hash;
14
15/// Semantic type identifier for type variables during inference
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct TypeVarId(pub u32);
18
19/// Semantic types - what the user sees in type annotations
20#[derive(Clone, Debug, PartialEq, Eq, Hash)]
21pub enum SemanticType {
22    // === Primitives ===
23    /// Floating-point number (f64)
24    Number,
25    /// Integer (i64)
26    Integer,
27    /// Boolean
28    Bool,
29    /// String
30    String,
31
32    // === Generic Containers ===
33    /// Optional value: Option<T>
34    /// - For numeric T: Uses NaN sentinel in storage
35    /// - For other T: Uses discriminated union
36    Option(Box<SemanticType>),
37
38    /// Result type: Result<T> or Result<T, E>
39    /// - err_type = None means universal Error type
40    Result {
41        ok_type: Box<SemanticType>,
42        err_type: Option<Box<SemanticType>>,
43    },
44
45    /// Array of values: Vec<T>
46    Array(Box<SemanticType>),
47
48    // === User-Defined Types ===
49    /// Struct type with name and fields
50    Struct {
51        name: String,
52        fields: Vec<(String, SemanticType)>,
53    },
54
55    /// Enum type with variants
56    Enum {
57        name: String,
58        variants: Vec<EnumVariant>,
59        type_params: Vec<String>,
60    },
61
62    /// Interface/trait type
63    Interface {
64        name: String,
65        methods: Vec<(String, FunctionSignature)>,
66    },
67
68    // === Type System Internals ===
69    /// Type variable for inference (α, β, γ)
70    TypeVar(TypeVarId),
71
72    /// Named type reference (before resolution)
73    Named(String),
74
75    /// Generic type instantiation: MyType<A, B>
76    Generic {
77        name: String,
78        args: Vec<SemanticType>,
79    },
80
81    // === Reference Types ===
82    /// Shared reference to a value: &T
83    Ref(Box<SemanticType>),
84    /// Exclusive (mutable) reference to a value: &mut T
85    RefMut(Box<SemanticType>),
86
87    // === Special Types ===
88    /// Bottom type - computation that never returns (e.g., panic, infinite loop)
89    Never,
90
91    /// Void - no value
92    Void,
93
94    /// Function type
95    Function(Box<FunctionSignature>),
96}
97
98/// Function signature
99#[derive(Clone, Debug, PartialEq, Eq, Hash)]
100pub struct FunctionSignature {
101    pub params: Vec<FunctionParam>,
102    pub return_type: SemanticType,
103    pub is_fallible: bool, // True if function uses ? operator
104}
105
106/// Function parameter
107#[derive(Clone, Debug, PartialEq, Eq, Hash)]
108pub struct FunctionParam {
109    pub name: Option<String>,
110    pub param_type: SemanticType,
111    pub optional: bool,
112}
113
114/// Enum variant
115#[derive(Clone, Debug, PartialEq, Eq, Hash)]
116pub struct EnumVariant {
117    pub name: String,
118    pub payload: Option<SemanticType>,
119}
120
121impl SemanticType {
122    // === Constructors ===
123
124    /// Create Option<T> type
125    pub fn option(inner: SemanticType) -> Self {
126        SemanticType::Option(Box::new(inner))
127    }
128
129    /// Create Result<T> type with universal Error
130    pub fn result(ok_type: SemanticType) -> Self {
131        SemanticType::Result {
132            ok_type: Box::new(ok_type),
133            err_type: None,
134        }
135    }
136
137    /// Create Result<T, E> type with specific error
138    pub fn result_with_error(ok_type: SemanticType, err_type: SemanticType) -> Self {
139        SemanticType::Result {
140            ok_type: Box::new(ok_type),
141            err_type: Some(Box::new(err_type)),
142        }
143    }
144
145    /// Create Vec<T> type
146    pub fn array(element: SemanticType) -> Self {
147        SemanticType::Array(Box::new(element))
148    }
149
150    /// Create shared reference type: &T
151    pub fn shared_ref(inner: SemanticType) -> Self {
152        SemanticType::Ref(Box::new(inner))
153    }
154
155    /// Create exclusive reference type: &mut T
156    pub fn exclusive_ref(inner: SemanticType) -> Self {
157        SemanticType::RefMut(Box::new(inner))
158    }
159
160    /// Create function type
161    pub fn function(params: Vec<SemanticType>, return_type: SemanticType) -> Self {
162        SemanticType::Function(Box::new(FunctionSignature {
163            params: params
164                .into_iter()
165                .map(|t| FunctionParam {
166                    name: None,
167                    param_type: t,
168                    optional: false,
169                })
170                .collect(),
171            return_type,
172            is_fallible: false,
173        }))
174    }
175
176    // === Type Queries ===
177
178    /// Check if type is numeric (for propagating operators)
179    pub fn is_numeric(&self) -> bool {
180        self.is_number_family() || self.is_integer_family()
181    }
182
183    /// Check if this semantic type is in the integer family.
184    pub fn is_integer_family(&self) -> bool {
185        match self {
186            SemanticType::Integer => true,
187            SemanticType::Named(name) => matches!(
188                name.as_str(),
189                "i8" | "u8" | "i16" | "u16" | "i32" | "i64" | "u32" | "u64" | "isize" | "usize"
190            ),
191            _ => false,
192        }
193    }
194
195    /// Check if this semantic type is in the floating-point family.
196    pub fn is_number_family(&self) -> bool {
197        match self {
198            SemanticType::Number => true,
199            SemanticType::Named(name) => matches!(name.as_str(), "f32" | "f64"),
200            _ => false,
201        }
202    }
203
204    /// Check if this is a reference type (&T or &mut T).
205    pub fn is_reference(&self) -> bool {
206        matches!(self, SemanticType::Ref(_) | SemanticType::RefMut(_))
207    }
208
209    /// Check if this is an exclusive (mutable) reference type (&mut T).
210    pub fn is_exclusive_ref(&self) -> bool {
211        matches!(self, SemanticType::RefMut(_))
212    }
213
214    /// Get the inner type of a reference (&T → T, &mut T → T).
215    pub fn deref_type(&self) -> Option<&SemanticType> {
216        match self {
217            SemanticType::Ref(inner) | SemanticType::RefMut(inner) => Some(inner),
218            _ => None,
219        }
220    }
221
222    /// Strip reference wrappers to get the underlying value type.
223    /// For non-reference types, returns self.
224    pub fn auto_deref(&self) -> &SemanticType {
225        match self {
226            SemanticType::Ref(inner) | SemanticType::RefMut(inner) => inner.auto_deref(),
227            other => other,
228        }
229    }
230
231    /// Check if type is optional
232    pub fn is_option(&self) -> bool {
233        matches!(self, SemanticType::Option(_))
234    }
235
236    /// Check if type is a result
237    pub fn is_result(&self) -> bool {
238        matches!(self, SemanticType::Result { .. })
239    }
240
241    /// Get inner type of Option<T>
242    pub fn option_inner(&self) -> Option<&SemanticType> {
243        match self {
244            SemanticType::Option(inner) => Some(inner),
245            _ => None,
246        }
247    }
248
249    /// Get ok type of Result<T, E>
250    pub fn result_ok_type(&self) -> Option<&SemanticType> {
251        match self {
252            SemanticType::Result { ok_type, .. } => Some(ok_type),
253            _ => None,
254        }
255    }
256
257    /// Check if type contains unresolved type variables
258    pub fn has_type_vars(&self) -> bool {
259        match self {
260            SemanticType::TypeVar(_) => true,
261            SemanticType::Option(inner) => inner.has_type_vars(),
262            SemanticType::Result { ok_type, err_type } => {
263                ok_type.has_type_vars() || err_type.as_ref().is_some_and(|e| e.has_type_vars())
264            }
265            SemanticType::Array(elem) => elem.has_type_vars(),
266            SemanticType::Struct { fields, .. } => fields.iter().any(|(_, t)| t.has_type_vars()),
267            SemanticType::Enum { variants, .. } => variants
268                .iter()
269                .any(|v| v.payload.as_ref().is_some_and(|t| t.has_type_vars())),
270            SemanticType::Function(sig) => {
271                sig.params.iter().any(|p| p.param_type.has_type_vars())
272                    || sig.return_type.has_type_vars()
273            }
274            SemanticType::Generic { args, .. } => args.iter().any(|a| a.has_type_vars()),
275            _ => false,
276        }
277    }
278
279    // === Wire Protocol Conversion ===
280
281    /// Convert semantic type to wire protocol TypeInfo
282    ///
283    /// This bridges the compile-time type system with the wire format
284    /// used for REPL display and external tool integration.
285    pub fn to_type_info(&self) -> TypeInfo {
286        match self {
287            SemanticType::Number => TypeInfo::number(),
288            SemanticType::Integer => TypeInfo::integer(),
289            SemanticType::Bool => TypeInfo::bool(),
290            SemanticType::String => TypeInfo::string(),
291
292            SemanticType::Option(inner) => {
293                let inner_info = inner.to_type_info();
294                TypeInfo {
295                    name: format!("Option<{}>", inner_info.name),
296                    kind: TypeKind::Optional,
297                    fields: None,
298                    generic_params: Some(vec![inner_info]),
299                    variants: None,
300                    description: None,
301                    metadata: None,
302                }
303            }
304
305            SemanticType::Result { ok_type, err_type } => {
306                let ok_info = ok_type.to_type_info();
307                let name = match err_type {
308                    Some(e) => format!("Result<{}, {}>", ok_info.name, e.to_type_info().name),
309                    None => format!("Result<{}>", ok_info.name),
310                };
311                let mut params = vec![ok_info];
312                if let Some(e) = err_type {
313                    params.push(e.to_type_info());
314                }
315                TypeInfo {
316                    name,
317                    kind: TypeKind::Result,
318                    fields: None,
319                    generic_params: Some(params),
320                    variants: None,
321                    description: None,
322                    metadata: None,
323                }
324            }
325
326            SemanticType::Array(elem) => TypeInfo::array(elem.to_type_info()),
327
328            SemanticType::Struct { name, fields } => {
329                let field_infos: Vec<FieldInfo> = fields
330                    .iter()
331                    .map(|(fname, ftype)| FieldInfo::required(fname, ftype.to_type_info()))
332                    .collect();
333                TypeInfo::object(name, field_infos)
334            }
335
336            SemanticType::Enum { name, variants, .. } => {
337                let variant_names: Vec<String> = variants.iter().map(|v| v.name.clone()).collect();
338                TypeInfo {
339                    name: name.clone(),
340                    kind: TypeKind::Enum,
341                    fields: None,
342                    generic_params: None,
343                    variants: Some(variant_names),
344                    description: None,
345                    metadata: None,
346                }
347            }
348
349            SemanticType::Interface { name, .. } => TypeInfo::primitive(name),
350
351            SemanticType::TypeVar(id) => TypeInfo::primitive(format!("T{}", id.0)),
352
353            SemanticType::Named(name) => TypeInfo::primitive(name),
354
355            SemanticType::Generic { name, args } => {
356                let arg_infos: Vec<TypeInfo> = args.iter().map(|a| a.to_type_info()).collect();
357                let arg_names: Vec<String> = arg_infos.iter().map(|a| a.name.clone()).collect();
358                TypeInfo {
359                    name: format!("{}<{}>", name, arg_names.join(", ")),
360                    kind: TypeKind::Object, // Generic types are object-like
361                    fields: None,
362                    generic_params: Some(arg_infos),
363                    variants: None,
364                    description: None,
365                    metadata: None,
366                }
367            }
368
369            SemanticType::Ref(inner) => {
370                let inner_info = inner.to_type_info();
371                TypeInfo::primitive(format!("&{}", inner_info.name))
372            }
373            SemanticType::RefMut(inner) => {
374                let inner_info = inner.to_type_info();
375                TypeInfo::primitive(format!("&mut {}", inner_info.name))
376            }
377            SemanticType::Never => TypeInfo::primitive("Never"),
378            SemanticType::Void => TypeInfo::null(),
379
380            SemanticType::Function(sig) => {
381                let param_types: Vec<String> = sig
382                    .params
383                    .iter()
384                    .map(|p| p.param_type.to_type_info().name)
385                    .collect();
386                let ret_type = sig.return_type.to_type_info().name;
387                TypeInfo {
388                    name: format!("({}) -> {}", param_types.join(", "), ret_type),
389                    kind: TypeKind::Function,
390                    fields: None,
391                    generic_params: None,
392                    variants: None,
393                    description: None,
394                    metadata: None,
395                }
396            }
397        }
398    }
399}
400
401impl fmt::Display for SemanticType {
402    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403        match self {
404            SemanticType::Number => write!(f, "Number"),
405            SemanticType::Integer => write!(f, "Integer"),
406            SemanticType::Bool => write!(f, "Bool"),
407            SemanticType::String => write!(f, "String"),
408            SemanticType::Option(inner) => write!(f, "Option<{}>", inner),
409            SemanticType::Result { ok_type, err_type } => match err_type {
410                Some(e) => write!(f, "Result<{}, {}>", ok_type, e),
411                None => write!(f, "Result<{}>", ok_type),
412            },
413            SemanticType::Array(elem) => write!(f, "Vec<{}>", elem),
414            SemanticType::Struct { name, .. } => write!(f, "{}", name),
415            SemanticType::Enum { name, .. } => write!(f, "{}", name),
416            SemanticType::Interface { name, .. } => write!(f, "{}", name),
417            SemanticType::TypeVar(id) => write!(f, "T{}", id.0),
418            SemanticType::Named(name) => write!(f, "{}", name),
419            SemanticType::Generic { name, args } => {
420                write!(f, "{}<", name)?;
421                for (i, arg) in args.iter().enumerate() {
422                    if i > 0 {
423                        write!(f, ", ")?;
424                    }
425                    write!(f, "{}", arg)?;
426                }
427                write!(f, ">")
428            }
429            SemanticType::Ref(inner) => write!(f, "&{}", inner),
430            SemanticType::RefMut(inner) => write!(f, "&mut {}", inner),
431            SemanticType::Never => write!(f, "Never"),
432            SemanticType::Void => write!(f, "Void"),
433            SemanticType::Function(sig) => {
434                write!(f, "(")?;
435                for (i, param) in sig.params.iter().enumerate() {
436                    if i > 0 {
437                        write!(f, ", ")?;
438                    }
439                    write!(f, "{}", param.param_type)?;
440                }
441                write!(f, ") -> {}", sig.return_type)
442            }
443        }
444    }
445}
446
447#[cfg(test)]
448mod tests {
449    use super::*;
450
451    #[test]
452    fn test_option_creation() {
453        let opt = SemanticType::option(SemanticType::Number);
454        assert!(opt.is_option());
455        assert_eq!(opt.option_inner(), Some(&SemanticType::Number));
456    }
457
458    #[test]
459    fn test_result_creation() {
460        let res = SemanticType::result(SemanticType::Number);
461        assert!(res.is_result());
462        match &res {
463            SemanticType::Result { ok_type, err_type } => {
464                assert_eq!(**ok_type, SemanticType::Number);
465                assert!(err_type.is_none());
466            }
467            _ => panic!("Expected Result"),
468        }
469    }
470
471    #[test]
472    fn test_display() {
473        assert_eq!(format!("{}", SemanticType::Number), "Number");
474        assert_eq!(
475            format!("{}", SemanticType::option(SemanticType::Number)),
476            "Option<Number>"
477        );
478        assert_eq!(
479            format!("{}", SemanticType::result(SemanticType::String)),
480            "Result<String>"
481        );
482    }
483
484    #[test]
485    fn test_to_type_info_primitives() {
486        let num = SemanticType::Number.to_type_info();
487        assert_eq!(num.name, "Number");
488        assert_eq!(num.kind, TypeKind::Primitive);
489
490        let int = SemanticType::Integer.to_type_info();
491        assert_eq!(int.name, "Integer");
492
493        let bool_t = SemanticType::Bool.to_type_info();
494        assert_eq!(bool_t.name, "Bool");
495
496        let string_t = SemanticType::String.to_type_info();
497        assert_eq!(string_t.name, "String");
498    }
499
500    #[test]
501    fn test_to_type_info_option() {
502        let opt = SemanticType::option(SemanticType::Number).to_type_info();
503        assert_eq!(opt.name, "Option<Number>");
504        assert_eq!(opt.kind, TypeKind::Optional);
505        assert!(opt.generic_params.is_some());
506        assert_eq!(opt.generic_params.as_ref().unwrap().len(), 1);
507    }
508
509    #[test]
510    fn test_to_type_info_result() {
511        let res = SemanticType::result(SemanticType::String).to_type_info();
512        assert_eq!(res.name, "Result<String>");
513        assert_eq!(res.kind, TypeKind::Result);
514
515        let res_with_err =
516            SemanticType::result_with_error(SemanticType::Number, SemanticType::String)
517                .to_type_info();
518        assert_eq!(res_with_err.name, "Result<Number, String>");
519    }
520
521    #[test]
522    fn test_to_type_info_array() {
523        let arr = SemanticType::array(SemanticType::Bool).to_type_info();
524        assert_eq!(arr.name, "Array<Bool>");
525        assert_eq!(arr.kind, TypeKind::Array);
526    }
527
528    #[test]
529    fn test_named_width_numeric_families() {
530        assert!(SemanticType::Named("i16".to_string()).is_numeric());
531        assert!(SemanticType::Named("u64".to_string()).is_integer_family());
532        assert!(SemanticType::Named("f32".to_string()).is_number_family());
533        assert!(SemanticType::Named("f64".to_string()).is_numeric());
534        assert!(!SemanticType::Named("Candle".to_string()).is_numeric());
535    }
536
537    // === Reference type tests ===
538
539    #[test]
540    fn test_shared_ref_creation() {
541        let r = SemanticType::shared_ref(SemanticType::Integer);
542        assert!(r.is_reference());
543        assert!(!r.is_exclusive_ref());
544        assert_eq!(r.deref_type(), Some(&SemanticType::Integer));
545    }
546
547    #[test]
548    fn test_exclusive_ref_creation() {
549        let r = SemanticType::exclusive_ref(SemanticType::Integer);
550        assert!(r.is_reference());
551        assert!(r.is_exclusive_ref());
552        assert_eq!(r.deref_type(), Some(&SemanticType::Integer));
553    }
554
555    #[test]
556    fn test_auto_deref() {
557        let r = SemanticType::shared_ref(SemanticType::Integer);
558        assert_eq!(r.auto_deref(), &SemanticType::Integer);
559
560        // Non-reference types return themselves
561        assert_eq!(SemanticType::Integer.auto_deref(), &SemanticType::Integer);
562
563        // Nested refs deref all the way through
564        let nested = SemanticType::shared_ref(SemanticType::shared_ref(SemanticType::Bool));
565        assert_eq!(nested.auto_deref(), &SemanticType::Bool);
566    }
567
568    #[test]
569    fn test_ref_display() {
570        let shared = SemanticType::shared_ref(SemanticType::Integer);
571        assert_eq!(format!("{}", shared), "&Integer");
572
573        let exclusive = SemanticType::exclusive_ref(SemanticType::Integer);
574        assert_eq!(format!("{}", exclusive), "&mut Integer");
575    }
576
577    #[test]
578    fn test_ref_to_type_info() {
579        let r = SemanticType::shared_ref(SemanticType::Number);
580        let info = r.to_type_info();
581        assert_eq!(info.name, "&Number");
582    }
583
584    #[test]
585    fn test_ref_is_not_numeric() {
586        let r = SemanticType::shared_ref(SemanticType::Integer);
587        assert!(!r.is_numeric());
588    }
589
590    #[test]
591    fn test_non_ref_deref_type_is_none() {
592        assert!(SemanticType::Integer.deref_type().is_none());
593        assert!(SemanticType::String.deref_type().is_none());
594    }
595}