Treat a record spread that copies mutable fields as expansive
Why
The value restriction checked only the fields a spread literal writes, so {...base, tag: 1} was non-expansive even when it copied a mutable field from base, and its type was generalized (#9156). A record literal allocates every field of its type, whether written, copied from the spread or left out, so the check now requires all of them to be immutable, with or without a spread.
addedDiagnostic record spread copying a mutable field
type cell<'a> = {tag: int, mutable value: option<'a>}@val external base: cell<'a> = "base"let copy = {...base, tag: 1}copy.value = Some(1)let s: option<string> = copy.value
diagnostic
Before
After
none; `s` holds the number 1 at run time This has type: option<int>But it's expected to have type: option<string> The incompatible parts: int vs string
Review
- Does a spread of an immutable record still generalize? Yes; the super_errors fixture uses one at both option<int> and option<string> first.