-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stage2: more optionals stuff #6060
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, this is substantial progress :)
src-self-hosted/astgen.zig
Outdated
@@ -452,6 +453,12 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr | |||
return addZIRUnOp(mod, scope, src, .boolnot, operand); | |||
} | |||
|
|||
fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | |||
const tree = scope.tree(); | |||
const src = tree.token_locs[node.op_token].start; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused tree
and src
node.ptr_info.sentinel == null; | ||
|
||
if (simple) { | ||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this line and 494 can be moved up to above this branch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was planning on putting 494 after all the other attributes so that they would get analyzed in the order that they appear in the source but I couldn't figure how to pass child_type
to the sentinel cast result loc. If the order is not important then I'll just move it before the shortcut.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh that makes sense. Never mind my review comment then!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would still depend on being able to refer to the child type before the sentinel which doesn't seem possible but all the other attributes before the child type would still be an improvement.
node.ptr_info.volatile_token == null and | ||
node.ptr_info.sentinel == null; | ||
|
||
if (simple) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how you did this 👍
@@ -107,6 +107,17 @@ pub const Type = extern union { | |||
return @fieldParentPtr(T, "base", self.ptr_otherwise); | |||
} | |||
|
|||
pub fn castPointer(self: Type) ?*Payload.Pointer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like Type.zig and Value.zig might benefit from being reworked into following the pattern set by std.zig.ast, ZIR, and IR with the castTag
function (and the preference to use that function rather than the one that accepts the type parameter). This pattern has been working nicely elsewhere to make multiple tags map to the same payload type.
src-self-hosted/zir_sema.zig
Outdated
try mod.singleConstPtrType(scope, unwrap.base.src, child_type) | ||
else | ||
try mod.singleMutPtrType(scope, unwrap.base.src, child_type); | ||
var buf: Type.Payload.Pointer = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a reference to buf
is escaping this function.
I think this would be fixed simply by allocating buf
with scope.arena()
. Possibly as an optimization, Type.zig could have another function for accepting an allocator that would only allocate buf if it needed to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The resulting child type is immediately copied but an optionalChildAlloc
would be more explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! I see the copy. This actually is a really nice API. I like what you did here 👍
src-self-hosted/Module.zig
Outdated
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); | ||
} | ||
|
||
// TODO how do we get the result location |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need a pointer to write through, you would emit an alloc
instruction. However, for cases where it could be treated as a value (such as here) I think what you have here is better. Since the zig language does not guarantee a memory layout for optionals, that means codegen.zig is allowed to represent the optional value in any way it chooses to. For some combinations of architectures and payload types, this may mean that it uses a single register to represent both the optional bit and the payload. I think it makes sense to make Module.zig / zir_sema.zig not have to care about such details.
src-self-hosted/codegen.zig
Outdated
@@ -2004,9 +2023,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | |||
return mcv; | |||
} | |||
|
|||
fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) !MCValue { | |||
fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) error{ CodegenFail, OutOfMemory }!MCValue { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) error{ CodegenFail, OutOfMemory }!MCValue { | |
fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) InnerError!MCValue { |
src-self-hosted/astgen.zig
Outdated
if (cond_kind != .optional) { | ||
return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The presence of a payload capture here would make this an error union if (same deal with while
below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that documented anywhere? I think it might be better to require the explicit |_|
since that already seems to be more common.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm maybe I'm misunderstanding what the code is doing here. I'm thinking about this:
https://ziglang.org/documentation/master/#while-with-Error-Unions
When the else |x| syntax is present on a while expression, the while condition must have an Error Union Type.
What would be example zig code that would trigger this "else payload invalid on bool conditions" compile error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (errUnion) {} else |err| {} // else payload invalid on bool conditions
if (errUnion) |_| {} else |err| {} // explicitly ignoring the payload
Looking at the stdlib and tests explicitly ignoring the payload seems more common but that might be just people (like me) not realizing that it isn't necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhh now I see. Hmm. Here's my proposal:
if (errUnion) {} else |err| {}
on E!T
where T
is void
should be allowed, but if T
is not void
then it should be "error: expression value is ignored" same as if you called a non-void function and didn't capture or discard the return value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me!
src-self-hosted/astgen.zig
Outdated
const payload = payload_node.?.castTag(.PointerPayload).?; | ||
const is_ptr = payload.ptr_token != null; | ||
const ident_node = payload.value_symbol.castTag(.Identifier).?; | ||
const ident_name = try identifierTokenString(mod, &then_scope.base, ident_node.token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Elsewhere in stage2 we've treated _
as the "discard" identifier, but @"_"
as a normal identifier. Personally I could be persuaded to do it either way, but it should probably be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't realize this was a thing. Should we try to somehow also apply it to primitive types to fix #1802?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a neat idea! Let's do a separate proposal for that, but I think it might be a good solution to the "sometimes we want to use names that collide with primitive types" problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is just pending tests passing now
No description provided.