Handle var init-with-self situations. (#2488)

The problem I'm trying to solve is: `var x: i32 = x;`. This change makes it so that name lookup fails, by removing `x` from name lookup between the `=` and `;`.

`var x: i32` still adds to name lookup to handle future situations like `var (x: i32, x: i32);` which is still a redefinition of `x`; if we don't add `x` to name lookup, it gets harder to catch that example.

The VariableDeclaration/VariableInitializer refactor in ParseTree supports this by given a bracketing-like structure for semantics to cue that it's entering an initialization expression. With this, VariableInitializer can remove the name lookup and queue it to be restored. VariableDeclaration doesn't need to change too much since it's still bracketed by VariableIntroducer, and so we just traverse slightly differently.

Note this also incidentally changes a little about NameReference, that it's returning the storage consistently instead of the name. You can see this e.g. in global_lookup.carbon, `Assign(node8, node4): node2;` using node4 (VarStorage) instead of Node5 (BindName). Really either _could_ work, since from a BindName we can get to the VarStorage, and that may be reason to switch later if we find it preferable to have the BindName for whatever reason.

But the *actual* value in NameLookup is a BindName so that errors can associate with the _name_ instead of the "storage" parse node, which is currently the `:`. This is mainly for fail_duplicate_decl.carbon, which has a "Previous definition" note that points at the storage's parse node.
This commit is contained in:
Jon Ross-Perkins
2022-12-28 12:55:40 -08:00
committed by GitHub
parent 6c9b7cba55
commit 11deb14dc6
53 changed files with 297 additions and 242 deletions
+2 -11
View File
@@ -1811,21 +1811,12 @@ auto Parser::HandleVarAfterPatternState() -> void {
}
}
if (PositionIs(TokenKind::Equal())) {
PushState(ParserState::VarAfterInitializer());
++position_;
if (auto equals = ConsumeIf(TokenKind::Equal())) {
AddLeafNode(ParseNodeKind::VariableInitializer(), *equals);
PushState(ParserState::Expression());
return;
}
}
auto Parser::HandleVarAfterInitializerState() -> void {
auto state = PopState();
AddNode(ParseNodeKind::VariableInitializer(), state.token,
state.subtree_start, state.has_error);
}
auto Parser::HandleVarFinishAsSemicolonState() -> void {
auto state = PopState();