Add Term::Invalid for invalid readbacks

This commit is contained in:
LunaAmora 2024-02-05 12:53:27 -03:00
parent be707a17eb
commit 0bcabe93bc
25 changed files with 139 additions and 46 deletions

View File

@ -56,7 +56,12 @@ impl Term {
arm.encode_builtins();
}
}
Term::Var { .. } | Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Era => {}
Term::Var { .. }
| Term::Lnk { .. }
| Term::Ref { .. }
| Term::Num { .. }
| Term::Era
| Term::Invalid => {}
}
}

View File

@ -82,7 +82,8 @@ impl Term {
| Term::Ref { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
}
Ok(())
}

View File

@ -109,7 +109,7 @@ pub fn check_uses<'a>(
}
}
Term::List { .. } => unreachable!(),
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => (),
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Invalid => (),
}
Ok(())
}

View File

@ -78,6 +78,7 @@ impl Term {
Term::List { els } => {
write!(f, "[{}]", DisplayJoin(|| els.iter().map(|el| display!("{}", el.display(def_names))), ", "),)
}
Term::Invalid => write!(f, "<Invalid>"),
})
}
}
@ -252,6 +253,7 @@ impl ReadbackError {
pub fn display<'a>(&'a self, def_names: &'a DefNames) -> impl Display + '_ {
DisplayFn(move |f| match self {
ReadbackError::InvalidNumericMatch => write!(f, "Invalid Numeric Match"),
ReadbackError::InvalidNumericOp => write!(f, "Invalid Numeric Operation"),
ReadbackError::ReachedRoot => write!(f, "Reached Root"),
ReadbackError::Cyclic => write!(f, "Cyclic Term"),
ReadbackError::InvalidBind => write!(f, "Invalid Bind"),

View File

@ -153,6 +153,7 @@ pub enum Term {
},
#[default]
Era,
Invalid,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -450,7 +451,7 @@ impl Term {
fst.subst(from, to);
snd.subst(from, to);
}
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => (),
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Invalid => (),
}
}
@ -480,7 +481,8 @@ impl Term {
| Term::Ref { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
}
}
@ -551,7 +553,7 @@ impl Term {
free_vars.extend(fvs);
}
}
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => {}
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Invalid => {}
}
}
@ -593,7 +595,12 @@ impl Term {
Term::Lam { bod, .. } => {
go(bod, decls, uses);
}
Term::Var { .. } | Term::Num { .. } | Term::Str { .. } | Term::Ref { .. } | Term::Era => (),
Term::Var { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Invalid => (),
}
}
let mut decls = Default::default();
@ -622,23 +629,30 @@ impl Term {
let succ = (Pattern::Num(MatchNum::Succ(Some(succ_label))), succ_term);
Term::Match { scrutinee: Box::new(scrutinee), arms: vec![zero, succ] }
} else {
let match_bind = succ_label.clone().unwrap_or_else(|| Name::new("*"));
match succ_label {
Some(succ) => {
let match_bind = succ.clone();
if let Some(label) = &succ_label {
let new_label = Name(format!("{}-1", label));
succ_term.subst(label, &Term::Var { nam: new_label.clone() });
succ_label = Some(new_label);
}
let new_label = Name(format!("{}-1", succ));
succ_term.subst(&succ, &Term::Var { nam: new_label.clone() });
succ_label = Some(new_label);
let succ = (Pattern::Num(MatchNum::Succ(Some(succ_label))), succ_term);
let succ = (Pattern::Num(MatchNum::Succ(Some(succ_label))), succ_term);
Term::Let {
pat: Pattern::Var(Some(match_bind.clone())),
val: Box::new(scrutinee),
nxt: Box::new(Term::Match {
scrutinee: Box::new(Term::Var { nam: match_bind }),
arms: vec![zero, succ],
}),
Term::Let {
pat: Pattern::Var(Some(match_bind.clone())),
val: Box::new(scrutinee),
nxt: Box::new(Term::Match {
scrutinee: Box::new(Term::Var { nam: match_bind }),
arms: vec![zero, succ],
}),
}
}
None => {
let succ = (Pattern::Num(MatchNum::Succ(None)), succ_term);
Term::Match { scrutinee: Box::new(scrutinee), arms: vec![zero, succ] }
}
}
}
}

