Error reporting for type mismatches involving opaques

This commit is contained in:
ayazhafiz 2022-02-24 00:48:19 -05:00
parent 822e38d026
commit 059c324268
20 changed files with 526 additions and 149 deletions

View file

@ -6,11 +6,11 @@ use roc_types::subs::{
AliasVariables, Descriptor, ErrorTypeContext, FlatType, GetSubsSlice, Mark, OptVariable,
RecordFields, Subs, SubsIndex, SubsSlice, UnionTags, Variable, VariableSubsSlice,
};
use roc_types::types::{ErrorType, Mismatch, RecordField};
use roc_types::types::{AliasKind, ErrorType, Mismatch, RecordField};
macro_rules! mismatch {
() => {{
if cfg!(debug_assertions) && std::env::var("ROC_PRINT_MISMATCHES").is_some() {
if cfg!(debug_assertions) && std::env::var("ROC_PRINT_MISMATCHES").is_ok() {
println!(
"Mismatch in {} Line {} Column {}",
file!(),
@ -205,7 +205,9 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
Structure(flat_type) => {
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),
Alias(symbol, args, real_var, kind) => {
unify_alias(subs, pool, &ctx, *symbol, *args, *real_var, *kind)
}
&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!
@ -294,17 +296,26 @@ fn unify_alias(
symbol: Symbol,
args: AliasVariables,
real_var: Variable,
kind: AliasKind,
) -> Outcome {
let other_content = &ctx.second_desc.content;
let either_is_opaque =
kind == AliasKind::Opaque || matches!(other_content, Alias(_, _, _, AliasKind::Opaque));
match other_content {
FlexVar(_) => {
// Alias wins
merge(subs, ctx, Alias(symbol, args, real_var))
merge(subs, ctx, Alias(symbol, args, real_var, kind))
}
RecursionVar { structure, .. } if !either_is_opaque => {
unify_pool(subs, pool, real_var, *structure, ctx.mode)
}
RecursionVar { structure, .. } => unify_pool(subs, pool, real_var, *structure, ctx.mode),
RigidVar(_) => unify_pool(subs, pool, real_var, ctx.second, ctx.mode),
Alias(other_symbol, other_args, other_real_var) => {
Alias(other_symbol, other_args, other_real_var, _)
// Opaques types are only equal if the opaque symbols are equal!
if !either_is_opaque || symbol == *other_symbol =>
{
if symbol == *other_symbol {
if args.len() == other_args.len() {
let mut problems = Vec::new();
@ -334,8 +345,8 @@ fn unify_alias(
unify_pool(subs, pool, real_var, *other_real_var, ctx.mode)
}
}
Structure(_) => unify_pool(subs, pool, real_var, ctx.second, ctx.mode),
RangedNumber(other_real_var, other_range_vars) => {
Structure(_) if !either_is_opaque => unify_pool(subs, pool, real_var, ctx.second, ctx.mode),
RangedNumber(other_real_var, other_range_vars) if !either_is_opaque => {
let outcome = unify_pool(subs, pool, real_var, *other_real_var, ctx.mode);
if outcome.is_empty() {
check_valid_range(subs, pool, real_var, *other_range_vars, ctx.mode)
@ -344,6 +355,11 @@ fn unify_alias(
}
}
Error => merge(subs, ctx, Error),
other => {
// The type on the left is an alias, but the one on the right is not!
debug_assert!(kind != AliasKind::Opaque);
mismatch!("Cannot unify opaque {:?} with {:?}", symbol, other)
}
}
}
@ -409,11 +425,20 @@ fn unify_structure(
// Unify the two flat types
unify_flat_type(subs, pool, ctx, flat_type, other_flat_type)
}
Alias(_, _, real_var) => {
// NB: not treating this as a presence constraint seems pivotal! I
// can't quite figure out why, but it doesn't seem to impact other types.
unify_pool(subs, pool, ctx.first, *real_var, ctx.mode.as_eq())
}
Alias(sym, _, real_var, kind) => match kind {
AliasKind::Structural => {
// NB: not treating this as a presence constraint seems pivotal! I
// can't quite figure out why, but it doesn't seem to impact other types.
unify_pool(subs, pool, ctx.first, *real_var, ctx.mode.as_eq())
}
AliasKind::Opaque => {
mismatch!(
"Cannot unify structure {:?} with opaque {:?}",
&flat_type,
sym
)
}
},
RangedNumber(other_real_var, other_range_vars) => {
let outcome = unify_pool(subs, pool, ctx.first, *other_real_var, ctx.mode);
if outcome.is_empty() {
@ -1127,7 +1152,7 @@ fn unify_shared_tags_merge_new(
#[allow(dead_code)]
fn is_structure(var: Variable, subs: &mut Subs) -> bool {
match subs.get_content_without_compacting(var) {
Content::Alias(_, _, actual) => is_structure(*actual, subs),
Content::Alias(_, _, actual, _) => is_structure(*actual, subs),
Content::Structure(_) => true,
_ => false,
}
@ -1343,7 +1368,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(_, _, _) | RangedNumber(..) => {
RigidVar(_) | RecursionVar { .. } | Structure(_) | Alias(_, _, _, _) | RangedNumber(..) => {
if !ctx.mode.contains(Mode::RIGID_AS_FLEX) {
// Type mismatch! Rigid can only unify with flex, even if the
// rigid names are the same.
@ -1377,7 +1402,7 @@ fn unify_flex(
| RigidVar(_)
| RecursionVar { .. }
| Structure(_)
| Alias(_, _, _)
| Alias(_, _, _, _)
| RangedNumber(..) => {
// TODO special-case boolean here
// In all other cases, if left is flex, defer to right.
@ -1431,7 +1456,15 @@ fn unify_recursion(
},
),
Alias(_, _, actual) => {
Alias(opaque, _, _, AliasKind::Opaque) => {
mismatch!(
"RecursionVar {:?} cannot be equal to opaque {:?}",
ctx.first,
opaque
)
}
Alias(_, _, actual, _) => {
// look at the type the alias stands for
unify_pool(subs, pool, ctx.first, *actual, ctx.mode)