Skip to content
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

Merged
merged 5 commits into from
Aug 17, 2020
Merged

Stage2: more optionals stuff #6060

merged 5 commits into from
Aug 17, 2020

Conversation

Vexu
Copy link
Member

@Vexu Vexu commented Aug 15, 2020

No description provided.

Copy link
Member

@andrewrk andrewrk left a 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 :)

@@ -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;
Copy link
Member

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);
Copy link
Member

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

Copy link
Member Author

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.

Copy link
Member

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!

Copy link
Member Author

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) {
Copy link
Member

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 {
Copy link
Member

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.

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;
Copy link
Member

@andrewrk andrewrk Aug 15, 2020

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.

Copy link
Member Author

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.

Copy link
Member

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 👍

return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
}

// TODO how do we get the result location
Copy link
Member

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.

@@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) error{ CodegenFail, OutOfMemory }!MCValue {
fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) InnerError!MCValue {

Comment on lines 643 to 645
if (cond_kind != .optional) {
return mod.failNode(scope, payload, "else payload invalid on bool conditions", .{});
}
Copy link
Member

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)

Copy link
Member Author

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.

Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me!

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);
Copy link
Member

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.

Copy link
Member Author

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?

Copy link
Member

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.

Copy link
Member

@andrewrk andrewrk left a 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants