1mod binder_form;
2mod bindings;
3mod budget_arena;
4mod classified_form;
5mod compile_time_check;
6mod context;
7mod declared_trait;
8mod defining_call;
9mod docstring_notes;
10mod documented_terms;
11mod duplicate_definitions;
12mod enclosing_index;
13mod evaluated_forms;
14mod expansion_limit;
15mod expression;
16mod failed_definition;
17mod field_keyword;
18mod form_budget;
19mod generated_entry;
20mod globals;
21mod host;
22mod input_terms;
23mod introduced;
24mod macro_call;
25mod macro_function;
26mod macro_origins;
27#[cfg(test)]
28mod macro_value_limits;
29mod misplaced_definition;
30mod module_body;
31mod module_loading;
32mod module_notes;
33mod module_survey;
34mod names;
35mod noted_term;
36mod noted_terms;
37mod notes_module;
38mod prelude_state;
39mod problem_mark;
40mod problem_report;
41mod problems;
42mod recorded_inputs;
43mod recovered_errors;
44mod recur_check;
45mod rest_of_body;
46mod result_printer;
47mod returned_arguments;
48mod rust_clauses;
49mod rust_type;
50mod saved_definitions;
51mod saved_index;
52mod saved_notes;
53mod saved_values;
54mod session;
55mod set_aside_input;
56mod set_aside_problems;
57mod shape;
58mod sourced_items;
59mod spliced_forms;
60mod string_view;
61mod structural_path_claim;
62mod structural_path_claims;
63mod structural_traits;
64mod top_level_form;
65mod try_check;
66mod type_expr;
67mod type_note;
68mod type_parameters;
69
70use std::rc::Rc;
71
72use rustc_hash::{FxHashMap, FxHashSet};
73
74use crate::core::{
75 BindingArena, BindingId, BindingKind, CoreModule, ModuleId, ModulePath, Namespace, References,
76};
77use crate::diagnostic::Diagnostics;
78use crate::interpret::{Closure, Interpreter, Value};
79use crate::modules::{ModuleRegistry, ModuleSources};
80use crate::reader::Form;
81use crate::scope::{BindingTable, Phase, Scope, Scopes};
82use crate::source::{SourceId, SourceMap, Span};
83use bindings::Bindings;
84use budget_arena::BudgetArena;
85pub use classified_form::ClassifiedForm;
86use docstring_notes::DocstringNotes;
87use documented_terms::DocumentedTerms;
88use duplicate_definitions::DuplicateDefinitions;
89use evaluated_forms::EvaluatedForms;
90pub use generated_entry::GeneratedEntry;
91use globals::{GlobalTable, LoweredGlobals};
92pub use input_terms::InputTerms;
93pub use macro_call::MacroOrigin;
94use macro_call::MacroTable;
95pub use macro_origins::MacroOrigins;
96use module_notes::{ModuleNotes, NotesCheckpoint};
97pub use module_survey::ModuleSurvey;
98use noted_term::NotedTerm;
99use noted_terms::NotedTerms;
100use notes_module::NotesModule;
101pub use prelude_state::{PreludeState, UnreadablePrelude};
102use problem_report::ProblemReport;
103pub use problems::ExpandProblems;
104use recorded_inputs::RecordedInputs;
105pub use recorded_inputs::{BoundName, LoadedModule};
106use recovered_errors::RecoveredErrors;
107pub use result_printer::{GeneratedFunction, ResultPrinter};
108pub use saved_definitions::PendingDefinitions;
109use saved_definitions::{DefinitionSaver, SavedDefinitions, SavedTables};
110use saved_values::SavedValues;
111pub use session::ExpansionSession;
112pub use set_aside_input::SetAsideInput;
113pub use set_aside_problems::SetAsideProblems;
114use string_view::StringViewSearch;
115use structural_path_claims::StructuralPathClaims;
116use structural_traits::StructuralTraits;
117use type_note::TypeNote;
118
119pub struct Program {
120 pub modules: Vec<CoreModule>,
121 pub entry: ModuleId,
122 pub entry_function: Option<BindingId>,
123 pub bindings: BindingArena,
124 pub macro_origins: Rc<MacroOrigins>,
125 pub macro_helpers: FxHashSet<BindingId>,
126 pub string_view: Option<BindingId>,
127 pub checked_roots: Vec<BindingId>,
128 pub pending_definitions: PendingDefinitions,
129 pub warnings: Diagnostics,
130 pub expansion: ExpansionWork,
131}
132
133#[derive(Clone, Copy, Default)]
134pub struct ExpansionWork {
135 pub lowered_forms: usize,
136}
137
138impl Program {
139 pub(super) const WRITTEN_ENTRY_FUNCTION: &str = "main";
140
141 pub fn entry_module(&self) -> &CoreModule {
142 self.modules
143 .iter()
144 .find(|module| module.id == self.entry)
145 .expect("the entry module is expanded")
146 }
147
148 pub fn prelude_macro_helpers(&self) -> FxHashSet<BindingId> {
149 let prelude: FxHashSet<ModuleId> = self
150 .modules
151 .iter()
152 .filter(|module| ModuleSources::is_prelude(&module.path))
153 .map(|module| module.id)
154 .collect();
155 let is_prelude_global = |binding: BindingId| {
156 matches!(self.bindings.get(binding).kind(),
157 BindingKind::Global(module) if prelude.contains(&module))
158 };
159 self.macro_helpers
160 .iter()
161 .copied()
162 .filter(|binding| self.bindings.is_saved(*binding) || is_prelude_global(*binding))
163 .collect()
164 }
165
166 pub fn check_also(&mut self, binding: BindingId) {
167 self.checked_roots.push(binding);
168 self.pending_definitions
169 .restore(&mut self.modules, vec![binding]);
170 }
171
172 fn restore_reached(&mut self) {
173 let roots = self
174 .modules
175 .iter()
176 .flat_map(CoreModule::definitions)
177 .flat_map(|(_, value)| References::of(value, &self.bindings).into_globals())
178 .collect();
179 self.pending_definitions.restore(&mut self.modules, roots);
180 }
181
182 fn written_entry_function(&self) -> Option<BindingId> {
183 self.entry_module()
184 .definitions()
185 .map(|(binding, _)| binding)
186 .find(|binding| self.bindings.get(*binding).name() == Self::WRITTEN_ENTRY_FUNCTION)
187 }
188}
189
190#[derive(Clone, serde::Serialize, serde::Deserialize)]
191pub struct TraitMethods {
192 pub rust_name: Rc<str>,
193 pub self_variable: crate::core::BindingId,
194 pub associated: Vec<(crate::core::BindingId, Rc<str>)>,
195 pub methods: Vec<(crate::core::BindingId, crate::core::TypeExpr)>,
196 pub defaults: rustc_hash::FxHashSet<crate::core::BindingId>,
197}
198
199pub struct Expander<'s> {
200 sources: &'s mut SourceMap,
201 module_sources: ModuleSources,
202 modules: ModuleRegistry,
203 tables: ExpansionTables,
204 current_module: Option<ModuleId>,
205 problems: ProblemReport,
206 reported_hidden_modules: Vec<std::path::PathBuf>,
207 library_modules: Vec<(ModulePath, Rc<str>)>,
208 phase: Phase,
209 expansion_depth: usize,
210 nesting_depth: usize,
211 form_budgets: BudgetArena,
212 recovered: RecoveredErrors,
213 type_note: TypeNote,
214 saved_prelude: Option<PreludeState>,
215 saved_definitions: SavedDefinitions,
216 saved_macros: SavedValues<Closure>,
217 saved_globals: SavedValues<Value>,
218 expansion: ExpansionWork,
219 evaluated_forms: EvaluatedForms,
220 recorded_inputs: RecordedInputs,
221 declared_definitions: Vec<failed_definition::DeclaredName>,
222 failed_body_definitions: Vec<BindingId>,
223 introductions: Vec<Scope>,
224 duplicate_definitions: DuplicateDefinitions,
225}
226
227#[derive(Default, serde::Serialize, serde::Deserialize)]
228struct ExpansionTables {
229 scopes: Scopes,
230 table: BindingTable,
231 bindings: BindingArena,
232 macros: MacroTable,
233 macro_origins: MacroOrigins,
234 global_macros: Vec<(crate::core::BindingId, Form)>,
235 trait_paths: FxHashMap<crate::core::BindingId, Rc<str>>,
236 structural_path_claims: StructuralPathClaims,
237 enum_variants: FxHashMap<crate::core::BindingId, Vec<crate::core::BindingId>>,
238 variant_fields: FxHashMap<crate::core::BindingId, Vec<Rc<str>>>,
239 trait_methods: FxHashMap<crate::core::BindingId, TraitMethods>,
240 globals: GlobalTable,
241 module_notes: ModuleNotes,
242 expanded: FxHashMap<ModuleId, CoreModule>,
243 order: Vec<ModuleId>,
244 string_view: Option<BindingId>,
245}
246
247impl ExpansionTables {
248 fn forget_locals(&mut self) {
249 let bindings = &self.bindings;
250 self.table
251 .forget(|binding| matches!(bindings.get(binding).kind(), BindingKind::Local));
252 }
253
254 fn find_string_view(&self) -> Option<BindingId> {
255 let modules = self
256 .order
257 .iter()
258 .filter_map(|id| self.expanded.get(id))
259 .filter(|module| ModuleSources::is_embedded_prelude(&module.path));
260 StringViewSearch::in_modules(modules)
261 }
262
263 fn save_definitions(&mut self) -> SavedTables {
264 let mut saver = DefinitionSaver::new(&self.bindings, self.string_view);
265 let modules = self.expanded.values_mut();
266 for module in modules.filter(|module| ModuleSources::is_embedded_prelude(&module.path)) {
267 saver.take_from(module);
268 }
269 saver.finish()
270 }
271
272 fn take_lowered_globals(&mut self) -> LoweredGlobals {
273 let definitions = self.expanded.values().flat_map(CoreModule::definitions);
274 self.globals.take_lowered(definitions)
275 }
276
277 fn restore_lowered_globals(&mut self, lowered: &LoweredGlobals) {
278 let definitions = self.expanded.values().flat_map(CoreModule::definitions);
279 self.globals.restore_lowered(lowered, definitions);
280 }
281}
282
283impl<'s> Expander<'s> {
284 pub fn new(sources: &'s mut SourceMap, module_sources: ModuleSources) -> Self {
285 Self {
286 sources,
287 module_sources,
288 modules: ModuleRegistry::default(),
289 tables: ExpansionTables::default(),
290 current_module: None,
291 problems: ProblemReport::default(),
292 reported_hidden_modules: Vec::new(),
293 library_modules: Vec::new(),
294 phase: Phase::Runtime,
295 expansion_depth: 0,
296 nesting_depth: 0,
297 form_budgets: BudgetArena::default(),
298 recovered: RecoveredErrors::default(),
299 type_note: TypeNote::default(),
300 saved_prelude: None,
301 saved_definitions: SavedDefinitions::default(),
302 saved_macros: SavedValues::default(),
303 saved_globals: SavedValues::default(),
304 expansion: ExpansionWork::default(),
305 evaluated_forms: EvaluatedForms::default(),
306 recorded_inputs: RecordedInputs::default(),
307 declared_definitions: Vec::new(),
308 failed_body_definitions: Vec::new(),
309 introductions: Vec::new(),
310 duplicate_definitions: DuplicateDefinitions::default(),
311 }
312 }
313
314 pub fn evaluating(self, spans: impl IntoIterator<Item = Span>) -> Self {
315 Self {
316 evaluated_forms: EvaluatedForms::new(spans),
317 ..self
318 }
319 }
320
321 #[cfg(test)]
322 pub(crate) fn take_diagnostics_with_code(
323 &mut self,
324 code: &crate::diagnostic::DiagnosticCode,
325 ) -> Vec<crate::diagnostic::Diagnostic> {
326 self.take_diagnostics()
327 .in_source_order()
328 .into_iter()
329 .filter(|diagnostic| diagnostic.code() == Some(code))
330 .cloned()
331 .collect()
332 }
333
334 pub fn with_prelude(
335 sources: &'s mut SourceMap,
336 module_sources: ModuleSources,
337 prelude: PreludeState,
338 ) -> Self {
339 Self {
340 saved_prelude: Some(prelude),
341 ..Self::new(sources, module_sources)
342 }
343 }
344
345 #[inline(never)]
346 pub fn expand(mut self, path: ModulePath, entry: SourceId) -> Result<Program, Diagnostics> {
347 let entry = self.load_source_module(path, &[entry]);
348 self.into_program(entry)
349 }
350
351 fn into_program(mut self, entry: ModuleId) -> Result<Program, Diagnostics> {
352 let diagnostics = self.take_diagnostics();
353 self.tables.macro_origins.forget_introduced_names();
354 let string_view = self
355 .tables
356 .string_view
357 .or_else(|| self.tables.find_string_view());
358 let mut program = Program {
359 modules: self.take_modules(),
360 entry,
361 entry_function: None,
362 bindings: self.tables.bindings,
363 macro_helpers: self.tables.globals.macro_helpers(),
364 string_view,
365 checked_roots: Vec::new(),
366 pending_definitions: PendingDefinitions::new(self.saved_definitions),
367 macro_origins: Rc::new(self.tables.macro_origins),
368 warnings: self.problems.take_warnings(),
369 expansion: self.expansion,
370 };
371 program.restore_reached();
372 program.entry_function = program.written_entry_function();
373 diagnostics.into_result(program)
374 }
375
376 fn take_diagnostics(&mut self) -> Diagnostics {
377 self.recovered.hand_over(&mut self.problems);
378 self.problems.take_errors()
379 }
380
381 fn structural_traits(&mut self) -> StructuralTraits<'_> {
382 StructuralTraits::new(
383 &self.tables.bindings,
384 &mut self.tables.structural_path_claims,
385 &mut self.problems,
386 )
387 }
388
389 fn check_documented_terms(&mut self, module: ModuleId, since: NotesCheckpoint) {
390 for undefined in self.documented_terms(module, since).undefined() {
391 self.problems.report(undefined);
392 }
393 }
394
395 fn documented_terms(
396 &mut self,
397 module: ModuleId,
398 since: NotesCheckpoint,
399 ) -> DocumentedTerms<'_> {
400 let noted = self.noted_terms(module, since);
401 DocumentedTerms::new(self.bindings(), &self.duplicate_definitions, noted)
402 }
403
404 fn bindings(&self) -> Bindings<'_> {
405 Bindings::new(&self.tables.table, &self.tables.bindings, self.phase)
406 }
407
408 fn noted_terms(&mut self, module: ModuleId, since: NotesCheckpoint) -> NotedTerms {
409 let is_prelude = ModuleSources::is_prelude(self.modules.get(module).path());
410 if is_prelude || self.tables.module_notes.checkpoint() == since {
411 return NotedTerms::new(module, Vec::new());
412 }
413 let Some(notes) = self.docstring_notes() else {
414 return NotedTerms::new(module, Vec::new());
415 };
416 let terms = notes
417 .keys()
418 .into_iter()
419 .flat_map(|key| self.tables.module_notes.added_since(since, module, key))
420 .collect::<Vec<Form>>()
421 .into_iter()
422 .filter_map(|note| self.noted_term(notes.noted_term(), note))
423 .collect();
424 NotedTerms::new(module, terms)
425 }
426
427 fn docstring_notes(&mut self) -> Option<DocstringNotes> {
428 let notes_module = NotesModule::new(&self.modules, self.bindings()).find()?;
429 let key = self.exported_value(notes_module, DocstringNotes::DOCSTRINGS_KEY)?;
430 let documented_terms_key =
431 self.exported_value(notes_module, DocstringNotes::DOCUMENTED_TERMS_KEY)?;
432 let noted_term = self.exported_value(notes_module, DocstringNotes::NOTED_TERM)?;
433 DocstringNotes::of(&key, &documented_terms_key, noted_term)
434 }
435
436 fn exported_value(&mut self, module: ModuleId, name: &str) -> Option<Value> {
437 let binding = self.modules.get(module).exported(name, Namespace::Value)?;
438 let span = self.tables.bindings.get(binding).span()?;
439 self.evaluate_global(binding, span).ok()
440 }
441
442 fn noted_term(&mut self, accessor: &Value, note: Form) -> Option<NotedTerm> {
443 let span = note.span();
444 let steps = self.form_budgets.current().steps();
445 let term = Interpreter::new(self, span, steps)
446 .call(accessor, vec![Value::Form(note)], span)
447 .ok()?;
448 let term = term.as_form()?;
449 Some(NotedTerm {
450 term: term.as_symbol()?.clone(),
451 span: term.span(),
452 })
453 }
454
455 fn take_modules(&mut self) -> Vec<CoreModule> {
456 self.tables
457 .order
458 .iter()
459 .filter_map(|id| self.tables.expanded.remove(id))
460 .collect()
461 }
462}