mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Error reporting for type mismatches involving opaques
This commit is contained in:
parent
822e38d026
commit
059c324268
20 changed files with 526 additions and 149 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue