From ff8c28fe79218e7f8bb9a6cef32170d7747e3a34 Mon Sep 17 00:00:00 2001 From: Yann Hamdaoui Date: Tue, 7 Jan 2025 15:06:25 +0100 Subject: [PATCH] WIP --- core/src/cache.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/core/src/cache.rs b/core/src/cache.rs index 6638bb54f..ecd874b8a 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -2828,6 +2828,86 @@ mod ast_cache { Ok(CacheOp::Done(())) } + + /// Typecheck the stdlib, provided the initial typing environment. Has to be public because + /// it's used in benches. It probably does not have to be used for something else. + pub fn typecheck_stdlib_in_ctxt<'ast>( + &'ast mut self, + sources: &mut SourceCache, + wildcards: &mut WildcardsCache, + terms: &mut TermCache, + import_data: &mut ImportData, + initial_ctxt: &typecheck::Context<'ast>, + ) -> Result, CacheError> { + let mut ret = CacheOp::Cached(()); + + for (_, stdlib_module_id) in sources.files.stdlib_modules() { + // The content of each iteration is exactly the same as `self.typecheck` applied to + // `stdlib_module_id`, but we can't factorize it because of the borrow checker. Due + // to lifetime inference intricacies, calling `self.typecheck` here doesn't work - + // we couldn't find a better and safe way to solve this than to duplicate the code. + + // If the term cache is populated, given the current split of the pipeline between the old + // and the new AST, the term MUST have been typechecked. + if terms.terms.get(&stdlib_module_id).is_some() { + return Ok(CacheOp::Cached(())); + } + + let Some((ast, _errs)) = self.asts.get(&stdlib_module_id) else { + return Err(CacheError::NotParsed); + }; + + let resolver = resolvers::AstResolver { + alloc: &self.alloc, + asts: &self.asts, + new_asts: Vec::new(), + import_data, + sources, + }; + + let wildcards_map = measure_runtime!( + "runtime:type_check", + typecheck( + &self.alloc, + &ast, + initial_ctxt.clone(), + &resolver, + TypecheckMode::Walk + )? + ); + + self.asts + .extend(resolver.new_asts.into_iter().map(|(id, ast)| { + ( + id, + ( + // Safety: the implementation of AstResolver can only allocate new ASTs from + // `self.alloc` (or via leaked data), which thus are guaranteed to be live as long as + // `self`. As explained in the documentation of [Self], `'static` is just a non + // observable placeholder here. What counts is that the asts in the cache live as long + // as self. + unsafe { std::mem::transmute::, Ast<'static>>(ast) }, + ParseErrors::default(), + ), + ) + })); + + wildcards.wildcards.insert( + stdlib_module_id, + wildcards_map.iter().map(ToMainline::to_mainline).collect(), + ); + + // We can't use `update_state()` here because `self.asts.get_alloc()` must be live for the + // whole duration of the function (`'ast`) to match the provided typing context, which + // would conflict with borrowing `self` mutably. However, we can modify `terms` directly, + // as the compiler is able to see that we borrow a disjoint field. + terms.update_state(stdlib_module_id, EntryState::Typechecked); + + ret = CacheOp::Done(()); + } + + Ok(ret) + } } /// [AstCache] can't realistically and safely be cloned (especially since the pointers in the