mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Redundant and exhaustive marks in mono
This commit is contained in:
parent
98869b557d
commit
2f1306afd1
10 changed files with 152 additions and 86 deletions
|
@ -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);
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -108,6 +108,7 @@ fn walk_when_branch<V: Visitor>(visitor: &mut V, branch: &WhenBranch, expr_var:
|
|||
patterns,
|
||||
value,
|
||||
guard,
|
||||
redundant: _,
|
||||
} = branch;
|
||||
|
||||
patterns
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue