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

Track params in the parser #4777

Merged
merged 9 commits into from
Jan 10, 2025
Merged

Conversation

geoffromer
Copy link
Contributor

@geoffromer geoffromer commented Jan 8, 2025

This change splits NodeKind::IdentifierName into separate node kinds depending on whether the identifier is followed by parameters, and similarly splits NameQualifier based on whether the qualifier has parameters. This enables us to only push a pattern block when it's actually needed, rather than "defensively" pushing one when it might be needed.

@github-actions github-actions bot requested a review from danakj January 8, 2025 22:27
@jonmeow
Copy link
Contributor

jonmeow commented Jan 9, 2025

Just glancing, did you notice this is regressing the diagnostic location? i.e., before it pointed at parameters:

// CHECK:STDERR: fail_params.carbon:[[@LINE+7]]:8: error: `alias` declaration cannot have parameters [UnexpectedDeclNameParams]
// CHECK:STDERR: alias A(T:! type) = T*;
// CHECK:STDERR:        ^~~~~~~~~~

Now it points at the node after the parameters (and doesn't explain why this name can't have parameters):

// CHECK:STDERR: fail_params.carbon:[[@LINE+3]]:19: error: unexpected parameters after name declaration [UnexpectedParamsAfterDeclName]
// CHECK:STDERR: alias A(T:! type) = T*;
// CHECK:STDERR:                   ^

Also, the PR description is empty, should it have a little more detail about what's changing (and motivation)? e.g., it looks like you're adding node kinds, maybe the PR could explain the approach?

@jonmeow
Copy link
Contributor

jonmeow commented Jan 9, 2025

I should also note, #3988 had moved validation from parse to check in order to get more uniform handling. It might be good to explain how the changes there are adapted here in that context, particularly since this is changing diagnostics (are incorrectly placed parameters ever diagnosed in check after this change?)

edit: something like fn NS(x: I32).F() probably needs to be handled in check. But do you have tests for something like

// This needs to be handled in check.
fn NS(x: i32).F() {}

// And we'll probably have static vars, like:
class C(T:! type) {
  static var x: i32;
}
var C(T:! type).x = i32;

// Is the parse approach going to be able to reject incorrect params in this syntax?
var C(T:! type).x() = i32;

