mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Merge pull request #4450 from roc-lang/simpl-exhaustiveness
Simplify constructor recovery
This commit is contained in:
commit
c4016547af
2 changed files with 39 additions and 56 deletions
|
@ -247,7 +247,7 @@ fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
|
|||
let is_alt_exhaustive = |Ctor { arity, tag_id, .. }| {
|
||||
let new_matrix: Vec<_> = matrix
|
||||
.iter()
|
||||
.filter_map(|r| specialize_row_by_ctor(tag_id, arity, r))
|
||||
.filter_map(|r| specialize_row_by_ctor(tag_id, arity, r.to_owned()))
|
||||
.collect();
|
||||
let rest: Vec<Vec<Pattern>> = is_exhaustive(&new_matrix, arity + n - 1);
|
||||
|
||||
|
@ -301,8 +301,8 @@ fn recover_ctor(
|
|||
arity: usize,
|
||||
mut patterns: Vec<Pattern>,
|
||||
) -> Vec<Pattern> {
|
||||
let mut rest = patterns.split_off(arity);
|
||||
let args = patterns;
|
||||
let args = patterns.split_off(patterns.len() - arity);
|
||||
let mut rest = patterns;
|
||||
|
||||
rest.push(Ctor(union, tag_id, args));
|
||||
|
||||
|
@ -310,8 +310,8 @@ fn recover_ctor(
|
|||
}
|
||||
|
||||
fn recover_list(arity: ListArity, mut patterns: Vec<Pattern>) -> Vec<Pattern> {
|
||||
let mut rest = patterns.split_off(arity.min_len());
|
||||
let list_elems = patterns;
|
||||
let list_elems = patterns.split_off(patterns.len() - arity.min_len());
|
||||
let mut rest = patterns;
|
||||
|
||||
rest.push(List(arity, list_elems));
|
||||
|
||||
|
@ -340,7 +340,7 @@ pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
|||
match first_pattern {
|
||||
// keep checking rows that start with this Ctor or Anything
|
||||
Ctor(_, id, args) => {
|
||||
specialize_row_by_ctor2(id, args.len(), &mut old_matrix, &mut matrix);
|
||||
specialize_matrix_by_ctor(id, args.len(), &mut old_matrix, &mut matrix);
|
||||
|
||||
std::mem::swap(&mut old_matrix, &mut matrix);
|
||||
|
||||
|
@ -411,7 +411,7 @@ pub fn is_useful(mut old_matrix: PatternMatrix, mut vector: Row) -> bool {
|
|||
|
||||
let mut old_matrix = old_matrix.clone();
|
||||
let mut matrix = vec![];
|
||||
specialize_row_by_ctor2(
|
||||
specialize_matrix_by_ctor(
|
||||
tag_id,
|
||||
arity,
|
||||
&mut old_matrix,
|
||||
|
@ -489,13 +489,11 @@ fn specialize_matrix_by_list(
|
|||
// constructors are built up.
|
||||
fn specialize_row_by_list(spec_arity: ListArity, mut row: Row) -> Option<Row> {
|
||||
let head = row.pop();
|
||||
let row_patterns = row;
|
||||
let mut spec_patterns = row;
|
||||
|
||||
match head {
|
||||
Some(List(this_arity, args)) => {
|
||||
if this_arity.covers_arities_of(&spec_arity) {
|
||||
let mut specialized_pats = Vec::with_capacity(row_patterns.len() + args.len());
|
||||
|
||||
// This pattern covers the constructor we are specializing, so add on the
|
||||
// specialized fields of this pattern relative to the given constructor.
|
||||
if spec_arity.min_len() != this_arity.min_len() {
|
||||
|
@ -516,17 +514,16 @@ fn specialize_row_by_list(spec_arity: ListArity, mut row: Row) -> Option<Row> {
|
|||
|
||||
let new_pats = (before.iter().chain(extra_wildcards).chain(after)).cloned();
|
||||
|
||||
specialized_pats.extend(new_pats);
|
||||
specialized_pats.extend(row_patterns);
|
||||
spec_patterns.extend(new_pats);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug_assert_eq!(this_arity.min_len(), spec_arity.min_len());
|
||||
|
||||
specialized_pats.extend(args);
|
||||
specialized_pats.extend(row_patterns);
|
||||
spec_patterns.extend(args);
|
||||
}
|
||||
Some(specialized_pats)
|
||||
|
||||
Some(spec_patterns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -534,8 +531,8 @@ fn specialize_row_by_list(spec_arity: ListArity, mut row: Row) -> Option<Row> {
|
|||
Some(Anything) => {
|
||||
// The specialized fields for a `Anything` pattern with a list constructor is just
|
||||
// `Anything` repeated for the number of times we want to see the list pattern.
|
||||
let specialized_pats = std::iter::repeat(Anything).take(spec_arity.min_len()).chain(row_patterns).collect();
|
||||
Some(specialized_pats)
|
||||
spec_patterns.extend(std::iter::repeat(Anything).take(spec_arity.min_len()));
|
||||
Some(spec_patterns)
|
||||
}
|
||||
Some(Ctor(..)) => internal_error!("After type checking, lists and constructors should never align in exhaustiveness checking"),
|
||||
Some(Literal(..)) => internal_error!("After type checking, lists and literals should never align in exhaustiveness checking"),
|
||||
|
@ -544,63 +541,36 @@ fn specialize_row_by_list(spec_arity: ListArity, mut row: Row) -> Option<Row> {
|
|||
}
|
||||
|
||||
/// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
|
||||
fn specialize_row_by_ctor2(
|
||||
fn specialize_matrix_by_ctor(
|
||||
tag_id: TagId,
|
||||
arity: usize,
|
||||
old_matrix: &mut PatternMatrix,
|
||||
matrix: &mut PatternMatrix,
|
||||
) {
|
||||
for mut row in old_matrix.drain(..) {
|
||||
let head = row.pop();
|
||||
let mut patterns = row;
|
||||
|
||||
match head {
|
||||
Some(Ctor(_, id, args)) => {
|
||||
if id == tag_id {
|
||||
patterns.extend(args);
|
||||
matrix.push(patterns);
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
Some(Anything) => {
|
||||
// TODO order!
|
||||
patterns.extend(std::iter::repeat(Anything).take(arity));
|
||||
matrix.push(patterns);
|
||||
}
|
||||
Some(List(..)) => internal_error!("After type checking, constructors and lists should never align in exhaustiveness checking"),
|
||||
Some(Literal(_)) => internal_error!("After type checking, constructors and literal should never align in pattern match exhaustiveness checks."),
|
||||
None => internal_error!("Empty matrices should not get specialized."),
|
||||
for row in old_matrix.drain(..) {
|
||||
if let Some(spec_row) = specialize_row_by_ctor(tag_id, arity, row) {
|
||||
matrix.push(spec_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// INVARIANT: (length row == N) ==> (length result == arity + N - 1)
|
||||
fn specialize_row_by_ctor(tag_id: TagId, arity: usize, row: &RefRow) -> Option<Row> {
|
||||
let mut row = row.to_vec();
|
||||
|
||||
fn specialize_row_by_ctor(tag_id: TagId, arity: usize, mut row: Row) -> Option<Row> {
|
||||
let head = row.pop();
|
||||
let patterns = row;
|
||||
let mut spec_patterns = row;
|
||||
|
||||
match head {
|
||||
Some(Ctor(_, id, args)) => {
|
||||
if id == tag_id {
|
||||
// TODO order!
|
||||
let mut new_patterns = Vec::new();
|
||||
new_patterns.extend(args);
|
||||
new_patterns.extend(patterns);
|
||||
Some(new_patterns)
|
||||
spec_patterns.extend(args);
|
||||
Some(spec_patterns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(Anything) => {
|
||||
// TODO order!
|
||||
let new_patterns = std::iter::repeat(Anything)
|
||||
.take(arity)
|
||||
.chain(patterns)
|
||||
.collect();
|
||||
Some(new_patterns)
|
||||
spec_patterns.extend(std::iter::repeat(Anything).take(arity));
|
||||
Some(spec_patterns)
|
||||
}
|
||||
Some(List(..)) => {
|
||||
internal_error!(r#"After type checking, a constructor can never align with a list"#)
|
||||
|
|
|
@ -12266,8 +12266,7 @@ All branches in an `if` must have the same type!
|
|||
|
||||
[[B, ..]]
|
||||
[_, .., []]
|
||||
[[], .., [.., A]]
|
||||
[[_, ..], .., [.., A]]
|
||||
[_, .., [.., A]]
|
||||
|
||||
I would have to crash if I saw one of those! Add branches for them!
|
||||
"###
|
||||
|
@ -12384,4 +12383,18 @@ All branches in an `if` must have the same type!
|
|||
one should be removed.
|
||||
"###
|
||||
);
|
||||
|
||||
test_no_problem!(
|
||||
list_match_with_guard,
|
||||
indoc!(
|
||||
r#"
|
||||
l : List [A]
|
||||
|
||||
when l is
|
||||
[ A, .. ] if Bool.true -> ""
|
||||
[ A, .. ] -> ""
|
||||
_ -> ""
|
||||
"#
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue