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    // === 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 function type
145    pub fn function(params: Vec<SemanticType>, return_type: SemanticType) -> Self {
146        SemanticType::Function(Box::new(FunctionSignature {
147            params: params
148                .into_iter()
149                .map(|t| FunctionParam {
150                    name: None,
151                    param_type: t,
152                    optional: false,
153                })
154                .collect(),
155            return_type,
156            is_fallible: false,
157        }))
158    }
159
160    // === Type Queries ===
161
162    /// Check if type is numeric (for propagating operators)
163    pub fn is_numeric(&self) -> bool {
164        self.is_number_family() || self.is_integer_family()
165    }
166
167    /// Check if this semantic type is in the integer family.
168    pub fn is_integer_family(&self) -> bool {
169        match self {
170            SemanticType::Integer => true,
171            SemanticType::Named(name) => matches!(
172                name.as_str(),
173                "i8" | "u8" | "i16" | "u16" | "i32" | "i64" | "u32" | "u64" | "isize" | "usize"
174            ),
175            _ => false,
176        }
177    }
178
179    /// Check if this semantic type is in the floating-point family.
180    pub fn is_number_family(&self) -> bool {
181        match self {
182            SemanticType::Number => true,
183            SemanticType::Named(name) => matches!(name.as_str(), "f32" | "f64"),
184            _ => false,
185        }
186    }
187
188    /// Check if type is optional
189    pub fn is_option(&self) -> bool {
190        matches!(self, SemanticType::Option(_))
191    }
192
193    /// Check if type is a result
194    pub fn is_result(&self) -> bool {
195        matches!(self, SemanticType::Result { .. })
196    }
197
198    /// Get inner type of Option<T>
199    pub fn option_inner(&self) -> Option<&SemanticType> {
200        match self {
201            SemanticType::Option(inner) => Some(inner),
202            _ => None,
203        }
204    }
205
206    /// Get ok type of Result<T, E>
207    pub fn result_ok_type(&self) -> Option<&SemanticType> {
208        match self {
209            SemanticType::Result { ok_type, .. } => Some(ok_type),
210            _ => None,
211        }
212    }
213
214    /// Check if type contains unresolved type variables
215    pub fn has_type_vars(&self) -> bool {
216        match self {
217            SemanticType::TypeVar(_) => true,
218            SemanticType::Option(inner) => inner.has_type_vars(),
219            SemanticType::Result { ok_type, err_type } => {
220                ok_type.has_type_vars() || err_type.as_ref().is_some_and(|e| e.has_type_vars())
221            }
222            SemanticType::Array(elem) => elem.has_type_vars(),
223            SemanticType::Struct { fields, .. } => fields.iter().any(|(_, t)| t.has_type_vars()),
224            SemanticType::Enum { variants, .. } => variants
225                .iter()
226                .any(|v| v.payload.as_ref().is_some_and(|t| t.has_type_vars())),
227            SemanticType::Function(sig) => {
228                sig.params.iter().any(|p| p.param_type.has_type_vars())
229                    || sig.return_type.has_type_vars()
230            }
231            SemanticType::Generic { args, .. } => args.iter().any(|a| a.has_type_vars()),
232            _ => false,
233        }
234    }
235
236    // === Wire Protocol Conversion ===
237
238    /// Convert semantic type to wire protocol TypeInfo
239    ///
240    /// This bridges the compile-time type system with the wire format
241    /// used for REPL display and external tool integration.
242    pub fn to_type_info(&self) -> TypeInfo {
243        match self {
244            SemanticType::Number => TypeInfo::number(),
245            SemanticType::Integer => TypeInfo::integer(),
246            SemanticType::Bool => TypeInfo::bool(),
247            SemanticType::String => TypeInfo::string(),
248
249            SemanticType::Option(inner) => {
250                let inner_info = inner.to_type_info();
251                TypeInfo {
252                    name: format!("Option<{}>", inner_info.name),
253                    kind: TypeKind::Optional,
254                    fields: None,
255                    generic_params: Some(vec![inner_info]),
256                    variants: None,
257                    description: None,
258                    metadata: None,
259                }
260            }
261
262            SemanticType::Result { ok_type, err_type } => {
263                let ok_info = ok_type.to_type_info();
264                let name = match err_type {
265                    Some(e) => format!("Result<{}, {}>", ok_info.name, e.to_type_info().name),
266                    None => format!("Result<{}>", ok_info.name),
267                };
268                let mut params = vec![ok_info];
269                if let Some(e) = err_type {
270                    params.push(e.to_type_info());
271                }
272                TypeInfo {
273                    name,
274                    kind: TypeKind::Result,
275                    fields: None,
276                    generic_params: Some(params),
277                    variants: None,
278                    description: None,
279                    metadata: None,
280                }
281            }
282
283            SemanticType::Array(elem) => TypeInfo::array(elem.to_type_info()),
284
285            SemanticType::Struct { name, fields } => {
286                let field_infos: Vec<FieldInfo> = fields
287                    .iter()
288                    .map(|(fname, ftype)| FieldInfo::required(fname, ftype.to_type_info()))
289                    .collect();
290                TypeInfo::object(name, field_infos)
291            }
292
293            SemanticType::Enum { name, variants, .. } => {
294                let variant_names: Vec<String> = variants.iter().map(|v| v.name.clone()).collect();
295                TypeInfo {
296                    name: name.clone(),
297                    kind: TypeKind::Enum,
298                    fields: None,
299                    generic_params: None,
300                    variants: Some(variant_names),
301                    description: None,
302                    metadata: None,
303                }
304            }
305
306            SemanticType::Interface { name, .. } => TypeInfo::primitive(name),
307
308            SemanticType::TypeVar(id) => TypeInfo::primitive(format!("T{}", id.0)),
309
310            SemanticType::Named(name) => TypeInfo::primitive(name),
311
312            SemanticType::Generic { name, args } => {
313                let arg_infos: Vec<TypeInfo> = args.iter().map(|a| a.to_type_info()).collect();
314                let arg_names: Vec<String> = arg_infos.iter().map(|a| a.name.clone()).collect();
315                TypeInfo {
316                    name: format!("{}<{}>", name, arg_names.join(", ")),
317                    kind: TypeKind::Object, // Generic types are object-like
318                    fields: None,
319                    generic_params: Some(arg_infos),
320                    variants: None,
321                    description: None,
322                    metadata: None,
323                }
324            }
325
326            SemanticType::Never => TypeInfo::primitive("Never"),
327            SemanticType::Void => TypeInfo::null(),
328
329            SemanticType::Function(sig) => {
330                let param_types: Vec<String> = sig
331                    .params
332                    .iter()
333                    .map(|p| p.param_type.to_type_info().name)
334                    .collect();
335                let ret_type = sig.return_type.to_type_info().name;
336                TypeInfo {
337                    name: format!("({}) -> {}", param_types.join(", "), ret_type),
338                    kind: TypeKind::Function,
339                    fields: None,
340                    generic_params: None,
341                    variants: None,
342                    description: None,
343                    metadata: None,
344                }
345            }
346        }
347    }
348}
349
350impl fmt::Display for SemanticType {
351    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352        match self {
353            SemanticType::Number => write!(f, "Number"),
354            SemanticType::Integer => write!(f, "Integer"),
355            SemanticType::Bool => write!(f, "Bool"),
356            SemanticType::String => write!(f, "String"),
357            SemanticType::Option(inner) => write!(f, "Option<{}>", inner),
358            SemanticType::Result { ok_type, err_type } => match err_type {
359                Some(e) => write!(f, "Result<{}, {}>", ok_type, e),
360                None => write!(f, "Result<{}>", ok_type),
361            },
362            SemanticType::Array(elem) => write!(f, "Vec<{}>", elem),
363            SemanticType::Struct { name, .. } => write!(f, "{}", name),
364            SemanticType::Enum { name, .. } => write!(f, "{}", name),
365            SemanticType::Interface { name, .. } => write!(f, "{}", name),
366            SemanticType::TypeVar(id) => write!(f, "T{}", id.0),
367            SemanticType::Named(name) => write!(f, "{}", name),
368            SemanticType::Generic { name, args } => {
369                write!(f, "{}<", name)?;
370                for (i, arg) in args.iter().enumerate() {
371                    if i > 0 {
372                        write!(f, ", ")?;
373                    }
374                    write!(f, "{}", arg)?;
375                }
376                write!(f, ">")
377            }
378            SemanticType::Never => write!(f, "Never"),
379            SemanticType::Void => write!(f, "Void"),
380            SemanticType::Function(sig) => {
381                write!(f, "(")?;
382                for (i, param) in sig.params.iter().enumerate() {
383                    if i > 0 {
384                        write!(f, ", ")?;
385                    }
386                    write!(f, "{}", param.param_type)?;
387                }
388                write!(f, ") -> {}", sig.return_type)
389            }
390        }
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use super::*;
397
398    #[test]
399    fn test_option_creation() {
400        let opt = SemanticType::option(SemanticType::Number);
401        assert!(opt.is_option());
402        assert_eq!(opt.option_inner(), Some(&SemanticType::Number));
403    }
404
405    #[test]
406    fn test_result_creation() {
407        let res = SemanticType::result(SemanticType::Number);
408        assert!(res.is_result());
409        match &res {
410            SemanticType::Result { ok_type, err_type } => {
411                assert_eq!(**ok_type, SemanticType::Number);
412                assert!(err_type.is_none());
413            }
414            _ => panic!("Expected Result"),
415        }
416    }
417
418    #[test]
419    fn test_display() {
420        assert_eq!(format!("{}", SemanticType::Number), "Number");
421        assert_eq!(
422            format!("{}", SemanticType::option(SemanticType::Number)),
423            "Option<Number>"
424        );
425        assert_eq!(
426            format!("{}", SemanticType::result(SemanticType::String)),
427            "Result<String>"
428        );
429    }
430
431    #[test]
432    fn test_to_type_info_primitives() {
433        let num = SemanticType::Number.to_type_info();
434        assert_eq!(num.name, "Number");
435        assert_eq!(num.kind, TypeKind::Primitive);
436
437        let int = SemanticType::Integer.to_type_info();
438        assert_eq!(int.name, "Integer");
439
440        let bool_t = SemanticType::Bool.to_type_info();
441        assert_eq!(bool_t.name, "Bool");
442
443        let string_t = SemanticType::String.to_type_info();
444        assert_eq!(string_t.name, "String");
445    }
446
447    #[test]
448    fn test_to_type_info_option() {
449        let opt = SemanticType::option(SemanticType::Number).to_type_info();
450        assert_eq!(opt.name, "Option<Number>");
451        assert_eq!(opt.kind, TypeKind::Optional);
452        assert!(opt.generic_params.is_some());
453        assert_eq!(opt.generic_params.as_ref().unwrap().len(), 1);
454    }
455
456    #[test]
457    fn test_to_type_info_result() {
458        let res = SemanticType::result(SemanticType::String).to_type_info();
459        assert_eq!(res.name, "Result<String>");
460        assert_eq!(res.kind, TypeKind::Result);
461
462        let res_with_err =
463            SemanticType::result_with_error(SemanticType::Number, SemanticType::String)
464                .to_type_info();
465        assert_eq!(res_with_err.name, "Result<Number, String>");
466    }
467
468    #[test]
469    fn test_to_type_info_array() {
470        let arr = SemanticType::array(SemanticType::Bool).to_type_info();
471        assert_eq!(arr.name, "Array<Bool>");
472        assert_eq!(arr.kind, TypeKind::Array);
473    }
474
475    #[test]
476    fn test_named_width_numeric_families() {
477        assert!(SemanticType::Named("i16".to_string()).is_numeric());
478        assert!(SemanticType::Named("u64".to_string()).is_integer_family());
479        assert!(SemanticType::Named("f32".to_string()).is_number_family());
480        assert!(SemanticType::Named("f64".to_string()).is_numeric());
481        assert!(!SemanticType::Named("Candle".to_string()).is_numeric());
482    }
483}