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}