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