Change grammar to require or disallow types on fields for different containers#32
Change grammar to require or disallow types on fields for different containers#32mattbork wants to merge 5 commits into
Conversation
ifreund
left a comment
There was a problem hiding this comment.
The first commit here should definitely be merged as it brings the grammar back in sync with the implementation.
I'm not yet sure whether splitting the current ContainerField/ContainerMembers by container type is the right approach to take though. What we need to consider here is whether the overall complexity of the compiler implementation will be reduced or increased by this change. Right now, I'm pretty sure it would be increased as what is currently a single code path in the parser would be split into 4. Also, none of the errors that would be caught during parsing with this grammar change would make it past the new zig ast-check command, so I don't think catching them earlier is beneficial enough to justify this change. Furthermore, error messages generated during astgen are usually better as they have more context available.
… and unions with explicit tags, and add new test for invalid fields
|
For the sake of seeing all the required changes at once, I've now accounted for the differences between bare unions (must have types), unions with implicit tags (can have tag assignments and omit types), and unions with explicit tags (can omit type but must not have tag assignments). There are now five different |
|
Having thought about this a bit more the past few days, I don't think that differentiating between container types in the grammar makes sense for the zig compiler implementation. Compared to the status quo it would cause a significant increase in code duplication in the parser and zig fmt. The behavioral impact would be that some compile errors would be moved from astgen to parsing, but no new compile error messages would be possible and the quality of the error messages would be, if anything, reduced. Due to the fact that we now have a On the other hand, we definitely do want the change to disallow declarations between fields in the grammar merged. It's up to you @mattbork how to extract that from the rest of these changes, closing this PR and opening a new one might be simplest. |
|
I'll be happy to close this and open a new one for just the field and declaration split. My one concern, having looked at parse.zig more, is how this affects recovery on parsing errors. Currently, after an error in a |
|
I'm not sure I understand your concern, splitting Recovery for the const Foo = struct {
a: u32,
const x = 42;
b: u32,
const y = 42..;
}; |
|
You're right, there's no need to split Because Thanks for all the feedback. After I make a PR for the grammar changes here, I'll give the parse.zig changes a try. I am confused though why I can't get multiple errors after a declaration between fields, on my Windows machine or on godbolt. The only thing I can think of is that zig nightly and the trunk zig on godbolt are compiled without logging enabled? |
|
We don't necessarily need to make any changes to the code in
Hmm, not sure what's going on here, does the test case I used above not work for you? I can add as many copies of the |
|
Okay, that makes sense. The error recovery is definitely clearer when declarations and fields are handled in one function.
It doesn't. In fact, no errors anywhere in the file are reported after the first. I would have assumed this was a problem on my end, but again Compiler Explorer has the same behavior and on 0.7.1 and older as well on trunk. |
|
Oh I'm pretty sure I know whats happening here, I'm testing the self hosted |
|
Ok, good to know there's nothing wrong. I haven't looked at the stage1 parser much and assumed it did the same recovery. Thanks! |
The grammar should be more specific about what kind of fields a container allows. struct and untagged union containers should mandate types for fields, whereas tagged union containers may omit the type. Further, enum containers should not allow types for fields at all. Examples:
This requires separating
ContainerMembersfrom the newEnumMembersandTaggedUnionMembersnonterminals. To reduce duplication, container declarations are first pulled out into a new nonterminal,ContainerDeclarations. This also allows making the mixing of declarations in between container fields a parse error: all containers have a possibly empty prefix of declarations, followed by a possibly empty list of fields, followed by a possibly empty suffix of declarations.All tests (expecting the
invalid_ones) pass except for async_fn.zig, which was already failing before these changes.