Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/empty-record-mutable-generalize.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Stop generalizing the type of an empty record literal `{}` whose record has a mutable field, which let a value be stored at one type and read at another.
9 changes: 8 additions & 1 deletion compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2095,7 +2095,14 @@ let rec is_nonexpansive exp =
| None -> (
(* The optional fields the literal leaves out are allocated too *)
match fields with
| [||] -> true
| [||] -> (
(* [{}] has no field to find the record's labels through *)
match extract_concrete_record exp.exp_env exp.exp_type with
| _, _, decls, _ ->
List.for_all
(fun (ld : Types.label_declaration) -> ld.ld_mutable = Immutable)
decls
| exception Not_found -> false)
| _ ->
let lbl, _, _ = fields.(0) in
Array.for_all (fun lbl -> lbl.lbl_mut = Immutable) lbl.lbl_all))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

We've found a bug for you!
/.../fixtures/record_empty_mutable_does_not_generalize.res:10:25-34

8 │ let cell: cell<_> = {}
9 │ cell.value = Some(1)
10 │ let s: option<string> = cell.value
11 │

This has type: option<int>
But it's expected to have type: option<string>

The incompatible parts:
int vs string

You can convert int to string with Int.toString.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// An immutable record still generalizes.
type options<'a> = {value?: 'a}
let defaults: options<_> = {}
let ints: options<int> = defaults
let strings: options<string> = defaults

type cell<'a> = {tag?: int, mutable value?: 'a}
let cell: cell<_> = {}
cell.value = Some(1)
let s: option<string> = cell.value
Loading