mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
Malformed `base` declarations with an omitted colon need two different
recovery paths. For `extend base`, the consumed `extend` modifier
requires the parse tree to retain its `BaseColon` and base expression
children, so this synthesizes an errored `BaseColon` and continues
parsing the expression.
Other malformed forms, such as `base calss X {}`, now use the standard
declaration-error recovery: emit `ExpectedAfterBase`, skip past the
likely declaration end, and form an errored `BaseDecl` without inventing
a colon or cascading diagnostics.
The regression covers `extend base Foo;`, bare `base;`, and the reviewer
counterexample `base calss X {}`.
Tests:
- `prek run --files toolchain/parse/handle_base.cpp
toolchain/parse/testdata/class/fail_base.carbon`
- `./scripts/run_bazelisk.py test -c dbg //toolchain/parse/...`
- `./scripts/run_bazelisk.py test -c dbg //toolchain/testing:file_test`
AI assistance: OpenAI Codex helped inspect the parser recovery path,
implement the change, and run verification. The operator reviewed and
authorized the contribution.
Assisted-by: OpenAI Codex
48 lines
1.7 KiB
C++
48 lines
1.7 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "toolchain/parse/context.h"
|
|
#include "toolchain/parse/handle.h"
|
|
|
|
namespace Carbon::Parse {
|
|
|
|
// Handles a `base` declaration after the introducer.
|
|
auto HandleBaseAfterIntroducer(Context& context) -> void {
|
|
auto state = context.PopState();
|
|
|
|
if (!context.ConsumeAndAddLeafNodeIf(Lex::TokenKind::Colon,
|
|
NodeKind::BaseColon)) {
|
|
CARBON_DIAGNOSTIC(ExpectedAfterBase, Error,
|
|
"`class` or `:` expected after `base`");
|
|
context.emitter().Emit(*context.position(), ExpectedAfterBase);
|
|
auto base_token = *(context.position() - 1);
|
|
auto previous_token = Lex::TokenIndex(base_token.index - 1);
|
|
if (context.tokens().GetKind(previous_token) != Lex::TokenKind::Extend) {
|
|
context.RecoverFromDeclError(state, NodeKind::BaseDecl,
|
|
/*skip_past_likely_end=*/true);
|
|
return;
|
|
}
|
|
|
|
// Preserve the `extend base` tree shape using an errored placeholder.
|
|
context.AddLeafNode(NodeKind::BaseColon, *context.position(),
|
|
/*has_error=*/true);
|
|
state.has_error = true;
|
|
}
|
|
|
|
state.kind = StateKind::BaseDecl;
|
|
context.PushState(state);
|
|
context.PushState(StateKind::Expr);
|
|
}
|
|
|
|
// Handles processing of a complete `base: B` declaration.
|
|
auto HandleBaseDecl(Context& context) -> void {
|
|
auto state = context.PopState();
|
|
|
|
context.AddNodeExpectingDeclSemi(state, NodeKind::BaseDecl,
|
|
Lex::TokenKind::Base,
|
|
/*is_def_allowed=*/false);
|
|
}
|
|
|
|
} // namespace Carbon::Parse
|