lex_store/merge_checker.rs
1//! Store-backed [`lex_vcs::ResolutionChecker`] (#834).
2//!
3//! `lex-vcs`'s [`MergeSession`](lex_vcs::MergeSession) knows the *shape*
4//! of a merge — which sig resolves to which stage — but can't compose a
5//! program from stage ids: it has no `lex-store` dependency, by design.
6//! This adapter closes that gap. Constructed with the store and the dst
7//! branch of a merge in flight, it answers "does this resolution's
8//! projected program type-check?" by delegating to
9//! [`Store::typecheck_merge_projection`], which overlays the projected
10//! delta on dst's head and runs the type checker without moving the
11//! head.
12//!
13//! Wire it into `resolve_checked`:
14//! ```ignore
15//! let checker = MergeResolutionChecker::new(&store, dst_branch);
16//! let verdicts = session.resolve_checked(pairs, &checker);
17//! ```
18
19use std::collections::BTreeMap;
20
21use crate::store::Store;
22
23/// Adapter turning a [`Store`] + dst branch into a
24/// [`lex_vcs::ResolutionChecker`] for one merge session.
25pub struct MergeResolutionChecker<'a> {
26 store: &'a Store,
27 dst_branch: String,
28}
29
30impl<'a> MergeResolutionChecker<'a> {
31 /// `dst_branch` is the branch the merge lands on — the same branch
32 /// whose head the projection is overlaid upon. It must not have
33 /// moved since the session started (merges are held open in
34 /// process memory; the branch head only advances at commit).
35 pub fn new(store: &'a Store, dst_branch: impl Into<String>) -> Self {
36 Self { store, dst_branch: dst_branch.into() }
37 }
38}
39
40impl lex_vcs::ResolutionChecker for MergeResolutionChecker<'_> {
41 fn typecheck_projection(&self, delta: &BTreeMap<String, Option<String>>) -> Vec<String> {
42 match self.store.typecheck_merge_projection(&self.dst_branch, delta) {
43 Ok(()) => Vec::new(),
44 Err(crate::StoreError::TypeError(errors)) => {
45 errors.iter().map(|e| e.to_string()).collect()
46 }
47 // A read/IO failure isn't a type error, but the session's
48 // Vec<String> channel can't distinguish them — surface it as
49 // a single diagnostic so the resolution is rejected loudly
50 // rather than silently accepted.
51 Err(other) => vec![format!("merge projection check failed: {other}")],
52 }
53 }
54}