(also, alias may get params, I think that's not yet truly decided)

Copy link
Contributor

@danakj danakj left a comment

Choose a reason for hiding this comment

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

Thanks for looking as well Jon, this is definitely a challenging review for my first auto-assignment 😆

The IdentifierNameNotBeforeParams and IdentifierNameBeforeParams change seems nice, in that its making check a little more straightforward. Given the convo above, I am not sure about the DeclNameAndParams part of the change though, as it seems to be limiting things a bit more than it should? Are these two tired together necessarily? That's hard for me to tell, but it might be nice to just do the IdentifierNameNotBeforeParams part of the PR independently, if that doesn't change how diagnostics are being reported, and then it'll be easier to think about the other part.

toolchain/check/name_component.cpp Outdated Show resolved Hide resolved
toolchain/check/name_component.cpp Outdated Show resolved Hide resolved
toolchain/parse/state.def Outdated Show resolved Hide resolved
@jonmeow
Copy link
Contributor

jonmeow commented Jan 9, 2025

np, happy to look.

Also, @geoffromer, I think you need to re-add tests of how this behaves in check. The parse tree still contains the pattern, so it needs to be correctly handled (i.e., as currently implemented, the pattern block still neds to be pushed). I'm actually not sure that this change is removing the need for any of the work being done in check. (it may be that the TODOs are incorrect as a consequence -- the logic in check may need to stay)

@jonmeow
Copy link
Contributor

jonmeow commented Jan 9, 2025

I'm actually not sure that this change is removing the need for any of the work being done in check. (it may be that the TODOs are incorrect as a consequence -- the logic in check may need to stay)

Oh, I think I'm understanding part of this now. You're using the different parse node to only push a param block for when there's a pattern. Regardless, I think that still needs to be tested -- we need to make sure we aren't crashing on invalid code.

@geoffromer geoffromer changed the title Disallow params in the parser, where appropriate Track params in the parser Jan 9, 2025
Copy link
Contributor Author

@geoffromer geoffromer left a comment

Choose a reason for hiding this comment

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

The IdentifierNameNotBeforeParams and IdentifierNameBeforeParams change seems nice, in that its making check a little more straightforward. Given the convo above, I am not sure about the DeclNameAndParams part of the change though, as it seems to be limiting things a bit more than it should? Are these two tired together necessarily? That's hard for me to tell, but it might be nice to just do the IdentifierNameNotBeforeParams part of the PR independently, if that doesn't change how diagnostics are being reported, and then it'll be easier to think about the other part.

Oh, that's a good idea. Yes, they do turn out to be separable, so I've removed the DeclNameAndParams parts from this PR. I think that makes the other top-level comments moot, but let me know if I've missed anything.

Note that this means that this PR no longer resolves those TODOs as stated, but still removes them. I'm going to seek clarification on Discord about whether the folks who asked for them still want another PR with the parser diagnostic changes.

toolchain/check/name_component.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@danakj danakj left a comment

Choose a reason for hiding this comment

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

A couple questions to help me understand

// to be followed by parameters.
using IdentifierNameBeforeParams =
LeafNode<NodeKind::IdentifierNameBeforeParams, Lex::IdentifierTokenIndex,
NodeCategory::MemberName | NodeCategory::NonExprIdentifierName>;
Copy link
Contributor

Choose a reason for hiding this comment

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

How come IdentifierName was not NodeCategory::NonExprIdentifierName before, but this is now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That category didn't exist before; I introduced it in this PR in order to use AnyNonExprIdentifierName to talk about identifiers when we don't care whether they're followed by parameters.

Ideally I would have called this category IdentifierName, like the thing it's replacing, but my concern was that AnyIdentifierName sounds like it would encompass IdentifierNameExpr, so I went with a more specific name. I also considered adding NonExpr to the names of these two node types, but I just couldn't stomach the verbosity of e.g. NonExprIdentifierNameNotBeforeParams.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, one thing to mull might be if IdentifierNameExpr could actually be NameRef (since it looks like it's always translated to SemIR::NameRef), which might avoid the ambiguity of this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True, although SemIR::NameRefs can also be created from other node kinds, so they don't line up perfectly. Definitely an option to consider, though.

@@ -252,18 +253,16 @@ TEST_F(TypedNodeTest, VerifyExtractTraceClassDecl) {
EXPECT_THAT(err.message(), testing::MatchesRegex(
R"Trace(Aggregate [^:]*: begin
Aggregate [^:]*: begin
Aggregate [^:]*: begin
Copy link
Contributor

Choose a reason for hiding this comment

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

What makes this go away? (Not really sure what to make of these tests yet..)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Honestly, I have no idea; I don't really understand this test. I just took the failing test result, pasted the actual output back into the code, and replaced the mangled type names with regexes.

Copy link
Contributor

@jonmeow jonmeow Jan 10, 2025

Choose a reason for hiding this comment

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

I think before, NameAndParams existed as a member aggregate. It's gone without a replacement [ed: not an aggregate one anyways].

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.

Generally looks good, and as mentioned I think it makes sense to keep the param validation in check.

Just some minor questions, but these changes generally look good to me.

toolchain/parse/handle_binding_pattern.cpp Outdated Show resolved Hide resolved
toolchain/parse/typed_nodes.h Show resolved Hide resolved
toolchain/parse/typed_nodes.h Outdated Show resolved Hide resolved
toolchain/parse/node_ids.h Outdated Show resolved Hide resolved
toolchain/parse/handle_expr.cpp Outdated Show resolved Hide resolved
toolchain/parse/handle_period.cpp Outdated Show resolved Hide resolved
toolchain/parse/handle_period.cpp Outdated Show resolved Hide resolved
toolchain/check/name_component.cpp Outdated Show resolved Hide resolved
@geoffromer geoffromer requested review from jonmeow and danakj January 10, 2025 19:08
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.

Thanks, this looks good!

@geoffromer geoffromer enabled auto-merge January 10, 2025 20:59
@geoffromer geoffromer added this pull request to the merge queue Jan 10, 2025
Merged via the queue into carbon-language:trunk with commit 4f10735 Jan 10, 2025
8 checks passed
@geoffromer geoffromer deleted the pattern-parse branch January 10, 2025 23:29
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.

4 participants