Skip to main content

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 rustc_hash::FxHashMap as 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            builtin_ownership_id: self.builtin_ownership_id,
63            builtin_thread_safety_id: self.builtin_thread_safety_id,
64            builtin_ordering_id: self.builtin_ordering_id,
65            target: Target::default(), // Will be overridden by caller if needed
66            inference_ctx,
67            known: KnownSymbols::new(self.interner),
68            type_pool: self.type_pool.clone(),
69            module_registry: crate::sema_context::ModuleRegistry::new(),
70            source_file_path: None, // Will be set when analyzing specific files
71            file_paths: self.file_paths.clone(), // Copy file paths for module resolution
72            param_arena: &self.param_arena,
73        }
74    }
75
76    /// Build the inference context portion of SemaContext.
77    pub(crate) fn build_sema_context_inference(&self) -> SemaContextInferenceContext {
78        // Build function signatures with InferType for constraint generation
79        let func_sigs: HashMap<Spur, FunctionSig> = self
80            .functions
81            .iter()
82            .map(|(name, info)| {
83                (
84                    *name,
85                    FunctionSig {
86                        param_types: self
87                            .param_arena
88                            .types(info.params)
89                            .iter()
90                            .map(|t| self.type_to_infer_type(*t))
91                            .collect(),
92                        return_type: self.type_to_infer_type(info.return_type),
93                        is_generic: info.is_generic,
94                        param_modes: self.param_arena.modes(info.params).to_vec(),
95                        param_comptime: self.param_arena.comptime(info.params).to_vec(),
96                        param_names: self.param_arena.names(info.params).to_vec(),
97                        return_type_sym: info.return_type_sym,
98                    },
99                )
100            })
101            .collect();
102
103        // Build struct types map (name -> Type::new_struct(id))
104        let struct_types: HashMap<Spur, Type> = self
105            .structs
106            .iter()
107            .map(|(name, id)| (*name, Type::new_struct(*id)))
108            .collect();
109
110        // Build enum types map (name -> Type::new_enum(id))
111        let enum_types: HashMap<Spur, Type> = self
112            .enums
113            .iter()
114            .map(|(name, id)| (*name, Type::new_enum(*id)))
115            .collect();
116
117        // Build method signatures with InferType for constraint generation
118        // Exclude method-level-generic methods (ADR-0055); inference falls
119        // back to a fresh type var for those and specialization handles the
120        // concrete body analysis.
121        let method_sigs: HashMap<(StructId, Spur), MethodSig> = self
122            .methods
123            .iter()
124            .filter(|(_, info)| !info.is_generic)
125            .map(|((struct_id, method_name), info)| {
126                (
127                    (*struct_id, *method_name),
128                    MethodSig {
129                        struct_type: info.struct_type,
130                        has_self: info.has_self,
131                        param_types: self
132                            .param_arena
133                            .types(info.params)
134                            .iter()
135                            .map(|t| self.type_to_infer_type(*t))
136                            .collect(),
137                        return_type: self.type_to_infer_type(info.return_type),
138                    },
139                )
140            })
141            .collect();
142
143        SemaContextInferenceContext {
144            func_sigs,
145            struct_types,
146            enum_types,
147            method_sigs,
148        }
149    }
150}