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

Parsing impl...as #3473

Merged
merged 20 commits into from
Dec 9, 2023
Merged

Parsing impl...as #3473

merged 20 commits into from
Dec 9, 2023

Conversation

josh11b
Copy link
Contributor

@josh11b josh11b commented Dec 7, 2023

No description provided.

toolchain/parse/handle_impl.cpp Outdated Show resolved Hide resolved
auto state = context.PopState();
if (state.has_error) {
context.ReturnErrorOnState();
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

In this state, you've encountered a forall token. Why do you return here instead of letting the AddNode call occur, adding a parse node for the error token?

(note too, with the return, using state.has_error below is equivalent to /*has_error=*/false, which might be clearer)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm pretty uncertain about how to handle errors in the parser, could you perhaps suggest some code? I'm particularly uncertain about what can be assumed if state.has_error is true. When I try moving the context.AddNode call before the if (state.has_error), I get a parse validation error since the ImplForall node is missing its expected child. I assume filling in the missing child is what you mean by "adding a parse node for the error token"? I took a stab at it, but I'm not sure what is expected here. I also deleted the return; on error, but that is just a guess.

It would be really helpful to add a section to https://docs.google.com/document/d/1RRYMm42osyqhI2LyjrjockYCutQ5dOf8Abu50kTrkX0/edit?resourcekey=0-kHyqOESbOHmzZphUbtLrTw#heading=h.d6o1d67xs8xu about what to do about errors in the parse stage:

  • what does state.has_error mean? when should it be set? what can you assume when it has been set by another function? how should you handle it?
  • what invariants need to be maintained when there are errors?
  • what are common patterns?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd meant just dropping the return.

I'd expected though that ParamListAsImplicit would always add a node, even in error cases. That may be a consistency issue. You adding an InvalidParse node is an unintended workaround.

Anyways, current state is fine, though it's probably worth someone (maybe me) changing ParamList behavior there.

Regarding the rest, jotted down some notes: https://docs.google.com/document/d/1RRYMm42osyqhI2LyjrjockYCutQ5dOf8Abu50kTrkX0/edit?resourcekey=0-kHyqOESbOHmzZphUbtLrTw#heading=h.f0xq7he13pm

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Based on the observed behavior in the test, it seems that ParamListAsImplicit sets error == true on the parent state if it did not output a node. If ParamListAsImplicit does output a node, that node has the error state set to true, but the parent state is left alone.

toolchain/parse/node_kind.def Show resolved Hide resolved
toolchain/parse/node_kind.def Outdated Show resolved Hide resolved
toolchain/parse/node_kind.def Outdated Show resolved Hide resolved
toolchain/parse/state.def Outdated Show resolved Hide resolved
toolchain/parse/state.def Show resolved Hide resolved
toolchain/parse/tree.cpp Outdated Show resolved Hide resolved
toolchain/parse/handle_impl.cpp Outdated Show resolved Hide resolved

default:
context.PushState(State::ImplAs);
context.PushStateForExpr(PrecedenceGroup::ForImplAs());
Copy link
Contributor

Choose a reason for hiding this comment

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

I was expecting to see ForType here. Do we intend to have different rules for the type operands of impl T1 as T2 than for let x: T1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried ForType, but that is currently defined as equivalent to ForTopLevelExpr(), which means it will include the as afterwards.

Comment on lines 50 to 56
if (context.PositionKind() == Lex::TokenKind::As) {
context.AddLeafNode(NodeKind::ImplAs, context.Consume());
context.PushState(State::Expr);
} else {
context.PushState(State::ImplAs);
context.PushStateForExpr(PrecedenceGroup::ForImplAs());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this share code with HandleImplAfterIntroducer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

@jonmeow jonmeow left a comment

Choose a reason for hiding this comment

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

Looks good!

toolchain/parse/handle_impl.cpp Outdated Show resolved Hide resolved
toolchain/parse/handle_impl.cpp Outdated Show resolved Hide resolved
toolchain/parse/node_kind.def Show resolved Hide resolved
auto state = context.PopState();
if (state.has_error) {
context.ReturnErrorOnState();
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd meant just dropping the return.

I'd expected though that ParamListAsImplicit would always add a node, even in error cases. That may be a consistency issue. You adding an InvalidParse node is an unintended workaround.

Anyways, current state is fine, though it's probably worth someone (maybe me) changing ParamList behavior there.

Regarding the rest, jotted down some notes: https://docs.google.com/document/d/1RRYMm42osyqhI2LyjrjockYCutQ5dOf8Abu50kTrkX0/edit?resourcekey=0-kHyqOESbOHmzZphUbtLrTw#heading=h.f0xq7he13pm

@josh11b
Copy link
Contributor Author

josh11b commented Dec 9, 2023

FYI, I had to make some changes after merging. The trickiest one is now that impl is parsed, check_fuzzer started executing some new unimplemented interface code paths.

@josh11b josh11b added this pull request to the merge queue Dec 9, 2023
Merged via the queue into carbon-language:trunk with commit 5f439b8 Dec 9, 2023
6 checks passed
@josh11b josh11b deleted the impl branch December 9, 2023 04:19
josh11b added a commit to josh11b/carbon-lang that referenced this pull request Dec 9, 2023
@jonmeow
Copy link
Contributor

jonmeow commented Dec 11, 2023

LGTM, todo's seem reasonable for that.

github-merge-queue bot pushed a commit that referenced this pull request Dec 11, 2023
I think this matches expectations about how the parse code should be
structured better.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants