Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sc 453] don t stack overflow on very large terms #215

Merged
merged 7 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ indexmap = "2.2.3"
interner = "0.2.1"
itertools = "0.11.0"
logos = "0.14.0"
stacker = "0.1"

[dev-dependencies]
insta = "1.34.0"
stdext = "0.3.1"
walkdir = "2.3.3"

[profile.test]
opt-level = 2
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub fn create_host(book: Arc<Book>, labels: Arc<Labels>, compile_opts: CompileOp
term.resugar_builtins();

readback_errors.extend(resugar_errs);
if let Term::Str { val } = term {
if let Term::Str { ref val } = term {
println!("{val}");
}
}
Expand Down
74 changes: 38 additions & 36 deletions src/term/check/ctrs_arities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,46 +75,48 @@ impl Pattern {

impl Term {
pub fn check_ctrs_arities(&self, arities: &HashMap<Name, usize>) -> Result<(), MatchErr> {
match self {
Term::Mat { args, rules } => {
for arg in args {
arg.check_ctrs_arities(arities)?;
}
for rule in rules {
for pat in &rule.pats {
pat.check_ctrs_arities(arities)?;
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || {
match self {
Term::Mat { args, rules } => {
for arg in args {
arg.check_ctrs_arities(arities)?;
}
for rule in rules {
for pat in &rule.pats {
pat.check_ctrs_arities(arities)?;
}
rule.body.check_ctrs_arities(arities)?;
}
rule.body.check_ctrs_arities(arities)?;
}
}
Term::Let { pat, val, nxt } => {
pat.check_ctrs_arities(arities)?;
val.check_ctrs_arities(arities)?;
nxt.check_ctrs_arities(arities)?;
}
Term::Let { pat, val, nxt } => {
pat.check_ctrs_arities(arities)?;
val.check_ctrs_arities(arities)?;
nxt.check_ctrs_arities(arities)?;
}

Term::Lst { els } => {
for el in els {
el.check_ctrs_arities(arities)?;
Term::Lst { els } => {
for el in els {
el.check_ctrs_arities(arities)?;
}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. } => {
fst.check_ctrs_arities(arities)?;
snd.check_ctrs_arities(arities)?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_ctrs_arities(arities)?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Err => {}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. } => {
fst.check_ctrs_arities(arities)?;
snd.check_ctrs_arities(arities)?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_ctrs_arities(arities)?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Err => {}
}
Ok(())
Ok(())
})
}
}
64 changes: 33 additions & 31 deletions src/term/check/match_arity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,43 @@ impl Definition {

impl Term {
pub fn check_match_arity(&self) -> Result<(), MatchErr> {
match self {
Term::Mat { args, rules } => {
let expected = args.len();
for rule in rules {
let found = rule.pats.len();
if found != expected {
return Err(MatchErr::ArityMismatch(found, expected));
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || {
match self {
Term::Mat { args, rules } => {
let expected = args.len();
for rule in rules {
let found = rule.pats.len();
if found != expected {
return Err(MatchErr::ArityMismatch(found, expected));
}
rule.body.check_match_arity()?;
}
rule.body.check_match_arity()?;
}
}

Term::Lst { els } => {
for el in els {
el.check_match_arity()?;
Term::Lst { els } => {
for el in els {
el.check_match_arity()?;
}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. }
| Term::Let { val: fst, nxt: snd, .. } => {
fst.check_match_arity()?;
snd.check_match_arity()?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_match_arity()?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Err => {}
}
Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. }
| Term::Let { val: fst, nxt: snd, .. } => {
fst.check_match_arity()?;
snd.check_match_arity()?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_match_arity()?,
Term::Var { .. }
| Term::Lnk { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Ref { .. }
| Term::Era
| Term::Err => {}
}
Ok(())
Ok(())
})
}
}
66 changes: 34 additions & 32 deletions src/term/check/unbound_pats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,41 +67,43 @@ impl Pattern {

impl Term {
pub fn check_unbound_pats(&self, is_ctr: &impl Fn(&Name) -> bool) -> Result<(), UnboundCtrErr> {
match self {
Term::Let { pat, val, nxt } => {
pat.check_unbounds(is_ctr)?;
val.check_unbound_pats(is_ctr)?;
nxt.check_unbound_pats(is_ctr)?;
}
Term::Mat { args, rules } => {
for arg in args {
arg.check_unbound_pats(is_ctr)?;
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || {
match self {
Term::Let { pat, val, nxt } => {
pat.check_unbounds(is_ctr)?;
val.check_unbound_pats(is_ctr)?;
nxt.check_unbound_pats(is_ctr)?;
}
for rule in rules {
for pat in &rule.pats {
pat.check_unbounds(is_ctr)?;
Term::Mat { args, rules } => {
for arg in args {
arg.check_unbound_pats(is_ctr)?;
}
for rule in rules {
for pat in &rule.pats {
pat.check_unbounds(is_ctr)?;
}
rule.body.check_unbound_pats(is_ctr)?;
}
rule.body.check_unbound_pats(is_ctr)?;
}
Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. } => {
fst.check_unbound_pats(is_ctr)?;
snd.check_unbound_pats(is_ctr)?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_unbound_pats(is_ctr)?,
Term::Lst { .. } => unreachable!(),
Term::Var { .. }
| Term::Lnk { .. }
| Term::Ref { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era
| Term::Err => (),
}
Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. } => {
fst.check_unbound_pats(is_ctr)?;
snd.check_unbound_pats(is_ctr)?;
}
Term::Lam { bod, .. } | Term::Chn { bod, .. } => bod.check_unbound_pats(is_ctr)?,
Term::Lst { .. } => unreachable!(),
Term::Var { .. }
| Term::Lnk { .. }
| Term::Ref { .. }
| Term::Num { .. }
| Term::Str { .. }
| Term::Era
| Term::Err => (),
}
Ok(())
Ok(())
})
}
}
77 changes: 76 additions & 1 deletion src/term/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub struct Rule {
pub body: Term,
}

#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
#[derive(Debug, Default, PartialEq, Eq, Hash)]
pub enum Term {
Lam {
tag: Tag,
Expand Down Expand Up @@ -140,6 +140,81 @@ pub enum Term {
Err,
}

impl Clone for Term {
fn clone(&self) -> Self {
stacker::maybe_grow(1024 * 32, 1024 * 1024, move || match self {
Self::Lam { tag, nam, bod } => Self::Lam { tag: tag.clone(), nam: nam.clone(), bod: bod.clone() },
Self::Var { nam } => Self::Var { nam: nam.clone() },
Self::Chn { tag, nam, bod } => Self::Chn { tag: tag.clone(), nam: nam.clone(), bod: bod.clone() },
Self::Lnk { nam } => Self::Lnk { nam: nam.clone() },
Self::Let { pat, val, nxt } => Self::Let { pat: pat.clone(), val: val.clone(), nxt: nxt.clone() },
Self::App { tag, fun, arg } => Self::App { tag: tag.clone(), fun: fun.clone(), arg: arg.clone() },
Self::Tup { fst, snd } => Self::Tup { fst: fst.clone(), snd: snd.clone() },
Self::Dup { tag, fst, snd, val, nxt } => {
Self::Dup { tag: tag.clone(), fst: fst.clone(), snd: snd.clone(), val: val.clone(), nxt: nxt.clone() }
}
Self::Sup { tag, fst, snd } => Self::Sup { tag: tag.clone(), fst: fst.clone(), snd: snd.clone() },
Self::Num { val } => Self::Num { val: val.clone() },
Self::Str { val } => Self::Str { val: val.clone() },
Self::Lst { els } => Self::Lst { els: els.clone() },
Self::Opx { op, fst, snd } => Self::Opx { op: op.clone(), fst: fst.clone(), snd: snd.clone() },
Self::Mat { args, rules } => Self::Mat { args: args.clone(), rules: rules.clone() },
Self::Ref { nam } => Self::Ref { nam: nam.clone() },
Self::Era => Self::Era,
Self::Err => Self::Err,
})
}
}

impl Drop for Term {
fn drop(&mut self) {
if matches!(self, Term::Era | Term::Err) {
return;
}

let mut stack = vec![];
self.take_children(&mut stack);

while let Some(mut term) = stack.pop() {
term.take_children(&mut stack)
}
}
}

impl Term {
fn take_children(&mut self, stack: &mut Vec<Term>) {
match self {
Term::Lam { bod, .. } | Term::Chn { bod, .. } => {
stack.push(std::mem::take(bod.as_mut()));
}
Term::Let { val: fst, nxt: snd, .. }
| Term::App { fun: fst, arg: snd, .. }
| Term::Tup { fst, snd }
| Term::Dup { val: fst, nxt: snd, .. }
| Term::Sup { fst, snd, .. }
| Term::Opx { fst, snd, .. } => {
stack.push(std::mem::take(fst.as_mut()));
stack.push(std::mem::take(snd.as_mut()));
}
Term::Mat { args, rules } => {
for arg in std::mem::take(args).into_iter() {
stack.push(arg);
}

for Rule { body, .. } in std::mem::take(rules).into_iter() {
stack.push(body);
}
}
Term::Lst { els } => {
for el in std::mem::take(els).into_iter() {
stack.push(el);
}
}
_ => {}
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Pattern {
Var(Option<Name>),
Expand Down
Loading
Loading