-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Motivation
Currently, using & uses the ref result location. This causes type information to be lost, which, as of #16163 landing, has meaningful effects on the language. First, consider this code snippet:
const S = struct { x: u32 };
const s: S = .{ .x = @intCast(val) };This already works fine. The result type of S is forwarded to the struct init expression, which forwards field types onto each field init expression. Now, consider this (very similar) line:
const s: *const S = &.{ .x = @intCast(val) };This currently fails to compile. The use of & means the struct init expression uses a ref result type, so has no type information to forward onto the field init expression. This means you either need to write &S{ ... }, or use @as to specify the field type.
Copy elision is also important here. Consider the following:
const T = struct { inner: struct { x: u32 } };
const t: *const T = &.{ .inner = .{ .x = 123 } };Here, since there is not a known result type for the init expression, a copy of the inner struct cannot be avoided. The inner initialization is evaluated, then the result copied into the outer anon struct, which is then coerced to the correct type (potentially causing yet another copy).
Proposal
I'm going to explain this in terms of implementation details, because I think it's relatively easy to understand and is important to consider.
Introduce new result locations for typed refs. More specifically, expand AstGen.ResultInfo.Loc to add the following locations:
/// A pointer to the expression must be generated rather than the expression value itself.
/// The pointer child type (that is, the type of the expression) must be the provided type.
ref_ty: Zir.Inst.Ref,When &a has a result location of .{ .ty = T }, a has a result location of .{ .ref_ty = S } where S is found through a new ptr_child ZIR instruction. This is made a little more complicated by slices, because if T is a []Foo, we cannot make S a concrete type, as it may be any [n]Foo. This can be solved by introducing an internal "unknown length array" type which ptr_child can return for slices. Care should be taken to avoid this fake type from leaking into other parts of the compiler.
Error Messages
Aside from helping with cast builtins and copy elision as already discussed, this proposal has an additional benefit of improving error messages. RLS can improve errors because field inits become individual pointer writes, so type errors are caught at the point of a field initialization rather than at the point of type coercion. #16508 details an error message which would be improved by this change.
Bonus Proposal: Removing Anonymous Struct Types
EDIT: moved to #16865