View File

@ -108,12 +108,19 @@ impl<'a> Reader<'a> {
let zero_term = self.read_term(self.net.enter_port(Port(sel_node, 1)));
let succ_term = self.read_term(self.net.enter_port(Port(sel_node, 2)));
let Term::Lam { nam, bod, .. } = succ_term else { unreachable!() };
Term::new_native_match(scrutinee, zero_term, nam, *bod)
match succ_term {
Term::Lam { nam, bod, .. } => Term::new_native_match(scrutinee, zero_term, nam, *bod),
_ => {
self.error(ReadbackError::InvalidNumericMatch);
Term::new_native_match(scrutinee, zero_term, None, succ_term)
}
}
}
}
_ => unreachable!(),
_ => {
self.error(ReadbackError::InvalidNumericMatch);
Term::Invalid
}
},
Ref { def_id } => {
if self.book.is_def_name_generated(def_id) {
@ -179,11 +186,14 @@ impl<'a> Reader<'a> {
Term::Opx { op: Op::from_hvmc_label(opr), fst: Box::new(fst), snd: Box::new(snd) }
}
_ => unreachable!(),
_ => {
self.error(ReadbackError::InvalidNumericOp);
Term::Invalid
}
},
Rot => {
self.error(ReadbackError::ReachedRoot);
Term::Era
Term::Invalid
}
Tup => match next.slot() {
// If we're visiting a port 0, then it is a Tup.
@ -302,7 +312,12 @@ impl Term {
n
}
Term::List { .. } => unreachable!(),
Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Ref { .. } | Term::Era => 0,
Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Invalid => 0,
};
if n >= threshold {
let Split { tag, fst, snd, val } = std::mem::take(split);
@ -370,7 +385,12 @@ impl Term {
}
}
Term::Let { .. } | Term::List { .. } => unreachable!(),
Term::Var { .. } | Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => {}
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era
| Term::Invalid => {}
}
}
}
@ -441,6 +461,7 @@ pub struct ReadbackErrors(pub Vec<ReadbackError>);
#[derive(Debug)]
pub enum ReadbackError {
InvalidNumericMatch,
InvalidNumericOp,
ReachedRoot,
Cyclic,
InvalidBind,
@ -454,6 +475,7 @@ impl ReadbackError {
pub fn can_count(&self) -> bool {
match self {
ReadbackError::InvalidNumericMatch => true,
ReadbackError::InvalidNumericOp => true,
ReadbackError::ReachedRoot => true,
ReadbackError::Cyclic => true,
ReadbackError::InvalidBind => true,

View File

@ -55,7 +55,8 @@ impl<'a> Reader<'a> {
| Term::Var { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era => {}
| Term::Era
| Term::Invalid => {}
}
}

View File

@ -290,6 +290,7 @@ impl<'a> EncodeTermState<'a> {
Some(Port(tup, 0))
}
Term::Invalid => unreachable!(),
}
}

View File

@ -126,7 +126,8 @@ impl Book {
| Term::Num { .. }
| Term::Str { .. }
| Term::List { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
}
}

View File

@ -77,7 +77,8 @@ impl Term {
| Term::Num { .. }
| Term::Str { .. }
| Term::Lnk { .. }
| Term::Var { .. } => (),
| Term::Var { .. }
| Term::Invalid => (),
Term::Let { pat: _, .. } => {
unreachable!("Expected destructor let expressions to have been desugared already")
}

View File

@ -37,7 +37,8 @@ impl Term {
| Term::Var { .. }
| Term::Lnk { .. }
| Term::Ref { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
Term::Let { .. } => {
let Term::Let { pat, mut val, mut nxt } = std::mem::take(self) else { unreachable!() };

View File

@ -150,7 +150,8 @@ impl Term {
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era => {}
| Term::Era
| Term::Invalid => {}
Term::List { .. } => unreachable!(),
Term::Match { .. } => unreachable!("Scrutinee of match expression should have been extracted already"),
@ -244,7 +245,8 @@ impl Term {
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
Term::List { .. } => unreachable!(),
}
Ok(())

View File

@ -275,7 +275,9 @@ impl Term {
}
Term::Ref { def_id } if *def_id == term_info.rule_id => Detach::Recursive,
Term::Let { .. } | Term::List { .. } => unreachable!(),
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => Detach::Combinator,
Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Invalid => {
Detach::Combinator
}
}
}

View File

@ -322,7 +322,8 @@ fn normal_order_step(term: &mut Term) -> bool {
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era => false,
| Term::Era
| Term::Invalid => false,
}
}
@ -397,6 +398,7 @@ fn subst_rule_body(term: &mut Term, subst_var: &Name, body: &Term, name_gen: &mu
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
}
}

View File

@ -66,7 +66,8 @@ impl Term {
| Term::Str { .. }
| Term::List { .. }
| Term::Ref { .. }
| Term::Era => {}
| Term::Era
| Term::Invalid => {}
}
}
}

View File

@ -81,7 +81,8 @@ fn count_var_uses_in_term(term: &Term, uses: &mut HashMap<Name, Val>) {
}
}
Term::List { .. } => unreachable!("Should have been desugared already"),
Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => (),
Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Invalid => {
}
}
}
@ -224,7 +225,8 @@ fn term_to_affine(
}
}
Term::List { .. } => unreachable!("Should have been desugared already"),
Term::Era | Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } => (),
Term::Era | Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Invalid => {
}
};
}

