mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
Move exhaustiveness checking to type checking
This commit is contained in:
parent
f7e04490c0
commit
85e3373d8b
15 changed files with 346 additions and 94 deletions
|
@ -4727,6 +4727,7 @@ fn result_map(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
defn(
|
||||
|
@ -4824,6 +4825,7 @@ fn result_map_err(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
defn(
|
||||
|
@ -4887,6 +4889,7 @@ fn result_with_default(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
defn(
|
||||
|
@ -4964,6 +4967,7 @@ fn result_is_err(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
defn(
|
||||
|
@ -5041,6 +5045,7 @@ fn result_is_ok(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
defn(
|
||||
|
@ -5133,6 +5138,7 @@ fn result_after(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(no_region(Var(Symbol::ARG_1))),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
defn(
|
||||
|
|
|
@ -574,7 +574,7 @@ impl Constraints {
|
|||
Constraint::IsOpenType(_) => false,
|
||||
Constraint::IncludesTag(_) => false,
|
||||
Constraint::PatternPresence(_, _, _, _) => false,
|
||||
Constraint::Exhaustive(_, _) => false,
|
||||
Constraint::Exhaustive { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,10 +603,27 @@ impl Constraints {
|
|||
Constraint::Store(type_index, variable, string_index, line_number)
|
||||
}
|
||||
|
||||
pub fn exhaustive(&mut self, rows: SketchedRows, context: ExhaustiveContext) -> Constraint {
|
||||
let rows_index = Index::push_new(&mut self.sketched_rows, rows);
|
||||
pub fn exhaustive(
|
||||
&mut self,
|
||||
real_var: Variable,
|
||||
real_region: Region,
|
||||
real_category: Category,
|
||||
expected_branches: Expected<Type>,
|
||||
sketched_rows: SketchedRows,
|
||||
context: ExhaustiveContext,
|
||||
) -> Constraint {
|
||||
let real_category = Index::push_new(&mut self.categories, real_category);
|
||||
let expected_branches = Index::push_new(&mut self.expectations, expected_branches);
|
||||
let sketched_rows = Index::push_new(&mut self.sketched_rows, sketched_rows);
|
||||
|
||||
Constraint::Exhaustive(rows_index, context)
|
||||
Constraint::Exhaustive {
|
||||
real_var,
|
||||
real_region,
|
||||
real_category,
|
||||
expected_branches,
|
||||
sketched_rows,
|
||||
context,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -652,7 +669,14 @@ pub enum Constraint {
|
|||
Index<PatternCategory>,
|
||||
Region,
|
||||
),
|
||||
Exhaustive(Index<SketchedRows>, ExhaustiveContext),
|
||||
Exhaustive {
|
||||
real_var: Variable,
|
||||
real_region: Region,
|
||||
real_category: Index<Category>,
|
||||
expected_branches: Index<Expected<Type>>,
|
||||
sketched_rows: Index<SketchedRows>,
|
||||
context: ExhaustiveContext,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
|
@ -707,8 +731,19 @@ impl std::fmt::Debug for Constraint {
|
|||
arg0, arg1, arg2, arg3
|
||||
)
|
||||
}
|
||||
Self::Exhaustive(arg0, arg1) => {
|
||||
write!(f, "Exhaustive({:?}, {:?})", arg0, arg1)
|
||||
Self::Exhaustive {
|
||||
real_var: arg0,
|
||||
real_region: arg1,
|
||||
real_category: arg2,
|
||||
expected_branches: arg3,
|
||||
sketched_rows: arg4,
|
||||
context: arg5,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Exhaustive({:?}, {:?}, {:?}, {:?}, {:?}, {:?})",
|
||||
arg0, arg1, arg2, arg3, arg4, arg5
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1366,6 +1366,7 @@ fn build_effect_loop_inner_body(
|
|||
region: Region::zero(),
|
||||
loc_cond: Box::new(force_thunk_call),
|
||||
branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
Expr::LetNonRec(
|
||||
|
|
|
@ -6,6 +6,7 @@ use roc_exhaustive::{is_useful, Ctor, Error, Guard, Literal, Pattern, RenderAs,
|
|||
use roc_module::ident::{TagIdIntType, TagName};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{Content, FlatType, Subs, SubsFmtContent, Variable};
|
||||
use roc_types::types::AliasKind;
|
||||
|
||||
pub use roc_exhaustive::Context as ExhaustiveContext;
|
||||
|
||||
|
@ -22,7 +23,7 @@ pub fn check(
|
|||
roc_exhaustive::check(overall_region, context, matrix)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
enum SketchedPattern {
|
||||
Anything,
|
||||
Literal(Literal),
|
||||
|
@ -52,14 +53,14 @@ impl SketchedPattern {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct SketchedRow {
|
||||
patterns: Vec<SketchedPattern>,
|
||||
region: Region,
|
||||
guard: Guard,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SketchedRows {
|
||||
rows: Vec<SketchedRow>,
|
||||
overall_region: Region,
|
||||
|
@ -155,13 +156,15 @@ fn sketch_pattern(var: Variable, pattern: &crate::pattern::Pattern) -> SketchedP
|
|||
)
|
||||
}
|
||||
|
||||
// Treat this like a literal so we mark it as non-exhaustive
|
||||
MalformedPattern(..) => SP::Literal(Literal::Byte(1)),
|
||||
|
||||
Underscore
|
||||
| Identifier(_)
|
||||
| AbilityMemberSpecialization { .. }
|
||||
| Shadowed(..)
|
||||
| OpaqueNotInScope(..)
|
||||
| UnsupportedPattern(..)
|
||||
| MalformedPattern(..) => SP::Anything,
|
||||
| UnsupportedPattern(..) => SP::Anything,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +235,7 @@ pub fn sketch_rows(target_var: Variable, region: Region, patterns: &[WhenBranch]
|
|||
|
||||
let row = SketchedRow {
|
||||
patterns,
|
||||
region,
|
||||
region: loc_pat.region,
|
||||
guard,
|
||||
};
|
||||
rows.push(row);
|
||||
|
@ -285,7 +288,7 @@ fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union,
|
|||
|
||||
use {Content::*, FlatType::*};
|
||||
|
||||
match content {
|
||||
match dealias_tag(subs, content) {
|
||||
Structure(TagUnion(tags, ext) | RecursiveTagUnion(_, tags, ext)) => {
|
||||
let (sorted_tags, ext) = tags.sorted_iterator_and_ext(subs, *ext);
|
||||
|
||||
|
@ -335,3 +338,18 @@ fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union,
|
|||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dealias_tag<'a>(subs: &'a Subs, content: &'a Content) -> &'a Content {
|
||||
use Content::*;
|
||||
let mut result = content;
|
||||
loop {
|
||||
match result {
|
||||
Alias(_, _, real_var, AliasKind::Structural)
|
||||
| RecursionVar {
|
||||
structure: real_var,
|
||||
..
|
||||
} => result = subs.get_content_without_compacting(*real_var),
|
||||
_ => return result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use roc_parse::pattern::PatternType::*;
|
|||
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{Alias, LambdaSet, Type};
|
||||
use roc_types::types::{Alias, Category, LambdaSet, Type};
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::{char, u32};
|
||||
|
||||
|
@ -89,6 +89,7 @@ pub enum Expr {
|
|||
region: Region,
|
||||
loc_cond: Box<Loc<Expr>>,
|
||||
branches: Vec<WhenBranch>,
|
||||
branches_cond_var: Variable,
|
||||
},
|
||||
If {
|
||||
cond_var: Variable,
|
||||
|
@ -193,6 +194,47 @@ pub enum Expr {
|
|||
// Compiles, but will crash if reached
|
||||
RuntimeError(RuntimeError),
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn category(&self) -> Category {
|
||||
match self {
|
||||
Self::Num(..) => Category::Num,
|
||||
Self::Int(..) => Category::Int,
|
||||
Self::Float(..) => Category::Float,
|
||||
Self::Str(..) => Category::Str,
|
||||
Self::SingleQuote(..) => Category::Character,
|
||||
Self::List { .. } => Category::List,
|
||||
&Self::Var(sym) => Category::Lookup(sym),
|
||||
Self::When { .. } => Category::When,
|
||||
Self::If { .. } => Category::If,
|
||||
Self::LetRec(_, expr, _) => expr.value.category(),
|
||||
Self::LetNonRec(_, expr, _) => expr.value.category(),
|
||||
&Self::Call(_, _, called_via) => Category::CallResult(None, called_via),
|
||||
&Self::RunLowLevel { op, .. } => Category::LowLevelOpResult(op),
|
||||
Self::ForeignCall { .. } => Category::ForeignCall,
|
||||
Self::Closure(..) => Category::Lambda,
|
||||
Self::Record { .. } => Category::Record,
|
||||
Self::EmptyRecord => Category::Record,
|
||||
Self::Access { field, .. } => Category::Access(field.clone()),
|
||||
Self::Accessor(data) => Category::Accessor(data.field.clone()),
|
||||
Self::Update { .. } => Category::Record,
|
||||
Self::Tag {
|
||||
name, arguments, ..
|
||||
} => Category::TagApply {
|
||||
tag_name: name.clone(),
|
||||
args_count: arguments.len(),
|
||||
},
|
||||
Self::ZeroArgumentTag { name, .. } => Category::TagApply {
|
||||
tag_name: name.clone(),
|
||||
args_count: 0,
|
||||
},
|
||||
&Self::OpaqueRef { name, .. } => Category::OpaqueWrap(name),
|
||||
Self::Expect(..) => Category::Expect,
|
||||
Self::RuntimeError(..) => Category::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClosureData {
|
||||
pub function_type: Variable,
|
||||
|
@ -782,6 +824,7 @@ pub fn canonicalize_expr<'a>(
|
|||
region,
|
||||
loc_cond: Box::new(can_cond),
|
||||
branches: can_branches,
|
||||
branches_cond_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
(expr, output)
|
||||
|
@ -1298,6 +1341,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
region,
|
||||
loc_cond,
|
||||
branches,
|
||||
branches_cond_var,
|
||||
} => {
|
||||
let loc_cond = Box::new(Loc {
|
||||
region: loc_cond.region,
|
||||
|
@ -1333,6 +1377,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
|||
region,
|
||||
loc_cond,
|
||||
branches: new_branches,
|
||||
branches_cond_var,
|
||||
}
|
||||
}
|
||||
If {
|
||||
|
|
|
@ -65,6 +65,7 @@ fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr) {
|
|||
loc_cond,
|
||||
branches,
|
||||
region: _,
|
||||
branches_cond_var: _,
|
||||
} => {
|
||||
walk_when(visitor, *cond_var, *expr_var, loc_cond, branches);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue