Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
yannham committed Jan 7, 2025
1 parent f9560b3 commit ff8c28f
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions core/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<CacheOp<()>, CacheError<TypecheckError>> {
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<'_>, 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
Expand Down

0 comments on commit ff8c28f

Please sign in to comment.