View File

@ -71,7 +71,8 @@ impl Term {
| Term::Num { .. }
| Term::Str { .. }
| Term::List { .. }
| Term::Era => (),
| Term::Era
| Term::Invalid => (),
}
}
}

View File

@ -94,7 +94,12 @@ impl Term {
}
}
Term::List { .. } => unreachable!("Should have been desugared already"),
Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => (),
Term::Lnk { .. }
| Term::Ref { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era
| Term::Invalid => (),
}
Ok(())
}

View File

@ -68,6 +68,8 @@ pub fn subst_ref_to_ref(term: &mut Term, ref_map: &BTreeMap<DefId, DefId>) -> bo
subst
}
Term::List { .. } => unreachable!("Should have been desugared already"),
Term::Var { .. } | Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => false,
Term::Var { .. } | Term::Lnk { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era | Term::Invalid => {
false
}
}
}

View File

@ -81,7 +81,12 @@ impl UniqueNameGenerator {
}
// Global lam names are already unique, so no need to do anything
Term::Chn { bod, .. } => self.unique_names_in_term(bod),
Term::Lnk { .. } | Term::Ref { .. } | Term::Era | Term::Num { .. } | Term::Str { .. } => (),
Term::Lnk { .. }
| Term::Ref { .. }
| Term::Era
| Term::Num { .. }
| Term::Str { .. }
| Term::Invalid => (),
Term::Let { .. } => {
unreachable!("Let terms other than tuple destruction should have been desugared already.")

View File

@ -0,0 +1,3 @@
(a b)
& (#1 (* #2)) ~ (c d)
& ?<(#3 (* #4)) ?<d b>> ~ ?<c a>

View File

@ -0,0 +1,3 @@
(a b)
& #1 ~ (c d)
& <+ #1 <+ d b>> ~ <+ c a>

View File

@ -4,4 +4,4 @@ input_file: tests/golden_tests/readback_lnet/bad_net.hvm
---
Readback Warning:
Reached Root
*
<Invalid>

View File

@ -0,0 +1,8 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/readback_lnet/invalid_mat_mat.hvm
---
Readback Warning:
Invalid Numeric Match with 4 occurrences
λa match match <Invalid> { 0: 3; +: 4 } { 0: <Invalid>; +: <Invalid> }

View File

@ -0,0 +1,8 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/readback_lnet/invalid_op2_op2.hvm
---
Readback Warning:
Invalid Op2 with 2 occurrences
λa (+ (+ <Invalid> 1) (1 <Invalid>))