Turn invalid record field types into runtime errors

By emitting a runtime error rather than panicking when we can't layout
a record, we help programs like

```
main =
    get = \{a} -> a
    get {b: "hello world"}
```

execute as

```
Mismatch in compiler/unify/src/unify.rs Line 1071 Column 13
Trying to unify two flat types that are incompatible: EmptyRecord ~ { 'a' : Demanded(122), }<130>

🔨 Rebuilding host...
── TYPE MISMATCH ───────────────────────────────────────────────────────────────

The 1st argument to get is not what I expect:

8│      get {b: "hello world"}
            ^^^^^^^^^^^^^^^^^^

This argument is a record of type:

    { b : Str }

But get needs the 1st argument to be:

    { a : a }b

Tip: Seems like a record field typo. Maybe a should be b?

Tip: Can more type annotations be added? Type annotations always help
me give more specific messages, and I think they could help a lot in
this case

────────────────────────────────────────────────────────────────────────────────

'+fast-variable-shuffle' is not a recognized feature for this target (ignoring feature)
'+fast-variable-shuffle' is not a recognized feature for this target (ignoring feature)
Done!
Application crashed with message

    Can't create record with improper layout

Shutting down
```

rather than the hanging

```
Mismatch in compiler/unify/src/unify.rs Line 1071 Column 13
Trying to unify two flat types that are incompatible: EmptyRecord ~ { 'a' : Demanded(122), }<130>

thread '<unnamed>' panicked at 'invalid layout from var: UnresolvedTypeVar(104)', compiler/mono/s
rc/layout.rs:1510:52
```

that was previously produced.

Part of #2227
This commit is contained in:
ayazhafiz 2021-12-21 19:11:59 -06:00
parent e728e319c6
commit 576f1293fd
7 changed files with 96 additions and 51 deletions

View file

@ -3325,8 +3325,15 @@ pub fn with_hole<'a>(
mut fields,
..
} => {
let sorted_fields =
crate::layout::sort_record_fields(env.arena, record_var, env.subs, env.ptr_bytes);
let sorted_fields = match crate::layout::sort_record_fields(
env.arena,
record_var,
env.subs,
env.ptr_bytes,
) {
Ok(fields) => fields,
Err(_) => return Stmt::RuntimeError("Can't create record with improper layout"),
};
let mut field_symbols = Vec::with_capacity_in(fields.len(), env.arena);
let mut can_fields = Vec::with_capacity_in(fields.len(), env.arena);
@ -3678,8 +3685,15 @@ pub fn with_hole<'a>(
loc_expr,
..
} => {
let sorted_fields =
crate::layout::sort_record_fields(env.arena, record_var, env.subs, env.ptr_bytes);
let sorted_fields = match crate::layout::sort_record_fields(
env.arena,
record_var,
env.subs,
env.ptr_bytes,
) {
Ok(fields) => fields,
Err(_) => return Stmt::RuntimeError("Can't access record with improper layout"),
};
let mut index = None;
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
@ -3821,8 +3835,15 @@ pub fn with_hole<'a>(
// This has the benefit that we don't need to do anything special for reference
// counting
let sorted_fields =
crate::layout::sort_record_fields(env.arena, record_var, env.subs, env.ptr_bytes);
let sorted_fields = match crate::layout::sort_record_fields(
env.arena,
record_var,
env.subs,
env.ptr_bytes,
) {
Ok(fields) => fields,
Err(_) => return Stmt::RuntimeError("Can't update record with improper layout"),
};
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
@ -4378,11 +4399,7 @@ pub fn with_hole<'a>(
}
}
}
RuntimeError(e) => {
eprintln!("emitted runtime error {:?}", &e);
Stmt::RuntimeError(env.arena.alloc(format!("{:?}", e)))
}
RuntimeError(e) => Stmt::RuntimeError(env.arena.alloc(format!("{:?}", e))),
}
}
@ -7369,7 +7386,8 @@ fn from_can_pattern_help<'a>(
use crate::layout::UnionVariant::*;
let res_variant =
crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs, env.ptr_bytes);
crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs, env.ptr_bytes)
.map_err(Into::into);
let variant = match res_variant {
Ok(cached) => cached,
@ -7789,7 +7807,8 @@ fn from_can_pattern_help<'a>(
} => {
// sorted fields based on the type
let sorted_fields =
crate::layout::sort_record_fields(env.arena, *whole_var, env.subs, env.ptr_bytes);
crate::layout::sort_record_fields(env.arena, *whole_var, env.subs, env.ptr_bytes)
.map_err(Into::into)?;
// sorted fields based on the destruct
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);