I remember discussing this a while ago. I thought I had an issue open somewhere for this but I guess not.
It's currently not allowed to use FRU (functional record update) syntax to return a transformed type, i.e.:
struct Foo<T> {
val: T,
tag: &'static str,
}
impl<T> Foo<T> {
fn transform<U>(self, val: U) -> Foo<U> {
Foo { val: val, .. self }
}
}
will throw a "mismatched type" error with the span of self in the FRU literal because it is of type Foo<T> and not Foo<U>, even though the remaining fields of self are compatible.
According to RFC 736, FRU is supposed to be just syntactic sugar for a full struct literal, but a full struct literal works in this case because it doesn't place any restriction on the type of self.
Possible solutions:
-
Move fields nominally (foo: <tail expr>.foo, bar: <tail expr>.bar, etc.) and typecheck them individually, not typechecking the tail expression at all. This could allow FRU to work even between otherwise incompatible types which have compatible fields. I like this one more but it may be too implicit for some, and I gather that we don't want to add too much meaning to field names.
-
Only check equality of the outermost type constructor between the FRU literal and the tail expression, i.e. check that Foo<T> ~= Foo<U>; then, typecheck the moved fields individually. This would allow the above use-case but disallow using an entirely different type as the source or destination.
As far as I understand it, this should be backwards-compatible since it would strictly allow more code to compile.
Edit: clarify generic params
I remember discussing this a while ago. I thought I had an issue open somewhere for this but I guess not.
It's currently not allowed to use FRU (functional record update) syntax to return a transformed type, i.e.:
will throw a "mismatched type" error with the span of
selfin the FRU literal because it is of typeFoo<T>and notFoo<U>, even though the remaining fields ofselfare compatible.According to RFC 736, FRU is supposed to be just syntactic sugar for a full struct literal, but a full struct literal works in this case because it doesn't place any restriction on the type of
self.Possible solutions:
Move fields nominally (
foo: <tail expr>.foo,bar: <tail expr>.bar, etc.) and typecheck them individually, not typechecking the tail expression at all. This could allow FRU to work even between otherwise incompatible types which have compatible fields. I like this one more but it may be too implicit for some, and I gather that we don't want to add too much meaning to field names.Only check equality of the outermost type constructor between the FRU literal and the tail expression, i.e. check that
Foo<T> ~= Foo<U>; then, typecheck the moved fields individually. This would allow the above use-case but disallow using an entirely different type as the source or destination.As far as I understand it, this should be backwards-compatible since it would strictly allow more code to compile.
Edit: clarify generic params