gruel_air/sema/
sema_ctx_builder.rs

1//! SemaContext builder implementation.
2//!
3//! This module contains methods for building a [`SemaContext`] from a [`Sema`]
4//! for use in parallel function body analysis.
5
6use std::collections::HashMap;
7
8use gruel_target::Target;
9use lasso::Spur;
10
11use crate::inference::{FunctionSig, MethodSig};
12use crate::sema_context::{InferenceContext as SemaContextInferenceContext, SemaContext};
13use crate::types::{StructId, Type};
14
15use super::{KnownSymbols, Sema};
16
17impl<'a> Sema<'a> {
18    /// Build a SemaContext from the current Sema state.
19    ///
20    /// This creates an immutable context that can be shared across threads
21    /// for parallel function body analysis. The SemaContext contains all
22    /// type definitions, function signatures, and method signatures.
23    ///
24    /// The returned SemaContext borrows functions and methods from Sema,
25    /// so Sema must outlive the SemaContext. This is reflected in the
26    /// lifetime relationship: the returned context lives for `'s` (the
27    /// borrow of self), not `'a` (the lifetime of the RIR/interner).
28    ///
29    /// # Usage
30    ///
31    /// ```ignore
32    /// let mut sema = Sema::new(rir, interner, preview);
33    /// sema.inject_builtin_types();
34    /// sema.register_type_names()?;
35    /// sema.resolve_declarations()?;
36    /// let ctx = sema.build_sema_context();
37    /// // Now ctx can be shared across threads for parallel analysis
38    /// // (while sema is borrowed)
39    /// ```
40    pub fn build_sema_context<'s>(&'s self) -> SemaContext<'s>
41    where
42        'a: 's,
43    {
44        // Build the inference context
45        let inference_ctx = self.build_sema_context_inference();
46
47        SemaContext {
48            rir: self.rir,
49            interner: self.interner,
50            structs: self.structs.clone(),
51            enums: self.enums.clone(),
52            // Pass references to functions/methods/constants instead of cloning.
53            // This is safe because after declaration gathering, these HashMaps are immutable.
54            functions: &self.functions,
55            methods: &self.methods,
56            constants: &self.constants,
57            preview_features: self.preview_features.clone(),
58            builtin_string_id: self.builtin_string_id,
59            builtin_arch_id: self.builtin_arch_id,
60            builtin_os_id: self.builtin_os_id,
61            builtin_typekind_id: self.builtin_typekind_id,
62            target: Target::default(), // Will be overridden by caller if needed
63            inference_ctx,
64            known: KnownSymbols::new(self.interner),
65            type_pool: self.type_pool.clone(),
66            module_registry: crate::sema_context::ModuleRegistry::new(),
67            source_file_path: None, // Will be set when analyzing specific files
68            file_paths: self.file_paths.clone(), // Copy file paths for module resolution
69            param_arena: &self.param_arena,
70        }
71    }
72
73    /// Build the inference context portion of SemaContext.
74    pub(crate) fn build_sema_context_inference(&self) -> SemaContextInferenceContext {
75        // Build function signatures with InferType for constraint generation
76        let func_sigs: HashMap<Spur, FunctionSig> = self
77            .functions
78            .iter()
79            .map(|(name, info)| {
80                (
81                    *name,
82                    FunctionSig {
83                        param_types: self
84                            .param_arena
85                            .types(info.params)
86                            .iter()
87                            .map(|t| self.type_to_infer_type(*t))
88                            .collect(),
89                        return_type: self.type_to_infer_type(info.return_type),
90                        is_generic: info.is_generic,
91                        param_modes: self.param_arena.modes(info.params).to_vec(),
92                        param_comptime: self.param_arena.comptime(info.params).to_vec(),
93                        param_names: self.param_arena.names(info.params).to_vec(),
94                        return_type_sym: info.return_type_sym,
95                    },
96                )
97            })
98            .collect();
99
100        // Build struct types map (name -> Type::new_struct(id))
101        let struct_types: HashMap<Spur, Type> = self
102            .structs
103            .iter()
104            .map(|(name, id)| (*name, Type::new_struct(*id)))
105            .collect();
106
107        // Build enum types map (name -> Type::new_enum(id))
108        let enum_types: HashMap<Spur, Type> = self
109            .enums
110            .iter()
111            .map(|(name, id)| (*name, Type::new_enum(*id)))
112            .collect();
113
114        // Build method signatures with InferType for constraint generation
115        let method_sigs: HashMap<(StructId, Spur), MethodSig> = self
116            .methods
117            .iter()
118            .map(|((struct_id, method_name), info)| {
119                (
120                    (*struct_id, *method_name),
121                    MethodSig {
122                        struct_type: info.struct_type,
123                        has_self: info.has_self,
124                        param_types: self
125                            .param_arena
126                            .types(info.params)
127                            .iter()
128                            .map(|t| self.type_to_infer_type(*t))
129                            .collect(),
130                        return_type: self.type_to_infer_type(info.return_type),
131                    },
132                )
133            })
134            .collect();
135
136        SemaContextInferenceContext {
137            func_sigs,
138            struct_types,
139            enum_types,
140            method_sigs,
141        }
142    }
143}