Redundant and exhaustive marks in mono

This commit is contained in:
Ayaz Hafiz 2022-04-28 09:57:08 -04:00 committed by ayazhafiz
parent 98869b557d
commit 2f1306afd1
10 changed files with 152 additions and 86 deletions

View file

@ -9,7 +9,7 @@ use roc_module::ident::{Lowercase, TagName};
use roc_module::low_level::LowLevel;
use roc_module::symbol::Symbol;
use roc_region::all::{Loc, Region};
use roc_types::subs::{ExhaustiveMark, VarStore, Variable};
use roc_types::subs::{ExhaustiveMark, RedundantMark, VarStore, Variable};
macro_rules! macro_magic {
(@single $($x:tt)*) => (());
@ -4686,6 +4686,7 @@ fn result_map(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(ok),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4716,6 +4717,7 @@ fn result_map(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(err),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4785,6 +4787,7 @@ fn result_map_err(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(ok),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4815,6 +4818,7 @@ fn result_map_err(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(err),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4860,6 +4864,7 @@ fn result_with_default(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(Var(Symbol::ARG_3)),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4880,6 +4885,7 @@ fn result_with_default(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(Var(Symbol::ARG_2)),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4932,6 +4938,7 @@ fn result_is_err(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(false_expr),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -4959,6 +4966,7 @@ fn result_is_err(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(true_expr),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -5011,6 +5019,7 @@ fn result_is_ok(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(true_expr),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -5038,6 +5047,7 @@ fn result_is_ok(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(false_expr),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -5102,6 +5112,7 @@ fn result_after(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(ok),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);
@ -5132,6 +5143,7 @@ fn result_after(symbol: Symbol, var_store: &mut VarStore) -> Def {
patterns: vec![no_region(pattern)],
value: no_region(err),
guard: None,
redundant: RedundantMark(var_store.fresh()),
};
branches.push(branch);

View file

@ -8,7 +8,7 @@ use roc_module::called_via::CalledVia;
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::Symbol;
use roc_region::all::{Loc, Region};
use roc_types::subs::{ExhaustiveMark, VarStore, Variable};
use roc_types::subs::{ExhaustiveMark, RedundantMark, VarStore, Variable};
use roc_types::types::{AliasKind, LambdaSet, Type, TypeExtension};
#[derive(Debug, Default, Clone, Copy)]
@ -1209,6 +1209,7 @@ fn build_effect_loop_inner_body(
patterns: vec![Loc::at_zero(step_pattern)],
value: Loc::at_zero(force_thunk2),
guard: None,
redundant: RedundantMark(var_store.fresh()),
}
};
@ -1220,6 +1221,7 @@ fn build_effect_loop_inner_body(
patterns: vec![Loc::at_zero(done_pattern)],
value: Loc::at_zero(Expr::Var(done_symbol)),
guard: None,
redundant: RedundantMark(var_store.fresh()),
}
};

View file

@ -15,23 +15,40 @@ pub use roc_exhaustive::Context as ExhaustiveContext;
pub const GUARD_CTOR: &str = "#Guard";
pub const NONEXHAUSIVE_CTOR: &str = "#Open";
pub struct ErrorSummary {
errors: Vec<Error>,
exhaustive: bool,
redundant: Vec<RedundantMark>,
pub struct ExhaustiveSummary {
pub errors: Vec<Error>,
pub exhaustive: bool,
pub redundancies: Vec<RedundantMark>,
}
pub fn check(
subs: &Subs,
sketched_rows: SketchedRows,
context: ExhaustiveContext,
) -> Result<(), Vec<Error>> {
) -> ExhaustiveSummary {
let overall_region = sketched_rows.overall_region;
// TODO: can we keep going even if we had redundant rows?
let matrix = sketched_rows
.reify_to_non_redundant(subs)
.map_err(|e| vec![e])?;
roc_exhaustive::check(overall_region, context, matrix)
let mut all_errors = Vec::with_capacity(1);
let NonRedundantSummary {
non_redundant_rows,
errors,
redundancies,
} = sketched_rows.reify_to_non_redundant(subs);
all_errors.extend(errors);
let exhaustive = match roc_exhaustive::check(overall_region, context, non_redundant_rows) {
Ok(()) => true,
Err(errors) => {
all_errors.extend(errors);
false
}
};
ExhaustiveSummary {
errors: all_errors,
exhaustive,
redundancies,
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -69,6 +86,7 @@ struct SketchedRow {
patterns: Vec<SketchedPattern>,
region: Region,
guard: Guard,
redundant_mark: RedundantMark,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -78,7 +96,7 @@ pub struct SketchedRows {
}
impl SketchedRows {
pub fn reify_to_non_redundant(self, subs: &Subs) -> Result<Vec<Vec<Pattern>>, Error> {
fn reify_to_non_redundant(self, subs: &Subs) -> NonRedundantSummary {
to_nonredundant_rows(subs, self)
}
}
@ -203,6 +221,7 @@ pub fn sketch_rows(target_var: Variable, region: Region, patterns: &[WhenBranch]
patterns,
guard,
value: _,
redundant,
} in patterns
{
let guard = if guard.is_some() {
@ -248,6 +267,7 @@ pub fn sketch_rows(target_var: Variable, region: Region, patterns: &[WhenBranch]
patterns,
region: loc_pat.region,
guard,
redundant_mark: *redundant,
};
rows.push(row);
}
@ -261,18 +281,28 @@ pub fn sketch_rows(target_var: Variable, region: Region, patterns: &[WhenBranch]
/// REDUNDANT PATTERNS
struct NonRedundantSummary {
non_redundant_rows: Vec<Vec<Pattern>>,
redundancies: Vec<RedundantMark>,
errors: Vec<Error>,
}
/// INVARIANT: Produces a list of rows where (forall row. length row == 1)
fn to_nonredundant_rows(subs: &Subs, rows: SketchedRows) -> Result<Vec<Vec<Pattern>>, Error> {
fn to_nonredundant_rows(subs: &Subs, rows: SketchedRows) -> NonRedundantSummary {
let SketchedRows {
rows,
overall_region,
} = rows;
let mut checked_rows = Vec::with_capacity(rows.len());
let mut redundancies = vec![];
let mut errors = vec![];
for SketchedRow {
patterns,
guard,
region,
redundant_mark,
} in rows.into_iter()
{
let next_row: Vec<Pattern> = patterns
@ -283,7 +313,8 @@ fn to_nonredundant_rows(subs: &Subs, rows: SketchedRows) -> Result<Vec<Vec<Patte
if matches!(guard, Guard::HasGuard) || is_useful(checked_rows.clone(), next_row.clone()) {
checked_rows.push(next_row);
} else {
return Err(Error::Redundant {
redundancies.push(redundant_mark);
errors.push(Error::Redundant {
overall_region,
branch_region: region,
index: HumanIndex::zero_based(checked_rows.len()),
@ -291,7 +322,11 @@ fn to_nonredundant_rows(subs: &Subs, rows: SketchedRows) -> Result<Vec<Vec<Patte
}
}
Ok(checked_rows)
NonRedundantSummary {
non_redundant_rows: checked_rows,
redundancies,
errors,
}
}
fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union, TagId) {

View file

@ -18,7 +18,7 @@ use roc_parse::ast::{self, EscapedChar, StrLiteral};
use roc_parse::pattern::PatternType::*;
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
use roc_region::all::{Loc, Region};
use roc_types::subs::{ExhaustiveMark, VarStore, Variable};
use roc_types::subs::{ExhaustiveMark, RedundantMark, VarStore, Variable};
use roc_types::types::{Alias, Category, LambdaSet, Type};
use std::fmt::{Debug, Display};
use std::{char, u32};
@ -338,6 +338,8 @@ pub struct WhenBranch {
pub patterns: Vec<Loc<Pattern>>,
pub value: Loc<Expr>,
pub guard: Option<Loc<Expr>>,
/// Whether this branch is redundant in the `when` it appears in
pub redundant: RedundantMark,
}
impl WhenBranch {
@ -1137,6 +1139,7 @@ fn canonicalize_when_branch<'a>(
patterns,
value,
guard,
redundant: RedundantMark(var_store.fresh()),
},
references,
)
@ -1374,6 +1377,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
patterns: branch.patterns,
value,
guard,
redundant: RedundantMark(var_store.fresh()),
};
new_branches.push(new_branch);

View file

@ -108,6 +108,7 @@ fn walk_when_branch<V: Visitor>(visitor: &mut V, branch: &WhenBranch, expr_var:
patterns,
value,
guard,
redundant: _,
} = branch;
patterns