Skip to main content

gaia_assembler/types/
mapping.rs

1//! Type mapping utilities for Gaia IR
2//! 
3//! This module provides utilities for mapping types to various backend formats,
4//! with special handling for JVM types, type erasure, and generic bounds.
5
6use super::GaiaType;
7use std::collections::HashMap;
8
9/// Type mapping context for type conversion
10#[derive(Debug, Default)]
11pub struct TypeMappingContext {
12    /// Cache for resolved types to avoid redundant calculations
13    type_cache: HashMap<String, GaiaType>,
14    /// Generic type parameters and their bounds
15    generic_bounds: HashMap<String, Vec<GaiaType>>,
16    /// Type erasure information
17    type_erasure_map: HashMap<String, String>,
18}
19
20impl TypeMappingContext {
21    /// Create a new type mapping context
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Add a generic type bound
27    pub fn add_generic_bound(&mut self, type_param: &str, bound: GaiaType) {
28        self.generic_bounds.entry(type_param.to_string())
29            .or_default()
30            .push(bound);
31    }
32
33    /// Add type erasure information
34    pub fn add_type_erasure(&mut self, generic_type: &str, erased_type: &str) {
35        self.type_erasure_map.insert(generic_type.to_string(), erased_type.to_string());
36    }
37
38    /// Get the erased type for a generic type
39    pub fn get_erased_type(&self, generic_type: &str) -> Option<&String> {
40        self.type_erasure_map.get(generic_type)
41    }
42}
43
44/// Parse a type name string to GaiaType
45/// 
46/// Supports primitive types, reference types, array types, and generic types.
47pub fn parse_type_name(type_name: &str, ctx: &mut TypeMappingContext) -> GaiaType {
48    if let Some(gaia_type) = ctx.type_cache.get(type_name) {
49        return gaia_type.clone();
50    }
51
52    let gaia_type = match type_name {
53        "bool" => GaiaType::Bool,
54        "byte" | "i8" => GaiaType::I8,
55        "short" | "i16" => GaiaType::I16,
56        "int" | "i32" => GaiaType::I32,
57        "long" | "i64" => GaiaType::I64,
58        "float" | "f32" => GaiaType::F32,
59        "double" | "f64" => GaiaType::F64,
60        "char" => GaiaType::U16,
61        "void" => GaiaType::Void,
62        
63        "String" => GaiaType::String,
64        "Object" => GaiaType::Object,
65        
66        s if s.starts_with('[') => {
67            let element_type = &s[1..];
68            let gaia_element_type = parse_type_name(element_type, ctx);
69            GaiaType::Array(Box::new(gaia_element_type), 0)
70        }
71        
72        s if s.contains('<') && s.contains('>') => {
73            let (base_type, _type_params) = parse_generic_type(s);
74            
75            if let Some(erased_type) = ctx.get_erased_type(base_type) {
76                GaiaType::Class(erased_type.clone())
77            } else {
78                GaiaType::Class(base_type.to_string())
79            }
80        }
81        
82        s => GaiaType::Class(s.to_string()),
83    };
84
85    ctx.type_cache.insert(type_name.to_string(), gaia_type.clone());
86    gaia_type
87}
88
89/// Legacy alias for backward compatibility
90pub fn map_uir_type_to_gaia_type(uir_type: &str, ctx: &mut TypeMappingContext) -> GaiaType {
91    parse_type_name(uir_type, ctx)
92}
93
94/// Parse generic type string into base type and type parameters
95fn parse_generic_type(generic_type: &str) -> (&str, Vec<&str>) {
96    if let Some(idx) = generic_type.find('<') {
97        let base_type = &generic_type[..idx];
98        let params_str = &generic_type[idx+1..generic_type.len()-1];
99        let type_params = params_str.split(',').map(|p| p.trim()).collect();
100        (base_type, type_params)
101    } else {
102        (generic_type, Vec::new())
103    }
104}
105
106/// Map GaiaType to JVM type descriptor
107pub fn map_gaia_type_to_jvm_descriptor(ty: &GaiaType) -> String {
108    match ty {
109        GaiaType::Void => "V".to_string(),
110        GaiaType::Bool => "Z".to_string(),
111        GaiaType::I8 => "B".to_string(),
112        GaiaType::U8 => "B".to_string(),
113        GaiaType::I16 => "S".to_string(),
114        GaiaType::U16 => "S".to_string(),
115        GaiaType::I32 => "I".to_string(),
116        GaiaType::U32 => "I".to_string(),
117        GaiaType::I64 => "J".to_string(),
118        GaiaType::U64 => "J".to_string(),
119        GaiaType::F32 => "F".to_string(),
120        GaiaType::F64 => "D".to_string(),
121        GaiaType::String => "Ljava/lang/String;".to_string(),
122        GaiaType::Class(name) => format!("L{};", name.replace('.', "/")),
123        GaiaType::Array(inner, _) => format!("[{}", map_gaia_type_to_jvm_descriptor(inner)),
124        GaiaType::Object => "Ljava/lang/Object;".to_string(),
125        GaiaType::Interface(name) => format!("L{};", name.replace('.', "/")),
126        _ => "Ljava/lang/Object;".to_string(),
127    }
128}
129
130/// Check if two Gaia types are compatible
131pub fn are_types_compatible(from: &GaiaType, to: &GaiaType) -> bool {
132    match (from, to) {
133        (f, t) if f == t => true,
134        
135        (GaiaType::I8, GaiaType::I16) => true,
136        (GaiaType::I8, GaiaType::I32) => true,
137        (GaiaType::I8, GaiaType::I64) => true,
138        (GaiaType::I8, GaiaType::F32) => true,
139        (GaiaType::I8, GaiaType::F64) => true,
140        (GaiaType::U8, GaiaType::I16) => true,
141        (GaiaType::U8, GaiaType::I32) => true,
142        (GaiaType::U8, GaiaType::I64) => true,
143        (GaiaType::U8, GaiaType::F32) => true,
144        (GaiaType::U8, GaiaType::F64) => true,
145        (GaiaType::I16, GaiaType::I32) => true,
146        (GaiaType::I16, GaiaType::I64) => true,
147        (GaiaType::I16, GaiaType::F32) => true,
148        (GaiaType::I16, GaiaType::F64) => true,
149        (GaiaType::U16, GaiaType::I32) => true,
150        (GaiaType::U16, GaiaType::I64) => true,
151        (GaiaType::U16, GaiaType::F32) => true,
152        (GaiaType::U16, GaiaType::F64) => true,
153        (GaiaType::I32, GaiaType::I64) => true,
154        (GaiaType::I32, GaiaType::F32) => true,
155        (GaiaType::I32, GaiaType::F64) => true,
156        (GaiaType::U32, GaiaType::I64) => true,
157        (GaiaType::U32, GaiaType::F32) => true,
158        (GaiaType::U32, GaiaType::F64) => true,
159        (GaiaType::I64, GaiaType::F64) => true,
160        (GaiaType::U64, GaiaType::F64) => true,
161        (GaiaType::F32, GaiaType::F64) => true,
162        
163        (GaiaType::String, GaiaType::Object) => true,
164        (GaiaType::Class(_), GaiaType::Object) => true,
165        (GaiaType::Interface(_), GaiaType::Object) => true,
166        (GaiaType::Array(_, _), GaiaType::Object) => true,
167        
168        (GaiaType::Bool, GaiaType::Object) => true,
169        (GaiaType::I8, GaiaType::Object) => true,
170        (GaiaType::U8, GaiaType::Object) => true,
171        (GaiaType::I16, GaiaType::Object) => true,
172        (GaiaType::U16, GaiaType::Object) => true,
173        (GaiaType::I32, GaiaType::Object) => true,
174        (GaiaType::U32, GaiaType::Object) => true,
175        (GaiaType::I64, GaiaType::Object) => true,
176        (GaiaType::U64, GaiaType::Object) => true,
177        (GaiaType::F32, GaiaType::Object) => true,
178        (GaiaType::F64, GaiaType::Object) => true,
179        
180        (GaiaType::Array(f_inner, _), GaiaType::Array(t_inner, _)) => {
181            are_types_compatible(f_inner, t_inner)
182        },
183        
184        (GaiaType::Any, GaiaType::Object) => true,
185        
186        _ => false,
187    }
188}
189
190/// Get the common super type of two Gaia types
191pub fn get_common_super_type(a: &GaiaType, b: &GaiaType) -> Option<GaiaType> {
192    if are_types_compatible(a, b) {
193        return Some(b.clone());
194    }
195    if are_types_compatible(b, a) {
196        return Some(a.clone());
197    }
198    
199    match (a, b) {
200        (GaiaType::String, _) | (_, GaiaType::String) => Some(GaiaType::Object),
201        (GaiaType::Class(_), _) | (_, GaiaType::Class(_)) => Some(GaiaType::Object),
202        (GaiaType::Interface(_), _) | (_, GaiaType::Interface(_)) => Some(GaiaType::Object),
203        (GaiaType::Array(_, _), _) | (_, GaiaType::Array(_, _)) => Some(GaiaType::Object),
204        _ => None,
205    }
206}