mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Second pass
This commit is contained in:
parent
5e0d90ac53
commit
8dc92ccd97
15 changed files with 651 additions and 275 deletions
|
@ -83,6 +83,7 @@ pub enum Unified {
|
|||
Success(Pool),
|
||||
Failure(Pool, ErrorType, ErrorType),
|
||||
BadType(Pool, roc_types::types::Problem),
|
||||
NotInRange(Pool, ErrorType, Vec<ErrorType>),
|
||||
}
|
||||
|
||||
type Outcome = Vec<Mismatch>;
|
||||
|
@ -94,6 +95,13 @@ pub fn unify(subs: &mut Subs, var1: Variable, var2: Variable, mode: Mode) -> Uni
|
|||
|
||||
if mismatches.is_empty() {
|
||||
Unified::Success(vars)
|
||||
} else if let Some((typ, range)) = mismatches.iter().find_map(|mis| match mis {
|
||||
Mismatch::TypeNotInRange(typ, range) => Some((typ, range)),
|
||||
_ => None,
|
||||
}) {
|
||||
let (target_type, _) = subs.var_to_error_type(*typ);
|
||||
let range_types = range.iter().map(|&v| subs.var_to_error_type(v).0).collect();
|
||||
Unified::NotInRange(vars, target_type, range_types)
|
||||
} else {
|
||||
let (type1, mut problems) = subs.var_to_error_type(var1);
|
||||
let (type2, problems2) = subs.var_to_error_type(var2);
|
||||
|
@ -175,6 +183,7 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
|||
unify_structure(subs, pool, &ctx, flat_type, &ctx.second_desc.content)
|
||||
}
|
||||
Alias(symbol, args, real_var) => unify_alias(subs, pool, &ctx, *symbol, *args, *real_var),
|
||||
&RangedNumber(typ, range_vars) => unify_ranged_number(subs, pool, &ctx, typ, range_vars),
|
||||
Error => {
|
||||
// Error propagates. Whatever we're comparing it to doesn't matter!
|
||||
merge(subs, &ctx, Error)
|
||||
|
@ -182,6 +191,73 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unify_ranged_number(
|
||||
subs: &mut Subs,
|
||||
pool: &mut Pool,
|
||||
ctx: &Context,
|
||||
real_var: Variable,
|
||||
range_vars: VariableSubsSlice,
|
||||
) -> Outcome {
|
||||
let other_content = &ctx.second_desc.content;
|
||||
|
||||
let outcome = match other_content {
|
||||
FlexVar(_) => {
|
||||
// Ranged number wins
|
||||
merge(subs, ctx, RangedNumber(real_var, range_vars))
|
||||
}
|
||||
RecursionVar { .. } | RigidVar(..) | Alias(..) | Structure(..) => {
|
||||
unify_pool(subs, pool, real_var, ctx.second, ctx.mode)
|
||||
}
|
||||
&RangedNumber(other_real_var, _other_range_vars) => {
|
||||
unify_pool(subs, pool, real_var, other_real_var, ctx.mode)
|
||||
// TODO: check and intersect "other_range_vars"
|
||||
}
|
||||
Error => merge(subs, ctx, Error),
|
||||
};
|
||||
|
||||
if !outcome.is_empty() {
|
||||
return outcome;
|
||||
}
|
||||
|
||||
check_valid_range(subs, pool, ctx.second, range_vars, ctx.mode)
|
||||
}
|
||||
|
||||
fn check_valid_range(
|
||||
subs: &mut Subs,
|
||||
pool: &mut Pool,
|
||||
var: Variable,
|
||||
range: VariableSubsSlice,
|
||||
mode: Mode,
|
||||
) -> Outcome {
|
||||
let slice = subs
|
||||
.get_subs_slice(range)
|
||||
.iter()
|
||||
.copied()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut it = slice.iter().peekable();
|
||||
while let Some(&possible_var) = it.next() {
|
||||
let snapshot = subs.snapshot();
|
||||
let old_pool = pool.clone();
|
||||
let outcome = unify_pool(subs, pool, var, possible_var, mode);
|
||||
if outcome.is_empty() {
|
||||
// Okay, we matched some type in the range.
|
||||
subs.rollback_to(snapshot);
|
||||
*pool = old_pool;
|
||||
return vec![];
|
||||
} else if it.peek().is_some() {
|
||||
// We failed to match something in the range, but there are still things we can try.
|
||||
subs.rollback_to(snapshot);
|
||||
*pool = old_pool;
|
||||
} else {
|
||||
subs.commit_snapshot(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
return vec![Mismatch::TypeNotInRange(var, slice)];
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unify_alias(
|
||||
subs: &mut Subs,
|
||||
|
@ -231,6 +307,9 @@ fn unify_alias(
|
|||
}
|
||||
}
|
||||
Structure(_) => unify_pool(subs, pool, real_var, ctx.second, ctx.mode),
|
||||
RangedNumber(other_real_var, _) => {
|
||||
unify_pool(subs, pool, real_var, *other_real_var, ctx.mode)
|
||||
}
|
||||
Error => merge(subs, ctx, Error),
|
||||
}
|
||||
}
|
||||
|
@ -302,6 +381,7 @@ fn unify_structure(
|
|||
// can't quite figure out why, but it doesn't seem to impact other types.
|
||||
unify_pool(subs, pool, ctx.first, *real_var, Mode::Eq)
|
||||
}
|
||||
RangedNumber(real_var, _) => unify_pool(subs, pool, ctx.first, *real_var, ctx.mode),
|
||||
Error => merge(subs, ctx, Error),
|
||||
}
|
||||
}
|
||||
|
@ -829,6 +909,7 @@ fn unify_tag_union_new(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum OtherTags2 {
|
||||
Empty,
|
||||
Union(
|
||||
|
@ -1222,7 +1303,7 @@ fn unify_rigid(subs: &mut Subs, ctx: &Context, name: &Lowercase, other: &Content
|
|||
// If the other is flex, rigid wins!
|
||||
merge(subs, ctx, RigidVar(name.clone()))
|
||||
}
|
||||
RigidVar(_) | RecursionVar { .. } | Structure(_) | Alias(_, _, _) => {
|
||||
RigidVar(_) | RecursionVar { .. } | Structure(_) | Alias(_, _, _) | RangedNumber(..) => {
|
||||
// Type mismatch! Rigid can only unify with flex, even if the
|
||||
// rigid names are the same.
|
||||
mismatch!("Rigid {:?} with {:?}", ctx.first, &other)
|
||||
|
@ -1247,7 +1328,12 @@ fn unify_flex(
|
|||
merge(subs, ctx, FlexVar(opt_name.clone()))
|
||||
}
|
||||
|
||||
FlexVar(Some(_)) | RigidVar(_) | RecursionVar { .. } | Structure(_) | Alias(_, _, _) => {
|
||||
FlexVar(Some(_))
|
||||
| RigidVar(_)
|
||||
| RecursionVar { .. }
|
||||
| Structure(_)
|
||||
| Alias(_, _, _)
|
||||
| RangedNumber(..) => {
|
||||
// TODO special-case boolean here
|
||||
// In all other cases, if left is flex, defer to right.
|
||||
// (This includes using right's name if both are flex and named.)
|
||||
|
@ -1306,6 +1392,12 @@ fn unify_recursion(
|
|||
unify_pool(subs, pool, ctx.first, *actual, ctx.mode)
|
||||
}
|
||||
|
||||
RangedNumber(..) => mismatch!(
|
||||
"RecursionVar {:?} with ranged number {:?}",
|
||||
ctx.first,
|
||||
&other
|
||||
),
|
||||
|
||||
Error => merge(subs, ctx, Error),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue