RFC-0123 field-wise row constraints were incomplete
Limitation
where all R: Aspect parses (all is contextual, not reserved) and is enforced where it
is written: on an extend whose target is { ..R } (the impl applies to a record only
when every field satisfies the aspect, through method calls and T: A bounds, for
anonymous and nominal records) and on a function whose parameter has an open-row tail
({ x, ..R }, a struct-residual tail, and the Rest of a where R = { .., ..Rest }
decomposition), where every field of the argument beyond the ones the parameter names must
satisfy each aspect, else T0012 names the field.
fun consume<row R>(r: { id: i64, ..R }) -> i64 where all R: Copy { r.id }
consume({ id = 1, label = "x".to_string() }); // T0012: field `label` ... does not implement `Copy`
The completed implementation also carries this entitlement into generic bodies. Since
RFC-0179 a by-value open-row parameter owns its whole argument, so a body over an
unconstrained <row R> may pass such a row on with no bound
(spec.types.generics.open-rows.legality-3); where all R: Copy is only needed to use the
row more than once. The entitlement applies to the row's fields, not to R as a whole. Other impl targets and a row generic not used as a
parameter tail remain rejected with T0012, rather than silently ignoring the constraint.
Impact
At the time, generic functions could narrow an unknown row and only fail when a caller
instantiated the body with a non-Copy field. The completed implementation checks the
generic body against its declared field-wise entitlement instead.
Affects
Resolution
Resolved by metel-core#1302 with RFC-0173's completed generic-body checking
(metel-core#1364). Fixtures cover both the rejected unconstrained body and the accepted
where all R: Copy form.