Semantic Diff

#9152 Treat an empty record literal with mutable fields as expansive

1 commit

940b7617e87f4cab57e27b003bba4c274afdb363..pr-9152

d0537fc9f · cknitt + Claude · Oct 31, 2026, 08:21 UTC

Treat an empty record literal with mutable fields as expansive

Why

The value restriction looks for mutable fields among a record literal's entries, but {} of an all-optional record has none, so it was always non-expansive and its type variables were generalized even when a field is mutable (#9150). It now looks up the record's declaration and requires every field to be immutable.

addedDiagnostic empty record literal with a mutable field

type cell<'a> = {tag?: int, mutable value?: 'a}let cell: cell<_> = {}cell.value = Some(1)let s: option<string> = cell.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 {} of an immutable record still generalize? Yes; the super_errors fixture uses one such value at both option<int> and option<string> before reaching the error.