···8888use ecow::EcoString;
8989use id_arena::{Arena, Id};
9090use itertools::Itertools;
9191+use radix_trie::{Trie, TrieCommon};
9192use std::{
9293 cell::RefCell,
9394 collections::{HashMap, HashSet, VecDeque},
···302303 },
303304 StringPrefix {
304305 prefix: EcoString,
305305- rest: Id<Pattern>,
306306+ rest_pattern: Id<Pattern>,
306307 },
307308 Assign {
308309 name: EcoString,
···312313 name: EcoString,
313314 },
314315 Tuple {
315315- elements: Vec<Id<Pattern>>,
316316+ elems_patterns: Vec<Id<Pattern>>,
316317 },
317317- Constructor {
318318- variant_index: usize,
319319- arguments: Vec<Id<Pattern>>,
318318+ Variant {
319319+ index: usize,
320320+ args_patterns: Vec<Id<Pattern>>,
320321 },
321322 List {
322322- first: Id<Pattern>,
323323- rest: Id<Pattern>,
323323+ first_pattern: Id<Pattern>,
324324+ rest_pattern: Id<Pattern>,
324325 },
325326 EmptyList,
326327 // TODO: Compile the matching within the bit strings
···329330 },
330331}
331332333333+impl Pattern {
334334+ /// Each pattern (with a couple exceptions) can be turned into a
335335+ /// simpler `RuntimeCheck`: that is a check that can be performed at runtime
336336+ /// to make sure a `PatternCheck` can succeed on a specific value.
337337+ ///
338338+ fn to_runtime_check_kind(&self) -> Option<RuntimeCheckKind> {
339339+ let kind = match self {
340340+ // These patterns are unconditional: they will always match and be moved
341341+ // out of a branch's checks. So there's no corresponding runtime check
342342+ // we can perform for them.
343343+ Pattern::Discard | Pattern::Variable { .. } | Pattern::Assign { .. } => return None,
344344+ Pattern::Int { value } => RuntimeCheckKind::Int {
345345+ value: value.clone(),
346346+ },
347347+ Pattern::Float { value } => RuntimeCheckKind::Float {
348348+ value: value.clone(),
349349+ },
350350+ Pattern::String { value } => RuntimeCheckKind::String {
351351+ value: value.clone(),
352352+ },
353353+ Pattern::StringPrefix { prefix, .. } => RuntimeCheckKind::StringPrefix {
354354+ prefix: prefix.clone(),
355355+ },
356356+ Pattern::Tuple { elems_patterns } => RuntimeCheckKind::Tuple {
357357+ size: elems_patterns.len(),
358358+ },
359359+ Pattern::Variant { index, .. } => RuntimeCheckKind::Variant { index: *index },
360360+ Pattern::BitArray { value } => RuntimeCheckKind::BitArray {
361361+ value: value.clone(),
362362+ },
363363+ Pattern::List { .. } => RuntimeCheckKind::NonEmptyList,
364364+ Pattern::EmptyList => RuntimeCheckKind::EmptyList,
365365+ };
366366+367367+ Some(kind)
368368+ }
369369+370370+ fn is_matching_on_unreachable_variant(&self, branch_mode: &BranchMode) -> bool {
371371+ match (self, branch_mode) {
372372+ (
373373+ Self::Variant { index, .. },
374374+ BranchMode::NamedType {
375375+ inferred_variant: Some(variant),
376376+ ..
377377+ },
378378+ ) if index != variant => true,
379379+ _ => false,
380380+ }
381381+ }
382382+}
383383+332384/// A single check making up a branch, checking that a variable matches with a
333385/// given pattern. For example, the following branch has 2 checks:
334386///
···347399 pattern: Id<Pattern>,
348400}
349401350350-impl PatternCheck {
351351- fn new(var: Variable, pattern: Id<Pattern>) -> Self {
352352- Self { var, pattern }
353353- }
354354-355355- /// Each pattern check (with a couple exceptions) can be turned into a
356356- /// simpler `RuntimeCheck`: that is a check that can be performed at runtime
357357- /// to make sure the `PatternCheck` can succeed on a specific value.
358358- ///
359359- fn to_runtime_check_kind(&self, compiler: &Compiler<'_>) -> Option<RuntimeCheckKind> {
360360- let kind = match compiler.pattern(self.pattern) {
361361- // These patterns are unconditional: they will always match and be moved
362362- // out of a branch's checks. So there's no corresponding runtime check
363363- // we can perform for them.
364364- Pattern::Discard | Pattern::Variable { .. } | Pattern::Assign { .. } => return None,
365365- Pattern::Int { value } => {
366366- let value = value.clone();
367367- RuntimeCheckKind::Int { value }
368368- }
369369- Pattern::Float { value } => {
370370- let value = value.clone();
371371- RuntimeCheckKind::Float { value }
372372- }
373373- Pattern::String { value } => {
374374- let value = value.clone();
375375- RuntimeCheckKind::String { value }
376376- }
377377- Pattern::StringPrefix { prefix, .. } => {
378378- let prefix = prefix.clone();
379379- RuntimeCheckKind::StringPrefix { prefix }
380380- }
381381- Pattern::Tuple { elements } => {
382382- let size = elements.len();
383383- RuntimeCheckKind::Tuple { size }
384384- }
385385- Pattern::Constructor { variant_index, .. } => {
386386- let index = *variant_index;
387387- RuntimeCheckKind::Variant { index }
388388- }
389389- Pattern::BitArray { value } => {
390390- let value = value.clone();
391391- RuntimeCheckKind::BitArray { value }
392392- }
393393- Pattern::List { .. } => RuntimeCheckKind::NonEmptyList,
394394- Pattern::EmptyList => RuntimeCheckKind::EmptyList,
395395- };
396396-397397- Some(kind)
398398- }
399399-}
400400-401402/// This is one of the checks we can take at runtime to decide how to move
402403/// forward in the decision tree.
403404///
···441442 args: Vec<Variable>,
442443 },
443444 EmptyList,
444444- NonEmptyList {
445445+ List {
445446 first_arg: Variable,
446447 rest_arg: Variable,
447448 },
···471472 },
472473 RuntimeCheck::Variant { index, args: _ } => RuntimeCheckKind::Variant { index: *index },
473474 RuntimeCheck::EmptyList => RuntimeCheckKind::EmptyList,
474474- RuntimeCheck::NonEmptyList {
475475+ RuntimeCheck::List {
475476 first_arg: _,
476477 rest_arg: _,
477478 } => RuntimeCheckKind::NonEmptyList,
···492493 NonEmptyList,
493494}
494495495495-impl RuntimeCheckKind {
496496- fn is_matching_on_unreachable_variant(&self, branch_mode: &BranchMode) -> bool {
497497- match (self, branch_mode) {
498498- (
499499- Self::Variant { index },
500500- BranchMode::NamedType {
501501- inferred_variant: Some(variant),
502502- ..
503503- },
504504- ) if index != variant => true,
505505- _ => false,
506506- }
507507- }
508508-}
509509-510496/// A variable that can be matched on in a branch.
511497///
512498#[derive(Eq, PartialEq, Clone, Debug)]
···519505 fn new(id: usize, type_: Arc<Type>) -> Self {
520506 Self { id, type_ }
521507 }
508508+509509+ fn is(&self, pattern: Id<Pattern>) -> PatternCheck {
510510+ PatternCheck {
511511+ var: self.clone(),
512512+ pattern,
513513+ }
514514+ }
522515}
523516524517#[derive(Debug)]
···955948 continue;
956949 };
957950958958- // If it does check the same variable, we know that this branch is only relevant
959959- // for some specific shape of `pivot_var`, determined by the runtime check that
960960- // it is performing.
961961- let kind = pattern_check
962962- .to_runtime_check_kind(self)
963963- .expect("no var patterns left");
964964-965965- if kind.is_matching_on_unreachable_variant(branch_mode) {
951951+ let checked_pattern = self.pattern(pattern_check.pattern).clone();
952952+ if checked_pattern.is_matching_on_unreachable_variant(branch_mode) {
966953 self.mark_as_matching_impossible_variant(&branch);
967954 continue;
968955 }
969956970970- // We now replace the pattern check we've just removed with the new
971971- // ones we might have discovered.
972972- //
973973- // If a check is already there we don't generate a new one with
974974- // fresh variables, but reuse the existing one!
975975- //
976976- // TODO)) this might have to be slightly updated once we perform
977977- // code generation for string patterns that are a bit trickier to split
978978- // as they might be overlapping even when they're different!
979979- let runtime_check = match splitter.get_overlapping_runtime_check(&kind) {
980980- Some(runtime_check) => runtime_check,
981981- None => self.kind_to_runtime_check(kind, branch_mode),
982982- };
983983-984984- self.new_pattern_checks(&runtime_check, pattern_check.pattern)
985985- .into_iter()
986986- .for_each(|check| branch.add_check(check));
987987-988988- splitter.add_checked_branch(runtime_check, branch);
989989- }
990990- }
991991-992992- /// Comes up with new checks to perform after the given runtime check succeeds for
993993- /// the given pattern being matched.
994994- ///
995995- /// This is a tricky part, so let's have a look at an example: let's say this is
996996- /// the pattern check `a is Wibble(1, _, [])`.
997997- /// After making the runtime check that `a` is indeed a `Wibble` we're still
998998- /// left with many things to consider! We'll need to also make sure that `a`'s
999999- /// fields match with the respective patterns `1`, `_` and `[]`.
10001000- /// So we would have to add new pattern checks to this branch:
10011001- /// `a_0 is 1`, `a_1 is _` and `a_2 is []` (where `a_n` are fresh names we use
10021002- /// to refer to `a`'s fields).
10031003- ///
10041004- fn new_pattern_checks(
10051005- &mut self,
10061006- runtime_check: &RuntimeCheck,
10071007- pattern: Id<Pattern>,
10081008- ) -> Vec<PatternCheck> {
10091009- match (runtime_check, self.pattern(pattern)) {
10101010- // None of these patterns introduces new arguments we need to be matching on!
10111011- (
10121012- RuntimeCheck::Int { .. }
10131013- | RuntimeCheck::Float { .. }
10141014- | RuntimeCheck::String { .. }
10151015- | RuntimeCheck::BitArray { .. }
10161016- | RuntimeCheck::EmptyList,
10171017- _,
10181018- ) => vec![],
10191019-10201020- // A check on a string prefix introduces just a single new pattern: that is
10211021- // the one on the remaining bit.
10221022- (RuntimeCheck::StringPrefix { rest_arg, .. }, Pattern::StringPrefix { rest, .. }) => {
10231023- vec![PatternCheck::new(rest_arg.clone(), *rest)]
10241024- }
10251025- (RuntimeCheck::StringPrefix { .. }, _) => vec![],
10261026-10271027- // A check on a tuple introduces a new pattern for each of the elements making
10281028- // up the tuple. The same goes for variants, we have to introduce a new check
10291029- // for each of its fields, as shown in the doc comment above.
10301030- (RuntimeCheck::Tuple { args, .. }, Pattern::Tuple { elements: ps })
10311031- | (RuntimeCheck::Variant { args, .. }, Pattern::Constructor { arguments: ps, .. }) => {
10321032- (args.iter().zip(ps))
10331033- .map(|(arg, pattern)| PatternCheck::new(arg.clone(), *pattern))
10341034- .collect_vec()
10351035- }
10361036- (RuntimeCheck::Tuple { .. } | RuntimeCheck::Variant { .. }, _) => vec![],
10371037-10381038- // A check on a non empty list introduces two new patterns: one for the head of
10391039- // the list and one for the tail!
10401040- (
10411041- RuntimeCheck::NonEmptyList {
10421042- first_arg,
10431043- rest_arg,
10441044- },
10451045- Pattern::List { first, rest },
10461046- ) => vec![
10471047- PatternCheck::new(first_arg.clone(), *first),
10481048- PatternCheck::new(rest_arg.clone(), *rest),
10491049- ],
10501050- (RuntimeCheck::NonEmptyList { .. }, _) => vec![],
957957+ splitter.add_checked_branch(checked_pattern, branch, branch_mode, self);
1051958 }
1052959 }
105396010541054- /// Turns a `RuntimeCheckKind` into a proper `RuntimeCheck` by coming up with
961961+ /// Turns a `RuntimeCheckKind` into a new `RuntimeCheck` by coming up with
1055962 /// the needed new fresh variables.
1056963 /// All the type information needed to create these variables is in the
1057964 /// `branch_mode` arg.
1058965 ///
10591059- fn kind_to_runtime_check(
966966+ fn fresh_runtime_check(
1060967 &mut self,
1061968 kind: RuntimeCheckKind,
1062969 branch_mode: &BranchMode,
···10951002 }
10961003 }
1097100410051005+ /// Comes up with new pattern cecks that have to match in case a given
10061006+ /// runtime check succeeds for the given pattern.
10071007+ ///
10081008+ /// Let's make an example: when we have a pattern - say `a is Wibble(1, [])` -
10091009+ /// we come up with a runtime check to perform on it. For our example the
10101010+ /// runtime check is to make sure that `a` is indeed a `Wibble` variant.
10111011+ /// However, after successfully performing that check we're left with much to
10121012+ /// do! We know that `a` is `Wibble` but now we'll have to make sure that its
10131013+ /// inner arguments also match the given patterns. So the new additional checks
10141014+ /// we have to add are `a0 is 1, a1 is []` (where `a0` and `a1` are the fresh
10151015+ /// variable names we use to refer to the constructor's arguments).
10161016+ ///
10171017+ fn new_checks(
10181018+ &mut self,
10191019+ for_pattern: &Pattern,
10201020+ after_succeding_check: &RuntimeCheck,
10211021+ ) -> Vec<PatternCheck> {
10221022+ match (for_pattern, after_succeding_check) {
10231023+ // These patterns never result in adding new checks. After a runtime
10241024+ // check matches on them there's nothing else to discover.
10251025+ (
10261026+ Pattern::Discard
10271027+ | Pattern::Assign { .. }
10281028+ | Pattern::Variable { .. }
10291029+ | Pattern::Int { .. }
10301030+ | Pattern::Float { .. }
10311031+ | Pattern::BitArray { .. }
10321032+ | Pattern::EmptyList,
10331033+ _,
10341034+ )
10351035+ | (Pattern::String { .. }, RuntimeCheck::String { .. }) => vec![],
10361036+10371037+ // After making sure a value is not an empty list we'll have to perform
10381038+ // additional checks on its first item and on the tail.
10391039+ (
10401040+ Pattern::List {
10411041+ first_pattern,
10421042+ rest_pattern,
10431043+ },
10441044+ RuntimeCheck::List {
10451045+ first_arg,
10461046+ rest_arg,
10471047+ },
10481048+ ) => vec![first_arg.is(*first_pattern), rest_arg.is(*rest_pattern)],
10491049+10501050+ // After making sure a value is a specific variant we'll have to check each
10511051+ // of its arguments respects the given patterns (as shown in the doc example for
10521052+ // this function!)
10531053+ (Pattern::Variant { args_patterns, .. }, RuntimeCheck::Variant { args, .. }) => {
10541054+ (args.iter().zip(args_patterns))
10551055+ .map(|(arg, pattern)| arg.is(*pattern))
10561056+ .collect_vec()
10571057+ }
10581058+10591059+ // Tuples are exactly the same as variants: after making sure we're dealing with
10601060+ // a tuple, we will have to check that each of its elements matches the given
10611061+ // pattern: `a is #(1, _)` will result in the following checks
10621062+ // `a0 is 1, a1 is _` (where `a0` and `a1` are fresh variable names we use to
10631063+ // refer to each of the tuple's elements).
10641064+ (Pattern::Tuple { elems_patterns }, RuntimeCheck::Tuple { args, .. }) => {
10651065+ (args.iter().zip(elems_patterns))
10661066+ .map(|(arg, pattern)| arg.is(*pattern))
10671067+ .collect_vec()
10681068+ }
10691069+10701070+ // Strings are quite fun: if we've checked at runtime a string starts with a given
10711071+ // prefix and we want to check that it's some overlapping literal value we'll still
10721072+ // have some amount of work to perform.
10731073+ //
10741074+ // Let's have a look at an example: the pattern we care about is `a is "wibble"`
10751075+ // and we've just successfully ran the runtime check for `a is "wib" <> rest`.
10761076+ // So we know the string already starts with `"wib"` what we have to check now
10771077+ // is that the remaining part `rest` is `"ble"`.
10781078+ (
10791079+ Pattern::String { value },
10801080+ RuntimeCheck::StringPrefix {
10811081+ prefix, rest_arg, ..
10821082+ },
10831083+ ) => {
10841084+ let remaining = value.strip_prefix(prefix.as_str()).unwrap_or(value);
10851085+ vec![rest_arg.is(self.string_pattern(remaining))]
10861086+ }
10871087+10881088+ // String prefixes are similar to strings, but a bit more involved. Let's say we're
10891089+ // checking the pattern:
10901090+ //
10911091+ // ```text
10921092+ // "wibblest" <> rest1
10931093+ // ─┬────────
10941094+ // ╰── We will refer to this as `prefix1`
10951095+ // ```
10961096+ //
10971097+ // And we know that the following overlapping runtime check has already succeeded:
10981098+ //
10991099+ // ```text
11001100+ // "wibble" <> rest0
11011101+ // ─┬──────
11021102+ // ╰── We will refer to this as `prefix0`
11031103+ // ```
11041104+ //
11051105+ // We're lucky because we now know quite a bit about the shape of the string. Since
11061106+ // we know it already starts with `"wibble"` we can just check that the remaining
11071107+ // part after that starts with the missing part of the prefix:
11081108+ // `prefix0 is "st" <> rest1`.
11091109+ (
11101110+ Pattern::StringPrefix {
11111111+ prefix: prefix1,
11121112+ rest_pattern: rest1,
11131113+ },
11141114+ RuntimeCheck::StringPrefix {
11151115+ prefix: prefix0,
11161116+ rest_arg: rest0,
11171117+ },
11181118+ ) => {
11191119+ let remaining = prefix1.strip_prefix(prefix0.as_str()).unwrap_or(prefix1);
11201120+ vec![rest0.is(self.string_prefix_pattern(remaining, *rest1))]
11211121+ }
11221122+11231123+ (_, _) => unreachable!("invalid pattern overlapping"),
11241124+ }
11251125+ }
11261126+10981127 /// Builds an `IsVariant` runtime check, coming up with new fresh variable names
10991128 /// for its arguments.
11001129 ///
···11181147 /// names for its arguments.
11191148 ///
11201149 fn is_list_check(&mut self, inner_type: Arc<Type>) -> RuntimeCheck {
11211121- RuntimeCheck::NonEmptyList {
11501150+ RuntimeCheck::List {
11221151 first_arg: self.fresh_variable(inner_type.clone()),
11231152 rest_arg: self.fresh_variable(Arc::new(Type::list(inner_type))),
11241153 }
···11361165 .collect_vec(),
11371166 }
11381167 }
11681168+11691169+ /// Allocates a new `StringPattern` with the given value.
11701170+ ///
11711171+ fn string_pattern(&mut self, value: &str) -> Id<Pattern> {
11721172+ self.patterns.alloc(Pattern::String {
11731173+ value: EcoString::from(value),
11741174+ })
11751175+ }
11761176+11771177+ /// Allocates a new `StringPrefix` pattern with the given prefix and pattern
11781178+ /// for the rest of the string.
11791179+ ///
11801180+ fn string_prefix_pattern(&mut self, prefix: &str, rest_pattern: Id<Pattern>) -> Id<Pattern> {
11811181+ self.patterns.alloc(Pattern::StringPrefix {
11821182+ prefix: EcoString::from(prefix),
11831183+ rest_pattern,
11841184+ })
11851185+ }
11391186}
1140118711411188/// Returns a pattern check from `first_branch` to be used as a pivot to split all
···11711218 /// This is used to allow quickly looking up a choice in the `choices`
11721219 /// vector, without loosing track of the checks' order.
11731220 indices: HashMap<RuntimeCheckKind, usize>,
12211221+12221222+ /// This is used to store the indices of just the prefix checks as they have
12231223+ /// different rules from all the other `RuntimeCheckKinds` whose indices are
12241224+ /// instead stored in the `indices` field.
12251225+ ///
12261226+ /// We discuss this in more detail in the `index_of_overlapping_runtime_check`
12271227+ /// function!
12281228+ prefix_indices: Trie<String, usize>,
11741229}
1175123011761231impl BranchSplitter {
···11891244 fallback: VecDeque::new(),
11901245 choices,
11911246 indices,
12471247+ prefix_indices: Trie::new(),
11921248 }
11931249 }
11941250···12031259 self.fallback.push_back(branch);
12041260 }
1205126112061206- /// Add a branch that we know will only ever run if the `check` is true.
12621262+ /// Given a branch and the pattern its using to check on the pivot variable,
12631263+ /// adds it to the paths where it's relevant, that is where we know from
12641264+ /// previous checks that this pattern has a chance of matching.
12071265 ///
12081208- fn add_checked_branch(&mut self, check: RuntimeCheck, branch: Branch) {
12091209- match self.indices.get(&check.kind()) {
12101210- Some(index) => {
12111211- let (_, branches) = self
12661266+ fn add_checked_branch(
12671267+ &mut self,
12681268+ pattern: Pattern,
12691269+ branch: Branch,
12701270+ branch_mode: &BranchMode,
12711271+ compiler: &mut Compiler<'_>,
12721272+ ) {
12731273+ let kind = pattern
12741274+ .to_runtime_check_kind()
12751275+ .expect("no unconditional patterns left");
12761276+12771277+ let indices_of_overlapping_checks = self.indices_of_overlapping_checks(&kind);
12781278+ if indices_of_overlapping_checks.is_empty() {
12791279+ // This is a new choice we haven't yet discovered as it is not overlapping
12801280+ // with any of the existing ones. So we add it as a possible new path
12811281+ // we might have to go down to in the decision tree.
12821282+ self.save_index_of_new_choice(kind.clone());
12831283+ let mut branches = self.fallback.clone();
12841284+ branches.push_back(branch);
12851285+ let check = compiler.fresh_runtime_check(kind, branch_mode);
12861286+ self.choices.push((check, branches));
12871287+ } else {
12881288+ // Otherwise, we know that the check for this branch overlaps with
12891289+ // (possibly more than one) existing checks and so is relevant only
12901290+ // as part of those existing paths.
12911291+ // We'll add the branch with its newly discovered checks only to those
12921292+ // paths.
12931293+ for index in indices_of_overlapping_checks {
12941294+ let (overlapping_check, branches) = self
12121295 .choices
12131213- .get_mut(*index)
12961296+ .get_mut(index)
12141297 .expect("check to already be a choice");
12981298+12991299+ let mut branch = branch.clone();
13001300+ for new_check in compiler.new_checks(&pattern, overlapping_check) {
13011301+ branch.add_check(new_check);
13021302+ }
12151303 branches.push_back(branch);
12161304 }
13051305+ }
13061306+ }
13071307+13081308+ fn save_index_of_new_choice(&mut self, kind: RuntimeCheckKind) {
13091309+ let _ = match kind {
13101310+ RuntimeCheckKind::Int { .. }
13111311+ | RuntimeCheckKind::Float { .. }
13121312+ | RuntimeCheckKind::String { .. }
13131313+ | RuntimeCheckKind::Tuple { .. }
13141314+ | RuntimeCheckKind::BitArray { .. }
13151315+ | RuntimeCheckKind::Variant { .. }
13161316+ | RuntimeCheckKind::EmptyList
13171317+ | RuntimeCheckKind::NonEmptyList => self.indices.insert(kind, self.choices.len()),
13181318+13191319+ RuntimeCheckKind::StringPrefix { prefix } => self
13201320+ .prefix_indices
13211321+ .insert(prefix.to_string(), self.choices.len()),
13221322+ };
13231323+ }
1217132412181218- None => {
12191219- let _ = self.indices.insert(check.kind(), self.choices.len());
12201220- let mut branches = self.fallback.clone();
12211221- branches.push_back(branch);
12221222- self.choices.push((check, branches));
13251325+ fn indices_of_overlapping_checks(&self, kind: &RuntimeCheckKind) -> Vec<usize> {
13261326+ match kind {
13271327+ // All these checks will only overlap with a check that is exactly the
13281328+ // same, so we just look up their index in the `indices` map using the
13291329+ // kind as the lookup.
13301330+ RuntimeCheckKind::Int { .. }
13311331+ | RuntimeCheckKind::Float { .. }
13321332+ | RuntimeCheckKind::Tuple { .. }
13331333+ | RuntimeCheckKind::BitArray { .. }
13341334+ | RuntimeCheckKind::Variant { .. }
13351335+ | RuntimeCheckKind::EmptyList
13361336+ | RuntimeCheckKind::NonEmptyList => {
13371337+ self.indices.get(kind).cloned().into_iter().collect_vec()
13381338+ }
13391339+13401340+ // String patterns are a bit more tricky as they might end up overlapping
13411341+ // even if they're not exactly the same kind of check! Let's have a look
13421342+ // at an example. Say we're compiling these branches:
13431343+ //
13441344+ // ```
13451345+ // a is "wibble" <> rest -> todo
13461346+ // a is "wibbler" <> rest -> todo
13471347+ // ```
13481348+ //
13491349+ // We use the first (and only) check in the first branch as the pivot and
13501350+ // now we have to decide where to put the next branch. Is it matching with
13511351+ // the first one or completely unrelated?
13521352+ // Since `"wibbler"` starts with `"wibble"` we know it's overlapping and
13531353+ // it cannot possibly match if the previous one doesn't!
13541354+ //
13551355+ // So when we find a `String`/`StringPrefix` pattern we look for a prefix
13561356+ // among the ones we have discovered so far that could match with it.
13571357+ // That is, we look for a prefix of the pattern we're checking in the prefix
13581358+ // trie.
13591359+ RuntimeCheckKind::StringPrefix { prefix: value } => {
13601360+ ancestors_values(&self.prefix_indices, value).collect_vec()
13611361+ }
13621362+13631363+ // Strings are almost exactly the same, except they could also have an exact
13641364+ // match with other string patterns. So a string pattern could overlap with
13651365+ // another string pattern (if they're matching on the same value), or with
13661366+ // one or more string prefix patterns with a matching prefix.
13671367+ RuntimeCheckKind::String { value } => {
13681368+ let first_index = self.indices.get(kind).cloned();
13691369+ first_index
13701370+ .into_iter()
13711371+ .chain(ancestors_values(&self.prefix_indices, value))
13721372+ .collect_vec()
12231373 }
12241374 }
12251375 }
13761376+}
1226137712271227- fn get_overlapping_runtime_check(&self, kind: &RuntimeCheckKind) -> Option<RuntimeCheck> {
12281228- let index = self.indices.get(kind)?;
12291229- let (runtime_check, _) = self.choices.get(*index)?;
12301230- Some(runtime_check.clone())
12311231- }
13781378+fn ancestors_values(trie: &Trie<String, usize>, key: &str) -> impl Iterator<Item = usize> {
13791379+ trie.get_ancestor(key)
13801380+ .into_iter()
13811381+ .flat_map(|ancestor| ancestor.values().copied())
12321382}
1233138312341384pub struct ConstructorSpecialiser {
···13821532 let var = self
13831533 .subject_variables
13841534 .get(i)
13851385- .expect("wrong number of subjects")
13861386- .clone();
13871387-13881388- checks.push(PatternCheck::new(var, pattern))
15351535+ .expect("wrong number of subjects");
15361536+ checks.push(var.is(pattern))
13891537 }
1390153813911539 let has_guard = branch.guard.is_some();
···14071555 let var = self
14081556 .subject_variables
14091557 .first()
14101410- .expect("wrong number of subject variables for pattern")
14111411- .clone();
14121412- let checks = vec![PatternCheck::new(var, pattern)];
14131413- let branch = Branch::new(self.number_of_clauses, 0, checks, false);
15581558+ .expect("wrong number of subject variables for pattern");
15591559+ let branch = Branch::new(self.number_of_clauses, 0, vec![var.is(pattern)], false);
14141560 self.number_of_clauses += 1;
14151561 self.branches.push(branch);
14161562 }
···14721618 }
1473161914741620 TypedPattern::Tuple { elems, .. } => {
14751475- let elements = elems.iter().map(|elem| self.register(elem)).collect_vec();
14761476- self.insert(Pattern::Tuple { elements })
16211621+ let elems_patterns = elems.iter().map(|elem| self.register(elem)).collect_vec();
16221622+ self.insert(Pattern::Tuple { elems_patterns })
14771623 }
1478162414791625 TypedPattern::List { elements, tail, .. } => {
···14821628 None => self.insert(Pattern::EmptyList),
14831629 };
14841630 for element in elements.iter().rev() {
14851485- let first = self.register(element);
14861486- list = self.insert(Pattern::List { first, rest: list });
16311631+ let first_pattern = self.register(element);
16321632+ list = self.insert(Pattern::List {
16331633+ first_pattern,
16341634+ rest_pattern: list,
16351635+ });
14871636 }
14881637 list
14891638 }
···14931642 constructor,
14941643 ..
14951644 } => {
14961496- let variant_index =
14971497- constructor.expect_ref("must be inferred").constructor_index as usize;
14981498- let arguments = arguments
16451645+ let index = constructor.expect_ref("must be inferred").constructor_index as usize;
16461646+ let args_patterns = arguments
14991647 .iter()
15001648 .map(|argument| self.register(&argument.value))
15011649 .collect_vec();
15021502- self.insert(Pattern::Constructor {
15031503- variant_index,
15041504- arguments,
16501650+ self.insert(Pattern::Variant {
16511651+ index,
16521652+ args_patterns,
15051653 })
15061654 }
15071655···15251673 AssignName::Variable(name) => Pattern::Variable { name: name.clone() },
15261674 AssignName::Discard(_) => Pattern::Discard,
15271675 };
15281528- let rest = self.insert(rest_pattern);
15291529- self.insert(Pattern::StringPrefix { prefix, rest })
16761676+ let rest_pattern = self.insert(rest_pattern);
16771677+ self.insert(Pattern::StringPrefix {
16781678+ prefix,
16791679+ rest_pattern,
16801680+ })
15301681 }
1531168215321683 TypedPattern::VarUsage { .. } => {