diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp new file mode 100644 index 000000000000..6db4ba2eb86d --- /dev/null +++ b/toolchain/check/handle_impl.cpp @@ -0,0 +1,34 @@ +// 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/check/context.h" + +namespace Carbon::Check { + +auto HandleImplIntroducer(Context& context, Parse::NodeId parse_node) -> bool { + return context.TODO(parse_node, "HandleImplIntroducer"); +} + +auto HandleImplForall(Context& context, Parse::NodeId parse_node) -> bool { + return context.TODO(parse_node, "HandleImplForall"); +} + +auto HandleImplAs(Context& context, Parse::NodeId parse_node) -> bool { + return context.TODO(parse_node, "HandleImplAs"); +} + +auto HandleImplDecl(Context& context, Parse::NodeId parse_node) -> bool { + return context.TODO(parse_node, "HandleImplDecl"); +} + +auto HandleImplDefinitionStart(Context& context, Parse::NodeId parse_node) + -> bool { + return context.TODO(parse_node, "HandleImplDefinitionStart"); +} + +auto HandleImplDefinition(Context& context, Parse::NodeId parse_node) -> bool { + return context.TODO(parse_node, "HandleImplDefinition"); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/handle_name.cpp b/toolchain/check/handle_name.cpp index 95be5cad3e86..29795b275f7a 100644 --- a/toolchain/check/handle_name.cpp +++ b/toolchain/check/handle_name.cpp @@ -48,10 +48,14 @@ static auto GetExprValueForLookupResult(Context& context, return context.types().GetInstId( context.classes().Get(class_decl->class_id).self_type_id); } + if (auto interface_decl = lookup_result.TryAs()) { + // TODO: unimplemented + return SemIR::InstId::Invalid; + } // Anything else should be a typed value already. CARBON_CHECK(lookup_result.kind().value_kind() == SemIR::InstValueKind::Typed) - << "Unexpected kind for lookup result"; + << "Unexpected kind for lookup result, " << lookup_result; return lookup_result_id; } @@ -81,6 +85,9 @@ auto HandleMemberAccessExpr(Context& context, Parse::NodeId parse_node) ? context.LookupQualifiedName(parse_node, name_id, *name_scope_id) : SemIR::InstId::BuiltinError; inst_id = GetExprValueForLookupResult(context, inst_id); + if (!inst_id.is_valid()) { + return context.TODO(parse_node, "Unimplemented use of interface"); + } auto inst = context.insts().Get(inst_id); // TODO: Track that this instruction was named within `base_id`. context.AddInstAndPush( @@ -246,6 +253,9 @@ static auto HandleNameAsExpr(Context& context, Parse::NodeId parse_node, SemIR::NameId name_id) -> bool { auto value_id = context.LookupUnqualifiedName(parse_node, name_id); value_id = GetExprValueForLookupResult(context, value_id); + if (!value_id.is_valid()) { + return context.TODO(parse_node, "Unimplemented use of interface"); + } auto value = context.insts().Get(value_id); context.AddInstAndPush(parse_node, SemIR::NameRef{parse_node, value.type_id(), name_id, value_id}); diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 6f897ddfb4e6..a80362b61d22 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -107,6 +107,8 @@ CARBON_DIAGNOSTIC_KIND(ExpectedInitializerAfterLet) CARBON_DIAGNOSTIC_KIND(ParamsRequiredAfterImplicit) CARBON_DIAGNOSTIC_KIND(ParamsRequiredByIntroducer) CARBON_DIAGNOSTIC_KIND(ExpectedAfterBase) +CARBON_DIAGNOSTIC_KIND(ImplExpectedAfterForall) +CARBON_DIAGNOSTIC_KIND(ImplExpectedAs) // ============================================================================ // Semantics diagnostics diff --git a/toolchain/parse/handle_decl_definition.cpp b/toolchain/parse/handle_decl_definition.cpp new file mode 100644 index 000000000000..c3a7c3b220df --- /dev/null +++ b/toolchain/parse/handle_decl_definition.cpp @@ -0,0 +1,90 @@ +// 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" + +namespace Carbon::Parse { + +// Handles processing after params, deciding whether it's a declaration or +// definition. +static auto HandleDeclOrDefinition(Context& context, NodeKind decl_kind, + NodeKind definition_start_kind, + State definition_finish_state) -> void { + auto state = context.PopState(); + + if (state.has_error) { + context.RecoverFromDeclError(state, decl_kind, + /*skip_past_likely_end=*/true); + return; + } + + if (auto semi = context.ConsumeIf(Lex::TokenKind::Semi)) { + context.AddNode(decl_kind, *semi, state.subtree_start, state.has_error); + return; + } + + if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) { + context.EmitExpectedDeclSemiOrDefinition( + context.tokens().GetKind(state.token)); + context.RecoverFromDeclError(state, decl_kind, + /*skip_past_likely_end=*/true); + return; + } + + context.PushState(state, definition_finish_state); + context.PushState(State::DeclScopeLoop); + context.AddNode(definition_start_kind, context.Consume(), state.subtree_start, + state.has_error); +} + +auto HandleDeclOrDefinitionAsClass(Context& context) -> void { + HandleDeclOrDefinition(context, NodeKind::ClassDecl, + NodeKind::ClassDefinitionStart, + State::DeclDefinitionFinishAsClass); +} + +auto HandleDeclOrDefinitionAsImpl(Context& context) -> void { + HandleDeclOrDefinition(context, NodeKind::ImplDecl, + NodeKind::ImplDefinitionStart, + State::DeclDefinitionFinishAsImpl); +} + +auto HandleDeclOrDefinitionAsInterface(Context& context) -> void { + HandleDeclOrDefinition(context, NodeKind::InterfaceDecl, + NodeKind::InterfaceDefinitionStart, + State::DeclDefinitionFinishAsInterface); +} + +auto HandleDeclOrDefinitionAsNamedConstraint(Context& context) -> void { + HandleDeclOrDefinition(context, NodeKind::NamedConstraintDecl, + NodeKind::NamedConstraintDefinitionStart, + State::DeclDefinitionFinishAsNamedConstraint); +} + +// Handles parsing after the declaration scope of a type. +static auto HandleDeclDefinitionFinish(Context& context, + NodeKind definition_kind) -> void { + auto state = context.PopState(); + + context.AddNode(definition_kind, context.Consume(), state.subtree_start, + state.has_error); +} + +auto HandleDeclDefinitionFinishAsClass(Context& context) -> void { + HandleDeclDefinitionFinish(context, NodeKind::ClassDefinition); +} + +auto HandleDeclDefinitionFinishAsImpl(Context& context) -> void { + HandleDeclDefinitionFinish(context, NodeKind::ImplDefinition); +} + +auto HandleDeclDefinitionFinishAsInterface(Context& context) -> void { + HandleDeclDefinitionFinish(context, NodeKind::InterfaceDefinition); +} + +auto HandleDeclDefinitionFinishAsNamedConstraint(Context& context) -> void { + HandleDeclDefinitionFinish(context, NodeKind::NamedConstraintDefinition); +} + +} // namespace Carbon::Parse diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index 15053d6dfa2a..ae431217e436 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -142,8 +142,8 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state, return true; } case Lex::TokenKind::Impl: { - // TODO: Treat this `impl` token as a declaration introducer - HandleUnrecognizedDecl(context, state.subtree_start); + ApplyIntroducer(context, state, NodeKind::ImplIntroducer, + State::ImplAfterIntroducer); return true; } case Lex::TokenKind::Interface: { diff --git a/toolchain/parse/handle_impl.cpp b/toolchain/parse/handle_impl.cpp new file mode 100644 index 000000000000..a67df0d6a5a5 --- /dev/null +++ b/toolchain/parse/handle_impl.cpp @@ -0,0 +1,79 @@ +// 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" + +namespace Carbon::Parse { + +static auto ExpectAsOrTypeExpression(Carbon::Parse::Context& context) -> void { + if (context.PositionIs(Lex::TokenKind::As)) { + // as ... + context.AddLeafNode(NodeKind::ImplAs, context.Consume()); + context.PushState(State::Expr); + } else { + // as ... + context.PushState(State::ImplBeforeAs); + context.PushStateForExpr(PrecedenceGroup::ForImplAs()); + } +} + +auto HandleImplAfterIntroducer(Carbon::Parse::Context& context) -> void { + auto state = context.PopState(); + state.state = State::DeclOrDefinitionAsImpl; + context.PushState(state); + + if (context.PositionIs(Lex::TokenKind::Forall)) { + // forall [] ... + context.PushState(State::ImplAfterForall); + context.ConsumeAndDiscard(); + if (context.PositionIs(Lex::TokenKind::OpenSquareBracket)) { + context.PushState(State::PatternListAsImplicit); + } else { + CARBON_DIAGNOSTIC(ImplExpectedAfterForall, Error, + "Expected `[` after `forall` in `impl` declaration."); + context.emitter().Emit(*context.position(), ImplExpectedAfterForall); + context.ReturnErrorOnState(); + } + } else { + // One of: + // as ... + // as ... + ExpectAsOrTypeExpression(context); + } +} + +auto HandleImplAfterForall(Carbon::Parse::Context& context) -> void { + auto state = context.PopState(); + if (state.has_error) { + context.AddLeafNode(NodeKind::InvalidParse, *context.position(), + /*has_error=*/true); + context.ReturnErrorOnState(); + } + context.AddNode(NodeKind::ImplForall, state.token, state.subtree_start, + state.has_error); + + // One of: + // as ... + // as ... + ExpectAsOrTypeExpression(context); +} + +auto HandleImplBeforeAs(Carbon::Parse::Context& context) -> void { + auto state = context.PopState(); + if (state.has_error) { + context.ReturnErrorOnState(); + return; + } + if (auto as = context.ConsumeIf(Lex::TokenKind::As)) { + context.AddLeafNode(NodeKind::ImplAs, *as); + context.PushState(State::Expr); + } else { + CARBON_DIAGNOSTIC(ImplExpectedAs, Error, + "Expected `as` in `impl` declaration."); + context.emitter().Emit(*context.position(), ImplExpectedAs); + context.ReturnErrorOnState(); + } +} + +} // namespace Carbon::Parse diff --git a/toolchain/parse/handle_type.cpp b/toolchain/parse/handle_type.cpp index 964118ad8ee2..aea94daa00ac 100644 --- a/toolchain/parse/handle_type.cpp +++ b/toolchain/parse/handle_type.cpp @@ -15,86 +15,15 @@ static auto HandleTypeAfterIntroducer(Context& context, } auto HandleTypeAfterIntroducerAsClass(Context& context) -> void { - HandleTypeAfterIntroducer(context, State::TypeAfterParamsAsClass); + HandleTypeAfterIntroducer(context, State::DeclOrDefinitionAsClass); } auto HandleTypeAfterIntroducerAsInterface(Context& context) -> void { - HandleTypeAfterIntroducer(context, State::TypeAfterParamsAsInterface); + HandleTypeAfterIntroducer(context, State::DeclOrDefinitionAsInterface); } auto HandleTypeAfterIntroducerAsNamedConstraint(Context& context) -> void { - HandleTypeAfterIntroducer(context, State::TypeAfterParamsAsNamedConstraint); -} - -// Handles processing after params, deciding whether it's a declaration or -// definition. -static auto HandleTypeAfterParams(Context& context, NodeKind decl_kind, - NodeKind definition_start_kind, - State definition_finish_state) -> void { - auto state = context.PopState(); - - if (state.has_error) { - context.RecoverFromDeclError(state, decl_kind, - /*skip_past_likely_end=*/true); - return; - } - - if (auto semi = context.ConsumeIf(Lex::TokenKind::Semi)) { - context.AddNode(decl_kind, *semi, state.subtree_start, state.has_error); - return; - } - - if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) { - context.EmitExpectedDeclSemiOrDefinition( - context.tokens().GetKind(state.token)); - context.RecoverFromDeclError(state, decl_kind, - /*skip_past_likely_end=*/true); - return; - } - - context.PushState(state, definition_finish_state); - context.PushState(State::DeclScopeLoop); - context.AddNode(definition_start_kind, context.Consume(), state.subtree_start, - state.has_error); -} - -auto HandleTypeAfterParamsAsClass(Context& context) -> void { - HandleTypeAfterParams(context, NodeKind::ClassDecl, - NodeKind::ClassDefinitionStart, - State::TypeDefinitionFinishAsClass); -} - -auto HandleTypeAfterParamsAsInterface(Context& context) -> void { - HandleTypeAfterParams(context, NodeKind::InterfaceDecl, - NodeKind::InterfaceDefinitionStart, - State::TypeDefinitionFinishAsInterface); -} - -auto HandleTypeAfterParamsAsNamedConstraint(Context& context) -> void { - HandleTypeAfterParams(context, NodeKind::NamedConstraintDecl, - NodeKind::NamedConstraintDefinitionStart, - State::TypeDefinitionFinishAsNamedConstraint); -} - -// Handles parsing after the declaration scope of a type. -static auto HandleTypeDefinitionFinish(Context& context, - NodeKind definition_kind) -> void { - auto state = context.PopState(); - - context.AddNode(definition_kind, context.Consume(), state.subtree_start, - state.has_error); -} - -auto HandleTypeDefinitionFinishAsClass(Context& context) -> void { - HandleTypeDefinitionFinish(context, NodeKind::ClassDefinition); -} - -auto HandleTypeDefinitionFinishAsInterface(Context& context) -> void { - HandleTypeDefinitionFinish(context, NodeKind::InterfaceDefinition); -} - -auto HandleTypeDefinitionFinishAsNamedConstraint(Context& context) -> void { - HandleTypeDefinitionFinish(context, NodeKind::NamedConstraintDefinition); + HandleTypeAfterIntroducer(context, State::DeclOrDefinitionAsNamedConstraint); } } // namespace Carbon::Parse diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index c578dfb07a94..393d4e2073a8 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -693,6 +693,35 @@ CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDecl, InterfaceIntroducer, CARBON_TOKEN(Semi) CARBON_IF_ERROR(CARBON_TOKEN(Interface))) +// `impl ... as`: +// ImplIntroducer +// _repeated_ _external_: modifier +// _optional_ ImplForall (see below) +// _optional_ _external_: expression +// ImplAs +// _external_: expression +// ImplDefinitionStart +// _external_: declarations +// ImplDefinition +// +// The above is the structure for a definition; for a declaration, +// ImplDefinitionStart and later nodes are removed and replaced by +// ImplDecl. +CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplIntroducer, 0, CARBON_TOKEN(Impl)) + +// `forall ...`: +// _external_: ImplicitParamList +// ImplForall +CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplForall, 1, CARBON_TOKEN(Forall)) +CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplAs, 0, CARBON_TOKEN(As)) +CARBON_PARSE_NODE_KIND_BRACKET(ImplDefinitionStart, ImplIntroducer, + CARBON_TOKEN(OpenCurlyBrace)) +CARBON_PARSE_NODE_KIND_BRACKET(ImplDefinition, ImplDefinitionStart, + CARBON_TOKEN(CloseCurlyBrace)) +CARBON_PARSE_NODE_KIND_BRACKET(ImplDecl, ImplIntroducer, + CARBON_TOKEN(Semi) + CARBON_IF_ERROR(CARBON_ANY_TOKEN)) + // `constraint`: // NamedConstraintIntroducer // _repeated_ _external_: modifier diff --git a/toolchain/parse/precedence.cpp b/toolchain/parse/precedence.cpp index 1da00e6a3349..01354619310b 100644 --- a/toolchain/parse/precedence.cpp +++ b/toolchain/parse/precedence.cpp @@ -191,6 +191,10 @@ auto PrecedenceGroup::ForExprStatement() -> PrecedenceGroup { auto PrecedenceGroup::ForType() -> PrecedenceGroup { return ForTopLevelExpr(); } +auto PrecedenceGroup::ForImplAs() -> PrecedenceGroup { + return PrecedenceGroup(As); +} + auto PrecedenceGroup::ForLeading(Lex::TokenKind kind) -> std::optional { switch (kind) { diff --git a/toolchain/parse/precedence.h b/toolchain/parse/precedence.h index 4024dfcc332f..145828054a36 100644 --- a/toolchain/parse/precedence.h +++ b/toolchain/parse/precedence.h @@ -54,6 +54,10 @@ class PrecedenceGroup { // operators have higher precedence than this. static auto ForType() -> PrecedenceGroup; + // Get the precedence level at which to parse the type expression between + // `impl` and `as`. + static auto ForImplAs() -> PrecedenceGroup; + // Look up the operator information of the given prefix operator token, or // return std::nullopt if the given token is not a prefix operator. static auto ForLeading(Lex::TokenKind kind) -> std::optional; diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index 59abca5f0ffe..c146a3192a5b 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -328,6 +328,11 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterImplicit) // 1. FunctionIntroducer // 2. DeclScopeLoop // +// impl ... +// ^~~~ +// 1. ImplAfterIntroducer +// 2. DeclScopeLoop +// // interface ... // ^~~~~~~~~ // 1. TypeAfterIntroducerAsInterface @@ -1071,10 +1076,10 @@ CARBON_PARSE_STATE(StatementWhileBlockFinish) // Handles parsing after the declaration scope of a type. // -// class/interface/constraint { ... } -// ^ +// class/impl/interface/constraint ... { ... } +// ^ // (state done) -CARBON_PARSE_STATE_VARIANTS3(TypeDefinitionFinish, Class, Interface, +CARBON_PARSE_STATE_VARIANTS4(DeclDefinitionFinish, Class, Impl, Interface, NamedConstraint) // Handles processing of a type after its introducer. @@ -1082,23 +1087,23 @@ CARBON_PARSE_STATE_VARIANTS3(TypeDefinitionFinish, Class, Interface, // class/interface/constraint ... // ^ // 1. DeclNameAndParamsAsOptional -// 2. TypeAfterParamsAs(Class|Interface|NamedConstraint) +// 2. DeclOrDefinitionAs(Class|Interface|NamedConstraint) CARBON_PARSE_STATE_VARIANTS3(TypeAfterIntroducer, Class, Interface, NamedConstraint) // Handles processing of a type after its optional parameters. // -// class/interface/constraint name ( ... ) { -// ^ +// class/impl/interface/constraint name ( ... ) { +// ^ // 1. DeclScopeLoop -// 2. TypeDefinitionFinishAs(Class|Interface|NamedConstraint) +// 2. DeclDefinitionFinishAs(Class|Impl|Interface|NamedConstraint) // -// class/interface/constraint name ( ... ) ; -// ^ -// class/interface/constraint name ( ... ) ??? -// ^ +// class/impl/interface/constraint name ( ... ) ; +// ^ +// class/impl/interface/constraint name ( ... ) ??? +// ^ // (state done) -CARBON_PARSE_STATE_VARIANTS3(TypeAfterParams, Class, Interface, NamedConstraint) +CARBON_PARSE_STATE_VARIANTS4(DeclOrDefinition, Class, Impl, Interface, NamedConstraint) // Handles processing of a completed `base: B` declaration. // @@ -1109,6 +1114,44 @@ CARBON_PARSE_STATE_VARIANTS3(TypeAfterParams, Class, Interface, NamedConstraint) // (state done) CARBON_PARSE_STATE(BaseDecl) +// Handles processing of an `impl...as` declaration after the introducer. +// +// impl forall [ ... +// ^~~~~~ +// 1. PatternListAsImplicit +// 2. ImplAfterForall +// 3. DeclOrDefinitionAsImpl +// impl as ... +// ^~ +// 1. Expr +// 2. DeclOrDefinitionAsImpl +// impl type_expression as ... +// ^ +// 1. Expr +// 2. ImplBeforeAs +// 3. DeclOrDefinitionAsImpl +CARBON_PARSE_STATE(ImplAfterIntroducer) + +// Handles processing of an `impl forall` declaration after the implicit +// parameter list. +// +// impl forall [ ... ] as ... +// ^~ +// 1. Expr +// impl forall [ ... ] type_expression as ... +// ^ +// 1. Expr +// 2. ImplBeforeAs +CARBON_PARSE_STATE(ImplAfterForall) + +// Handles processing of the `as` in an `impl` declaration after the type +// expression. +// +// impl TypeExpression as ... +// ^~ +// 1. Expr +CARBON_PARSE_STATE(ImplBeforeAs) + // Handles the start of a `var` or `returned var`. // // var ... (variant is not Returned) diff --git a/toolchain/parse/testdata/function/declaration/fail_impl.carbon b/toolchain/parse/testdata/function/declaration/fail_impl.carbon deleted file mode 100644 index 790c6cc99f1c..000000000000 --- a/toolchain/parse/testdata/function/declaration/fail_impl.carbon +++ /dev/null @@ -1,24 +0,0 @@ -// 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 -// -// AUTOUPDATE - -// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:1: ERROR: Unrecognized declaration introducer. -// CHECK:STDERR: impl foo bar; -// CHECK:STDERR: ^~~~ -impl foo bar; -// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:1: ERROR: Unrecognized declaration introducer. -// CHECK:STDERR: impl -// CHECK:STDERR: ^~~~ -impl - -// CHECK:STDOUT: - filename: fail_impl.carbon -// CHECK:STDOUT: parse_tree: [ -// CHECK:STDOUT: {kind: 'FileStart', text: ''}, -// CHECK:STDOUT: {kind: 'InvalidParseStart', text: 'impl', has_error: yes}, -// CHECK:STDOUT: {kind: 'InvalidParseSubtree', text: ';', has_error: yes, subtree_size: 2}, -// CHECK:STDOUT: {kind: 'InvalidParseStart', text: 'impl', has_error: yes}, -// CHECK:STDOUT: {kind: 'InvalidParseSubtree', text: 'impl', has_error: yes, subtree_size: 2}, -// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, -// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/basic.carbon b/toolchain/parse/testdata/generics/impl/basic.carbon new file mode 100644 index 000000000000..030cd93212bb --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/basic.carbon @@ -0,0 +1,36 @@ +// 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 +// +// AUTOUPDATE + +impl i32 as Interface { + fn Add[self: Self](b: Self) -> Self; +} + +// CHECK:STDOUT: - filename: basic.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Add'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'SelfValueName', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 15}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 21}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/class.carbon b/toolchain/parse/testdata/generics/impl/class.carbon new file mode 100644 index 000000000000..f45a41bc84e8 --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/class.carbon @@ -0,0 +1,58 @@ +// 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 +// +// AUTOUPDATE + +class C { + impl as ForwardDeclared; + impl C as ExplicitType { + } + impl Self as ExplicitSelf; + extend impl as ExtendImpl { + fn F(); + } + extend impl C as InvalidButDiagnosedInCheck; +} + +// CHECK:STDOUT: - filename: class.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ClassIntroducer', text: 'class'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'C'}, +// CHECK:STDOUT: {kind: 'ClassDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ForwardDeclared'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'C'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ExplicitType'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ExplicitSelf'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'ExtendImpl'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ExtendModifier', text: 'extend'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'C'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'InvalidButDiagnosedInCheck'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'ClassDefinition', text: '}', subtree_size: 36}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/declaration.carbon b/toolchain/parse/testdata/generics/impl/declaration.carbon new file mode 100644 index 000000000000..2f28645f2d45 --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/declaration.carbon @@ -0,0 +1,18 @@ +// 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 +// +// AUTOUPDATE + +impl bool as Interface; + +// CHECK:STDOUT: - filename: declaration.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/empty_body.carbon b/toolchain/parse/testdata/generics/impl/empty_body.carbon new file mode 100644 index 000000000000..1bbdee4cf4fe --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/empty_body.carbon @@ -0,0 +1,20 @@ +// 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 +// +// AUTOUPDATE + +impl String as Interface { +} + +// CHECK:STDOUT: - filename: empty_body.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'String'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/fail_impl.carbon b/toolchain/parse/testdata/generics/impl/fail_impl.carbon new file mode 100644 index 000000000000..f627fec7e36d --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/fail_impl.carbon @@ -0,0 +1,152 @@ +// 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 +// +// AUTOUPDATE + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:10: ERROR: Expected `as` in `impl` declaration. +// CHECK:STDERR: impl foo bar; +// CHECK:STDERR: ^~~ +impl foo bar; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:12: ERROR: Expected expression. +// CHECK:STDERR: impl i32 as; +// CHECK:STDERR: ^ +impl i32 as; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:18: ERROR: `impl` declarations must either end with a `;` or have a `{ ... }` block for a definition. +// CHECK:STDERR: impl bool as bar unexpected; +// CHECK:STDERR: ^~~~~~~~~~ +impl bool as bar unexpected; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+6]]:13: ERROR: Expected `[` after `forall` in `impl` declaration. +// CHECK:STDERR: impl forall f32; +// CHECK:STDERR: ^~~ +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:16: ERROR: Expected `as` in `impl` declaration. +// CHECK:STDERR: impl forall f32; +// CHECK:STDERR: ^ +impl forall f32; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:19: ERROR: Expected `as` in `impl` declaration. +// CHECK:STDERR: impl forall [] u32; +// CHECK:STDERR: ^ +impl forall [] u32; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+6]]:21: ERROR: Expected binding pattern. +// CHECK:STDERR: impl forall [invalid] i8; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:25: ERROR: Expected `as` in `impl` declaration. +// CHECK:STDERR: impl forall [invalid] i8; +// CHECK:STDERR: ^ +impl forall [invalid] i8; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:13: ERROR: Expected `[` after `forall` in `impl` declaration. +// CHECK:STDERR: impl forall f16 as Quux; +// CHECK:STDERR: ^~~ +impl forall f16 as Quux; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:30: ERROR: Expected `as` in `impl` declaration. +// CHECK:STDERR: impl forall [T:! type] String; +// CHECK:STDERR: ^ +impl forall [T:! type] String; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:26: ERROR: Expected `as` in `impl` declaration. +// CHECK:STDERR: impl forall [T:! type] T missing_as; +// CHECK:STDERR: ^~~~~~~~~~ +impl forall [T:! type] T missing_as; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:39: ERROR: `impl` declarations must either end with a `;` or have a `{ ... }` block for a definition. +// CHECK:STDERR: impl forall [T:! type] T as Interface extra; +// CHECK:STDERR: ^~~~~ +impl forall [T:! type] T as Interface extra; + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+3]]:5: ERROR: Expected expression. +// CHECK:STDERR: impl; +// CHECK:STDERR: ^ +impl; + +impl + +// CHECK:STDERR: fail_impl.carbon:[[@LINE+82]]:21: ERROR: Expected expression. +// CHECK:STDERR: // CHECK:STDOUT: ] +// CHECK:STDERR: ^ +// CHECK:STDOUT: - filename: fail_impl.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'foo'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'bar'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'f32', has_error: yes}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FloatTypeLiteral', text: 'f32'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'UnsignedIntTypeLiteral', text: 'u32'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 6}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'invalid'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ']', has_error: yes}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: 'invalid', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i8'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 9}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: 'f16', has_error: yes}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FloatTypeLiteral', text: 'f16'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Quux'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 7}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'StringTypeLiteral', text: 'String'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 9}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 9}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 11}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: ';', has_error: yes}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'InvalidParse', text: '', has_error: yes}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: 'impl', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/forall.carbon b/toolchain/parse/testdata/generics/impl/forall.carbon new file mode 100644 index 000000000000..ec93cec63918 --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/forall.carbon @@ -0,0 +1,46 @@ +// 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 +// +// AUTOUPDATE + +impl forall [T:! type] T as Interface; + +impl forall [T:! type, U:! Interface] U as Interface(T) { +} + +// CHECK:STDOUT: - filename: forall.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDecl', text: ';', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'U'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 9}, +// CHECK:STDOUT: {kind: 'ImplForall', text: 'forall', subtree_size: 10}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'U'}, +// CHECK:STDOUT: {kind: 'ImplAs', text: 'as'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'CallExprStart', text: '(', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'CallExpr', text: ')', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 19}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/tree.cpp b/toolchain/parse/tree.cpp index 6b475db241b2..206f33312ae8 100644 --- a/toolchain/parse/tree.cpp +++ b/toolchain/parse/tree.cpp @@ -51,9 +51,13 @@ auto Tree::Parse(Lex::TokenizedBuffer& tokens, DiagnosticConsumer& consumer, context.AddLeafNode(NodeKind::FileEnd, *context.position()); if (auto verify = tree.Verify(); !verify.ok()) { - if (vlog_stream) { - tree.Print(*vlog_stream); - } + // TODO: This is temporarily printing to stderr directly during development. + // If we can, restrict this to a subtree with the error and add it to the + // stack trace (such as with PrettyStackTraceFunction). Otherwise, switch + // back to vlog_stream prior to broader distribution so that end users are + // hopefully comfortable copy-pasting stderr when there are bugs in tree + // construction. + tree.Print(llvm::errs()); CARBON_FATAL() << "Invalid tree returned by Parse(): " << verify.error(); } return tree;