Skip to content

Record coercion can turn an immutable field into a mutable one #9063

Closed

Description

@cristianoc

What happens

:> between record types accepts a target whose field is mutable when the source's field is not:

type ro = {x: float}
type rw = {mutable x: float}

let toRw = (r: ro) => (r :> rw)

compiles on master (1a49d91) to

function toRw(r) {
  return r;
}

So a value typed ro, whose x the type system treats as immutable, can be written through the coerced view:

let r: ro = {x: 0.}
let w = (r :> rw)
w.x = 1.   // compiles; r.x is now 1.

Where

Record_coercion.check_record_fields (compiler/ml/record_coercion.ml) compares field names, optionality and runtime names, and passes the field types on for subtyping; it does not compare mutability.

Expected

A coercion should not grant write access the source does not have: a mutable target field requires a mutable source field. Where both are mutable, the field type is read and written, so it has to be equal (invariant) rather than a subtype.

Activity

  1. added theissue type on Oct 27, 2026
  2. added a commit that references this issue on Oct 28, 2026
    beb423d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions