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