diff --git a/CHANGELOG.md b/CHANGELOG.md index edce6c01..824d2108 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project does not currently adhere to a particular versioning scheme. - Improve error messages for redefinition of types and objects. ([#485][gh-485]) - Don't allow tabs to be used for indentation or spacing. ([#463][gh-463]) - Rename builtin function `sleep` to `IO/nanosleep`. ([#581][gh-581]) +- Equational number pattern compilation to use the predecessor variable when possible. ([#470][gh-470]) ### Fixed @@ -333,6 +334,7 @@ and this project does not currently adhere to a particular versioning scheme. [gh-465]: https://github.com/HigherOrderCO/Bend/issues/465 [gh-466]: https://github.com/HigherOrderCO/Bend/issues/466 [gh-467]: https://github.com/HigherOrderCO/Bend/issues/467 +[gh-470]: https://github.com/HigherOrderCO/Bend/issues/470 [gh-475]: https://github.com/HigherOrderCO/Bend/issues/475 [gh-478]: https://github.com/HigherOrderCO/Bend/issues/478 [gh-479]: https://github.com/HigherOrderCO/Bend/issues/479 diff --git a/src/fun/transform/desugar_match_defs.rs b/src/fun/transform/desugar_match_defs.rs index 26d5db1f..4b79144c 100644 --- a/src/fun/transform/desugar_match_defs.rs +++ b/src/fun/transform/desugar_match_defs.rs @@ -1,6 +1,7 @@ use crate::{ diagnostics::{Diagnostics, WarningType}, fun::{builtins, Adts, Constructors, Ctx, Definition, FanKind, Name, Num, Pattern, Rule, Tag, Term}, + maybe_grow, }; use std::collections::{BTreeSet, HashSet}; @@ -301,8 +302,10 @@ fn num_rule( let mut body = rule.body.clone(); if let Some(var) = var { let last_num = *nums.last().unwrap(); - let var_recovered = Term::add_num(Term::Var { nam: pred_var.clone() }, Num::U24(1 + last_num)); + let curr_num = 1 + last_num; + let var_recovered = Term::add_num(Term::Var { nam: pred_var.clone() }, Num::U24(curr_num)); body = Term::Use { nam: Some(var.clone()), val: Box::new(var_recovered), nxt: Box::new(body) }; + fast_pred_access(&mut body, curr_num, var, &pred_var); } let rule = Rule { pats: rule.pats[1..].to_vec(), body }; new_rules.push(rule); @@ -340,6 +343,25 @@ fn num_rule( Ok(term) } +/// Replaces `body` to `pred_var` if the term is a operation that subtracts the given var by the current +/// switch number. +fn fast_pred_access(body: &mut Term, curr_num: u32, var: &Name, pred_var: &Name) { + maybe_grow(|| { + if let Term::Oper { opr: crate::fun::Op::SUB, fst, snd } = body { + if let Term::Num { val: crate::fun::Num::U24(val) } = &**snd { + if let Term::Var { nam } = &**fst { + if nam == var && *val == curr_num { + *body = Term::Var { nam: pred_var.clone() }; + } + } + } + } + for child in body.children_mut() { + fast_pred_access(child, curr_num, var, pred_var) + } + }) +} + /// When the first column has constructors, create a branch on the constructors /// of the first arg. /// diff --git a/tests/snapshots/encode_pattern_match__match_num_pred.bend.snap b/tests/snapshots/encode_pattern_match__match_num_pred.bend.snap index 93d32c98..a3125d79 100644 --- a/tests/snapshots/encode_pattern_match__match_num_pred.bend.snap +++ b/tests/snapshots/encode_pattern_match__match_num_pred.bend.snap @@ -7,7 +7,7 @@ Scott (pred2) = λa switch a { 0: 0; _: λb switch b { 0: 0; _: λc c; }; } -(pred3) = λa switch a { 0: 0; _: λb switch b { 0: 0; _: λc switch c { 0: 0; _: λd (- (+ d 3) 3); }; }; } +(pred3) = λa switch a { 0: 0; _: λb switch b { 0: 0; _: λc switch c { 0: 0; _: λd d; }; }; } (zero) = λa switch a { 0: 1; _: λb switch b { 0: 0; _: λ* 0; }; } @@ -18,7 +18,7 @@ NumScott (pred2) = λa switch a { 0: 0; _: λb switch b { 0: 0; _: λc c; }; } -(pred3) = λa switch a { 0: 0; _: λb switch b { 0: 0; _: λc switch c { 0: 0; _: λd (- (+ d 3) 3); }; }; } +(pred3) = λa switch a { 0: 0; _: λb switch b { 0: 0; _: λc switch c { 0: 0; _: λd d; }; }; } (zero) = λa switch a { 0: 1; _: λb switch b { 0: 0; _: λ* 0; }; }