mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-10 12:28:25 +00:00
Add check support for struct patterns (#7876)
Implements check and pattern matching support for struct patterns. This PR implements complete patterns, and leaves `_` field handling for future work.
This commit is contained in:
1 parent
3ee012b86a
commit
c6b54b57e2
23 files changed
+1764
-110
No files matched your search
@@ -73,6 +73,7 @@ cc_library(
|
||||
"require_impls_stack.cpp",
|
||||
"return.cpp",
|
||||
"scope_stack.cpp",
|
||||
"struct.cpp",
|
||||
"subst.cpp",
|
||||
"thunk.cpp",
|
||||
"type.cpp",
|
||||
@@ -147,6 +148,7 @@ cc_library(
|
||||
"return.h",
|
||||
"scope_index.h",
|
||||
"scope_stack.h",
|
||||
"struct.h",
|
||||
"subst.h",
|
||||
"thunk.h",
|
||||
"type.h",
|
||||
|
||||
@@ -518,7 +518,8 @@ class Context {
|
||||
// - The associated entries witness table, while parsing an interface.
|
||||
InstBlockStack args_type_info_stack_;
|
||||
|
||||
// The stack of StructTypeFields for in-progress StructTypeLiterals.
|
||||
// The stack of StructTypeFields for in-progress StructTypeLiterals,
|
||||
// StructLiteral values, and StructPatterns.
|
||||
ArrayStack<SemIR::StructTypeField> struct_type_fields_stack_;
|
||||
|
||||
// The stack of FieldDecls for in-progress Class definitions.
|
||||
|
||||
@@ -42,9 +42,11 @@ static auto GetLeafBindingPatternInstKind(Parse::NodeKind node_kind,
|
||||
case Parse::NodeKind::CompileTimeBindingPattern:
|
||||
return SemIR::InstKind::SymbolicBindingPattern;
|
||||
case Parse::NodeKind::LetBindingPattern:
|
||||
case Parse::NodeKind::StructPatternFieldLetBindingPattern:
|
||||
return is_ref ? SemIR::InstKind::RefBindingPattern
|
||||
: SemIR::InstKind::ValueBindingPattern;
|
||||
case Parse::NodeKind::VarBindingPattern:
|
||||
case Parse::NodeKind::StructPatternFieldVarBindingPattern:
|
||||
return SemIR::InstKind::RefBindingPattern;
|
||||
default:
|
||||
CARBON_FATAL("Unexpected node kind: {0}", node_kind);
|
||||
@@ -421,7 +423,9 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
case FullPatternStack::Kind::ExplicitParamList: {
|
||||
bool is_deduced = context.full_pattern_stack().CurrentKind() ==
|
||||
FullPatternStack::Kind::ImplicitParamList;
|
||||
bool is_var = node_kind == Parse::NodeKind::VarBindingPattern;
|
||||
bool is_var =
|
||||
node_kind == Parse::NodeKind::VarBindingPattern ||
|
||||
node_kind == Parse::NodeKind::StructPatternFieldVarBindingPattern;
|
||||
if (!IsValidParamForIntroducer(context, node_id, name_id, introducer.kind,
|
||||
is_generic, is_deduced, is_var)) {
|
||||
if (name_id != SemIR::NameId::Underscore) {
|
||||
@@ -435,7 +439,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
|
||||
// Using `AsConcreteType` here causes `fn F[var self: Self]();`
|
||||
// to fail since `Self` is an incomplete type.
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern) {
|
||||
if (is_var) {
|
||||
auto [unqualified_type_id, qualifiers] =
|
||||
context.types().GetUnqualifiedTypeAndQualifiers(
|
||||
type_expr.type_component_id);
|
||||
@@ -463,6 +467,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
// enclosing `var` pattern is), or it's a compile-time binding pattern
|
||||
// (because then it's not passed to the `Call` inst).
|
||||
case Parse::NodeKind::LetBindingPattern:
|
||||
case Parse::NodeKind::StructPatternFieldLetBindingPattern:
|
||||
case Parse::NodeKind::FormBindingPattern: {
|
||||
auto param_pattern_id = SemIR::InstId::None;
|
||||
auto pattern_type_id =
|
||||
@@ -497,6 +502,7 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
break;
|
||||
}
|
||||
case Parse::NodeKind::VarBindingPattern:
|
||||
case Parse::NodeKind::StructPatternFieldVarBindingPattern:
|
||||
result_inst_id = make_binding_pattern(SemIR::RefBindingPattern::Kind);
|
||||
break;
|
||||
case Parse::NodeKind::CompileTimeBindingPattern:
|
||||
@@ -506,6 +512,20 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
default:
|
||||
CARBON_FATAL("Unexpected node kind {0}", node_kind);
|
||||
}
|
||||
|
||||
if (node_kind == Parse::NodeKind::StructPatternFieldLetBindingPattern ||
|
||||
node_kind == Parse::NodeKind::StructPatternFieldVarBindingPattern) {
|
||||
auto type_inst_id =
|
||||
context.types().GetTypeInstId(type_expr.type_component_id);
|
||||
|
||||
context.struct_type_fields_stack().AppendToTop(
|
||||
{.name_id = name_id, .type_inst_id = type_inst_id});
|
||||
|
||||
// Put the name node back on the stack for inspection when handling the
|
||||
// struct pattern.
|
||||
context.node_stack().Push(name_node, name_id);
|
||||
}
|
||||
|
||||
context.node_stack().Push(node_id, result_inst_id);
|
||||
break;
|
||||
}
|
||||
@@ -524,7 +544,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
builder.Attach(type_expr.node_id, IncompleteTypeInBindingDecl,
|
||||
type_expr.inst_id);
|
||||
};
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern) {
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern ||
|
||||
node_kind == Parse::NodeKind::StructPatternFieldVarBindingPattern) {
|
||||
if (!RequireConcreteType(
|
||||
context, type_expr.type_component_id, type_expr.node_id,
|
||||
incomplete_diagnostic_context, abstract_diagnostic_context)) {
|
||||
@@ -540,7 +561,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
|
||||
auto binding_pattern_id = make_binding_pattern(
|
||||
GetLeafBindingPatternInstKind(node_kind, is_ref));
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern) {
|
||||
if (node_kind == Parse::NodeKind::VarBindingPattern ||
|
||||
node_kind == Parse::NodeKind::StructPatternFieldVarBindingPattern) {
|
||||
CARBON_CHECK(!is_generic);
|
||||
|
||||
if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Returned)) {
|
||||
@@ -555,6 +577,18 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
|
||||
type_expr.node_id, type_expr.type_component_id, bind_id, name_id);
|
||||
}
|
||||
}
|
||||
if (node_kind == Parse::NodeKind::StructPatternFieldLetBindingPattern ||
|
||||
node_kind == Parse::NodeKind::StructPatternFieldVarBindingPattern) {
|
||||
auto type_inst_id =
|
||||
context.types().GetTypeInstId(type_expr.type_component_id);
|
||||
|
||||
context.struct_type_fields_stack().AppendToTop(
|
||||
{.name_id = name_id, .type_inst_id = type_inst_id});
|
||||
|
||||
// Put the name node back on the stack for inspection when handling the
|
||||
// struct pattern.
|
||||
context.node_stack().Push(name_node, name_id);
|
||||
}
|
||||
context.node_stack().Push(node_id, binding_pattern_id);
|
||||
break;
|
||||
}
|
||||
@@ -579,6 +613,22 @@ auto HandleParseNode(Context& context, Parse::LetBindingPatternId node_id)
|
||||
Parse::NodeKind::BindingPatternTypeStart);
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context,
|
||||
Parse::StructPatternFieldLetBindingPatternId node_id)
|
||||
-> bool {
|
||||
return HandleAnyBindingPattern(
|
||||
context, node_id, Parse::NodeKind::StructPatternFieldLetBindingPattern,
|
||||
Parse::NodeKind::BindingPatternTypeStart);
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context,
|
||||
Parse::StructPatternFieldVarBindingPatternId node_id)
|
||||
-> bool {
|
||||
return HandleAnyBindingPattern(
|
||||
context, node_id, Parse::NodeKind::StructPatternFieldVarBindingPattern,
|
||||
Parse::NodeKind::BindingPatternTypeStart);
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::SelfBindingPatternId node_id)
|
||||
-> bool {
|
||||
// A `self` binding with an omitted type behaves like `self: Self`. There is
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/pattern.h"
|
||||
#include "toolchain/check/struct.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/diagnostics/emitter.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
@@ -39,7 +41,12 @@ auto HandleParseNode(Context& context, Parse::TuplePatternStartId node_id)
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::StructPatternStartId node_id)
|
||||
-> bool {
|
||||
return context.TODO(node_id, "struct pattern start");
|
||||
EndEmptyExprRegionForPattern(context);
|
||||
context.node_stack().Push(node_id);
|
||||
context.struct_type_fields_stack().PushArray();
|
||||
context.param_and_arg_refs_stack().Push();
|
||||
BeginExprRegionForPattern(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::ExplicitParamListStartId node_id)
|
||||
@@ -137,12 +144,101 @@ auto HandleParseNode(Context& context, Parse::TuplePatternId node_id) -> bool {
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::StructPatternId node_id) -> bool {
|
||||
return context.TODO(node_id, "struct pattern");
|
||||
if (context.node_stack().PeekIs(Parse::NodeKind::StructPatternStart)) {
|
||||
// End the pending region started by a trailing comma, or the opening
|
||||
// delimiter of an empty list.
|
||||
EndEmptyExprRegionForPattern(context);
|
||||
} else {
|
||||
// End the pending region for the last pattern in the list.
|
||||
EndExprRegionForPattern(context, context.node_stack());
|
||||
}
|
||||
|
||||
// TODO: Reject StructPatterns in classes during Parse, or treat patterns in a
|
||||
// class scope as patterns and generate the FieldDecl insts in a later
|
||||
// pattern-matching step.
|
||||
if (context.scope_stack().TryGetCurrentScopeAs<SemIR::ClassDecl>()) {
|
||||
bool is_var = context.full_pattern_stack().IsCurrentKindClassScopeVarDecl();
|
||||
CARBON_DIAGNOSTIC(
|
||||
FieldWithStructPattern, Error,
|
||||
"found struct pattern in class member {0:var|let} declaration",
|
||||
Diagnostics::BoolAsSelect);
|
||||
context.emitter().Emit(node_id, FieldWithStructPattern, is_var);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.node_stack().PeekIs(Parse::NodeKind::UnderscoreName)) {
|
||||
return context.TODO(node_id, "Struct pattern underscore field");
|
||||
}
|
||||
|
||||
if (!context.node_stack().PeekIs(Parse::NodeCategory::MemberName)) {
|
||||
// Remove the last parameter from the node stack before collecting names.
|
||||
context.param_and_arg_refs_stack().EndNoPop(
|
||||
Parse::NodeKind::StructPatternStart);
|
||||
}
|
||||
|
||||
auto fields = context.struct_type_fields_stack().PeekArray();
|
||||
|
||||
llvm::SmallVector<Parse::NodeId> field_name_nodes =
|
||||
PopStructFieldNameNodes(context, fields.size());
|
||||
|
||||
auto refs_id = context.param_and_arg_refs_stack().EndAndPop(
|
||||
Parse::NodeKind::StructPatternStart);
|
||||
|
||||
context.node_stack()
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::StructPatternStart>();
|
||||
|
||||
if (DiagnoseDuplicateNames(context, field_name_nodes, fields,
|
||||
StructKind::StructPattern)) {
|
||||
context.node_stack().Push(node_id, SemIR::ErrorInst::InstId);
|
||||
} else {
|
||||
auto type_id = GetPatternType(
|
||||
context,
|
||||
GetStructType(context,
|
||||
context.struct_type_fields().AddCanonical(fields)));
|
||||
|
||||
context.node_stack().Push(
|
||||
node_id,
|
||||
AddInst<SemIR::StructPattern>(
|
||||
context, node_id, {.type_id = type_id, .elements_id = refs_id}));
|
||||
}
|
||||
|
||||
context.struct_type_fields_stack().PopArray();
|
||||
BeginExprRegionForPattern(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context,
|
||||
Parse::StructPatternDesignatedFieldId node_id) -> bool {
|
||||
return context.TODO(node_id, "struct pattern field");
|
||||
EndExprRegionForPattern(context, context.node_stack());
|
||||
|
||||
auto pattern_id = context.node_stack().PopPattern();
|
||||
auto pattern_type_id = context.insts().Get(pattern_id).type_id();
|
||||
auto name_id = context.node_stack().Peek<Parse::NodeCategory::MemberName>();
|
||||
|
||||
// NOTE: This check is required for the case when the struct pattern is found
|
||||
// in a class field, so the node_stack contains FieldDecls instead of
|
||||
// Patterns. See the TODO in the HandleParseNode function for the
|
||||
// StructPatternId.
|
||||
if (context.sem_ir().types().TryGetAs<SemIR::PatternType>(pattern_type_id)) {
|
||||
auto type_id = ExtractScrutineeType(context.sem_ir(), pattern_type_id);
|
||||
|
||||
auto type_inst = context.types().GetTypeInstId(type_id);
|
||||
|
||||
context.struct_type_fields_stack().AppendToTop(
|
||||
{.name_id = name_id, .type_inst_id = type_inst});
|
||||
|
||||
context.node_stack().Push(node_id, pattern_id);
|
||||
} else {
|
||||
context.struct_type_fields_stack().AppendToTop(
|
||||
{.name_id = name_id, .type_inst_id = SemIR::ErrorInst::TypeInstId});
|
||||
context.node_stack().Push(node_id, pattern_id);
|
||||
}
|
||||
|
||||
// Start a new pending `ExprRegion`, to maintain the invariant that one is
|
||||
// pending at the end of handling for a pattern.
|
||||
BeginExprRegionForPattern(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::PatternListCommaId /*node_id*/)
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "common/map.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/struct.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/check/unused.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
@@ -77,47 +77,6 @@ auto HandleParseNode(Context& context,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Diagnoses and returns true if there's a duplicate name.
|
||||
static auto DiagnoseDuplicateNames(
|
||||
Context& context, llvm::ArrayRef<Parse::NodeId> field_name_nodes,
|
||||
llvm::ArrayRef<SemIR::StructTypeField> fields, bool is_struct_type_literal)
|
||||
-> bool {
|
||||
Map<SemIR::NameId, Parse::NodeId> names;
|
||||
for (auto [field_name_node, field] :
|
||||
llvm::zip_equal(field_name_nodes, fields)) {
|
||||
auto result = names.Insert(field.name_id, field_name_node);
|
||||
if (!result.is_inserted()) {
|
||||
CARBON_DIAGNOSTIC(StructNameDuplicate, Error,
|
||||
"duplicated field name `{1}` in "
|
||||
"{0:struct type literal|struct literal}",
|
||||
Diagnostics::BoolAsSelect, SemIR::NameId);
|
||||
CARBON_DIAGNOSTIC_LABEL(StructNamePrevious, Info,
|
||||
"field with the same name here");
|
||||
context.emitter()
|
||||
.Build(result.value(), StructNameDuplicate, is_struct_type_literal,
|
||||
field.name_id)
|
||||
.Attach(field_name_node, StructNamePrevious)
|
||||
.Emit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pops the names of each field from the stack. These will have been left while
|
||||
// handling struct fields.
|
||||
static auto PopFieldNameNodes(Context& context, size_t field_count)
|
||||
-> llvm::SmallVector<Parse::NodeId> {
|
||||
llvm::SmallVector<Parse::NodeId> nodes;
|
||||
nodes.reserve(field_count);
|
||||
for ([[maybe_unused]] auto i : llvm::seq(field_count)) {
|
||||
auto [name_node, _] =
|
||||
context.node_stack().PopWithNodeId<Parse::NodeCategory::MemberName>();
|
||||
nodes.push_back(name_node);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
auto HandleParseNode(Context& context, Parse::StructLiteralId node_id) -> bool {
|
||||
if (!context.node_stack().PeekIs(Parse::NodeCategory::MemberName)) {
|
||||
// Remove the last parameter from the node stack before collecting names.
|
||||
@@ -127,7 +86,7 @@ auto HandleParseNode(Context& context, Parse::StructLiteralId node_id) -> bool {
|
||||
|
||||
auto fields = context.struct_type_fields_stack().PeekArray();
|
||||
llvm::SmallVector<Parse::NodeId> field_name_nodes =
|
||||
PopFieldNameNodes(context, fields.size());
|
||||
PopStructFieldNameNodes(context, fields.size());
|
||||
|
||||
auto elements_id = context.param_and_arg_refs_stack().EndAndPop(
|
||||
Parse::NodeKind::StructLiteralStart);
|
||||
@@ -137,7 +96,7 @@ auto HandleParseNode(Context& context, Parse::StructLiteralId node_id) -> bool {
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::StructLiteralStart>();
|
||||
|
||||
if (DiagnoseDuplicateNames(context, field_name_nodes, fields,
|
||||
/*is_struct_type_literal=*/false)) {
|
||||
StructKind::StructLiteral)) {
|
||||
context.node_stack().Push(node_id, SemIR::ErrorInst::InstId);
|
||||
} else {
|
||||
auto type_id = GetStructType(
|
||||
@@ -156,14 +115,14 @@ auto HandleParseNode(Context& context, Parse::StructTypeLiteralId node_id)
|
||||
-> bool {
|
||||
auto fields = context.struct_type_fields_stack().PeekArray();
|
||||
llvm::SmallVector<Parse::NodeId> field_name_nodes =
|
||||
PopFieldNameNodes(context, fields.size());
|
||||
PopStructFieldNameNodes(context, fields.size());
|
||||
|
||||
context.scope_stack().Pop(/*check_unused=*/true);
|
||||
context.node_stack()
|
||||
.PopAndDiscardSoloNodeId<Parse::NodeKind::StructTypeLiteralStart>();
|
||||
|
||||
if (DiagnoseDuplicateNames(context, field_name_nodes, fields,
|
||||
/*is_struct_type_literal=*/true)) {
|
||||
StructKind::StructTypeLiteral)) {
|
||||
context.node_stack().Push(node_id, SemIR::ErrorInst::InstId);
|
||||
} else {
|
||||
auto fields_id = context.struct_type_fields().AddCanonical(fields);
|
||||
|
||||
@@ -422,6 +422,7 @@ class NodeStack {
|
||||
case Parse::NodeKind::ShortCircuitOperandAnd:
|
||||
case Parse::NodeKind::ShortCircuitOperandOr:
|
||||
case Parse::NodeKind::StructLiteralField:
|
||||
case Parse::NodeKind::StructPatternDesignatedField:
|
||||
return Id::KindFor<SemIR::InstId>();
|
||||
case Parse::NodeKind::ExplicitParamList:
|
||||
case Parse::NodeKind::IfCondition:
|
||||
@@ -477,7 +478,6 @@ class NodeStack {
|
||||
case Parse::NodeKind::ReturnStatementStart:
|
||||
case Parse::NodeKind::StructLiteralStart:
|
||||
case Parse::NodeKind::StructPatternStart:
|
||||
case Parse::NodeKind::StructPatternDesignatedField:
|
||||
case Parse::NodeKind::StructTypeLiteralField:
|
||||
case Parse::NodeKind::StructTypeLiteralStart:
|
||||
case Parse::NodeKind::TemplateBindingName:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
#include "toolchain/sem_ir/expr_info.h"
|
||||
#include "toolchain/sem_ir/generic.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst_kind.h"
|
||||
#include "toolchain/sem_ir/pattern.h"
|
||||
@@ -200,6 +201,8 @@ class MatchContext {
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::TuplePattern tuple_pattern,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::StructPattern struct_pattern,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::SpliceInst splice,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry) -> void;
|
||||
auto DoPreWork(State state, SemIR::SpecificConstant specific_constant,
|
||||
@@ -223,6 +226,8 @@ class MatchContext {
|
||||
WorkItem entry) -> void;
|
||||
auto DoPostWork(State state, SemIR::TuplePattern tuple_pattern,
|
||||
WorkItem entry) -> void;
|
||||
auto DoPostWork(State state, SemIR::StructPattern struct_pattern,
|
||||
WorkItem entry) -> void;
|
||||
auto DoPostWork(State state, SemIR::SpecificConstant specific_constant,
|
||||
WorkItem entry) -> void;
|
||||
auto DoPostWork(State state, SemIR::ImportRefLoaded import_ref,
|
||||
@@ -819,6 +824,105 @@ auto MatchContext::DoPostWork(State /*state*/,
|
||||
results_stack_.AppendToTop(tuple_value_id);
|
||||
}
|
||||
|
||||
auto MatchContext::DoPreWork(State state, SemIR::StructPattern struct_pattern,
|
||||
SemIR::InstId scrutinee_id, WorkItem entry)
|
||||
-> void {
|
||||
if (struct_pattern.type_id == SemIR::ErrorInst::TypeId) {
|
||||
return;
|
||||
}
|
||||
auto subpattern_ids = context_.inst_blocks().Get(struct_pattern.elements_id);
|
||||
if (need_subpattern_results()) {
|
||||
results_stack_.PushArray();
|
||||
AddAsPostWork(entry);
|
||||
}
|
||||
|
||||
if (!scrutinee_id.has_value()) {
|
||||
CARBON_CHECK(std::holds_alternative<CalleeState*>(state) ||
|
||||
std::holds_alternative<ThunkState*>(state));
|
||||
for (auto subpattern_id : llvm::reverse(subpattern_ids)) {
|
||||
AddWork({.pattern_id = subpattern_id,
|
||||
.work = PreWork{.scrutinee_id = SemIR::InstId::None},
|
||||
.allow_unmarked_ref = entry.allow_unmarked_ref});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle `_` fields in the pattern struct. If the final field is `_`,
|
||||
// then number of fields in the expected type will be less than, or equal to,
|
||||
// the number of fields in the scrutinee. Unmatched fields in the scrutinee
|
||||
// should be discarded.
|
||||
auto expected_type_id = GetScrutineeTypeInSpecific(context_, entry.pattern_id,
|
||||
specific_id_stack_.back());
|
||||
|
||||
// TODO: This conversion is required to convert a StructLiteral into a
|
||||
// StructValue, because a StructLiteral scrutinee will produce a
|
||||
// StructAccess inst with a `Mixed` expression category, which can fail when
|
||||
// performing type conversions on fields (E.g., let {.a = b: i32} = {.a = 1}
|
||||
// needs to convert the IntLiteral `1` to an i32). If we can compute the
|
||||
// category of a StructAccess, where the struct being accessed as a `Mixed`
|
||||
// category, then we should be able to remove this conversion.
|
||||
scrutinee_id = ConvertToValueOrRefOfType(
|
||||
context_, SemIR::LocId(entry.pattern_id), scrutinee_id, expected_type_id);
|
||||
|
||||
if (scrutinee_id == SemIR::ErrorInst::InstId) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto scrutinee = context_.insts().GetWithLocId(scrutinee_id);
|
||||
|
||||
auto pattern_struct_type_inst =
|
||||
context_.types().GetAs<SemIR::StructType>(expected_type_id);
|
||||
|
||||
auto pattern_struct_fields =
|
||||
context_.struct_type_fields().Get(pattern_struct_type_inst.fields_id);
|
||||
|
||||
auto scrutinee_struct_type_inst = context_.insts().GetAs<SemIR::StructType>(
|
||||
context_.types().GetTypeInstId(scrutinee.inst.type_id()));
|
||||
|
||||
auto scrutinee_struct_fields =
|
||||
context_.struct_type_fields().Get(scrutinee_struct_type_inst.fields_id);
|
||||
|
||||
llvm::SmallVector<SemIR::InstId> field_access_insts;
|
||||
field_access_insts.reserve(subpattern_ids.size());
|
||||
|
||||
// TODO: This loop is O(m*n) for the number of fields in the
|
||||
// pattern/scrutinee. The nested looping should be removed once struct field
|
||||
// lookup is improved (see related TODO in PerformActionHelper in
|
||||
// member_access.cpp)
|
||||
for (auto field : pattern_struct_fields) {
|
||||
for (auto [i, s_field] : llvm::enumerate(scrutinee_struct_fields)) {
|
||||
if (field.name_id == s_field.name_id) {
|
||||
field_access_insts.push_back(GetOrAddInst<SemIR::StructAccess>(
|
||||
context_, scrutinee.loc_id,
|
||||
{.type_id =
|
||||
context_.types().GetTypeIdForTypeInstId(s_field.type_inst_id),
|
||||
.struct_id = scrutinee_id,
|
||||
.index = SemIR::ElementIndex(i)}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto [subpattern_id, subscrutinee_id] :
|
||||
llvm::reverse(llvm::zip_equal(subpattern_ids, field_access_insts))) {
|
||||
AddWork({.pattern_id = subpattern_id,
|
||||
.work = PreWork{.scrutinee_id = subscrutinee_id},
|
||||
.allow_unmarked_ref = entry.allow_unmarked_ref});
|
||||
}
|
||||
}
|
||||
|
||||
auto MatchContext::DoPostWork(State /*state*/,
|
||||
SemIR::StructPattern /*struct_pattern*/,
|
||||
WorkItem entry) -> void {
|
||||
auto elements_id = context_.inst_blocks().Add(results_stack_.PeekArray());
|
||||
results_stack_.PopArray();
|
||||
auto struct_value_id = AddInst<SemIR::StructValue>(
|
||||
context_, SemIR::LocId(entry.pattern_id),
|
||||
{.type_id = GetScrutineeTypeInSpecific(context_, entry.pattern_id,
|
||||
specific_id_stack_.back()),
|
||||
.elements_id = elements_id});
|
||||
results_stack_.AppendToTop(struct_value_id);
|
||||
}
|
||||
|
||||
// TODO: There is a cycle through pattern matching with an action.
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
auto MatchContext::DoPreWork(State state, SemIR::SpliceInst /*splice*/,
|
||||
@@ -1019,6 +1123,10 @@ auto MatchContext::Dispatch(State state, WorkItem entry) -> void {
|
||||
DoPreWork(state, tuple_pattern, work.scrutinee_id, entry);
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::StructPattern struct_pattern): {
|
||||
DoPreWork(state, struct_pattern, work.scrutinee_id, entry);
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::SpliceInst splice_inst): {
|
||||
DoPreWork(state, splice_inst, work.scrutinee_id, entry);
|
||||
break;
|
||||
@@ -1067,6 +1175,10 @@ auto MatchContext::Dispatch(State state, WorkItem entry) -> void {
|
||||
DoPostWork(state, tuple_pattern, entry);
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::StructPattern struct_pattern): {
|
||||
DoPostWork(state, struct_pattern, entry);
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::SpecificConstant specific_constant): {
|
||||
DoPostWork(state, specific_constant, entry);
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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/struct.h"
|
||||
|
||||
#include "common/map.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
auto PopStructFieldNameNodes(Context& context, size_t field_count)
|
||||
-> llvm::SmallVector<Parse::NodeId> {
|
||||
llvm::SmallVector<Parse::NodeId> nodes;
|
||||
nodes.reserve(field_count);
|
||||
for ([[maybe_unused]] auto i : llvm::seq(field_count)) {
|
||||
auto [name_node, _] =
|
||||
context.node_stack().PopWithNodeId<Parse::NodeCategory::MemberName>();
|
||||
nodes.push_back(name_node);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
// Diagnoses and returns true if there's a duplicate name.
|
||||
auto DiagnoseDuplicateNames(Context& context,
|
||||
llvm::ArrayRef<Parse::NodeId> field_name_nodes,
|
||||
llvm::ArrayRef<SemIR::StructTypeField> fields,
|
||||
StructKind struct_kind_for_diagnostic) -> bool {
|
||||
Map<SemIR::NameId, Parse::NodeId> names;
|
||||
for (auto [field_name_node, field] :
|
||||
llvm::zip_equal(field_name_nodes, fields)) {
|
||||
auto result = names.Insert(field.name_id, field_name_node);
|
||||
if (!result.is_inserted()) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
StructNameDuplicate, Error,
|
||||
"duplicated field name `{1}` in "
|
||||
"{0:=0:struct literal|=1:struct type literal|=2:struct pattern}",
|
||||
Diagnostics::IntAsSelect, SemIR::NameId);
|
||||
CARBON_DIAGNOSTIC_LABEL(StructNamePrevious, Info,
|
||||
"field with the same name here");
|
||||
context.emitter()
|
||||
.Build(result.value(), StructNameDuplicate,
|
||||
static_cast<int>(struct_kind_for_diagnostic), field.name_id)
|
||||
.Attach(field_name_node, StructNamePrevious)
|
||||
.Emit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
@@ -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
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_CHECK_STRUCT_H_
|
||||
#define CARBON_TOOLCHAIN_CHECK_STRUCT_H_
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/struct_type_field.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
// Struct kinds, for diagnostics. Converted to an int for a format select.
|
||||
enum class StructKind : uint8_t {
|
||||
StructLiteral = 0,
|
||||
StructTypeLiteral = 1,
|
||||
StructPattern = 2
|
||||
};
|
||||
|
||||
// Pops the names of each field from the stack. These will have been left while
|
||||
// handling struct fields.
|
||||
auto PopStructFieldNameNodes(Context& context, size_t field_count)
|
||||
-> llvm::SmallVector<Parse::NodeId>;
|
||||
|
||||
// Diagnoses and returns true if there's a duplicate name.
|
||||
auto DiagnoseDuplicateNames(Context& context,
|
||||
llvm::ArrayRef<Parse::NodeId> field_name_nodes,
|
||||
llvm::ArrayRef<SemIR::StructTypeField> fields,
|
||||
StructKind struct_kind_for_diagnostic) -> bool;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_STRUCT_H_
|
||||
+1288
File diff suppressed because it is too large.
Load diff
@@ -303,6 +303,7 @@ CARBON_DIAGNOSTIC_KIND(ClassSpecificDeclOutsideClass)
|
||||
CARBON_DIAGNOSTIC_KIND(ClassForwardDeclaredHere)
|
||||
CARBON_DIAGNOSTIC_KIND(ClassIncompleteWithinDefinition)
|
||||
CARBON_DIAGNOSTIC_KIND(FieldNamedUnderscore)
|
||||
CARBON_DIAGNOSTIC_KIND(FieldWithStructPattern)
|
||||
CARBON_DIAGNOSTIC_KIND(FieldWithTuplePattern)
|
||||
CARBON_DIAGNOSTIC_KIND(FriendNotAllowedInScope)
|
||||
CARBON_DIAGNOSTIC_KIND(FriendNotNameScope)
|
||||
|
||||
@@ -281,7 +281,9 @@ static auto HandleBindingPatternFinish(Context& context, StateKind finish_kind)
|
||||
|
||||
auto node_kind = NodeKind::InvalidParse;
|
||||
if (state.in_var_pattern) {
|
||||
node_kind = NodeKind::VarBindingPattern;
|
||||
node_kind = state.in_field_shorthand_pattern
|
||||
? NodeKind::StructPatternFieldVarBindingPattern
|
||||
: NodeKind::VarBindingPattern;
|
||||
if (finish_kind != StateKind::BindingPatternFinishAsRegular) {
|
||||
CARBON_DIAGNOSTIC(NonRegularBindingInVarDecl, Error,
|
||||
"found {0:generic|`:?`} binding inside `var` pattern",
|
||||
@@ -297,7 +299,9 @@ static auto HandleBindingPatternFinish(Context& context, StateKind finish_kind)
|
||||
node_kind = NodeKind::CompileTimeBindingPattern;
|
||||
break;
|
||||
case StateKind::BindingPatternFinishAsRegular:
|
||||
node_kind = NodeKind::LetBindingPattern;
|
||||
node_kind = state.in_field_shorthand_pattern
|
||||
? NodeKind::StructPatternFieldLetBindingPattern
|
||||
: NodeKind::LetBindingPattern;
|
||||
break;
|
||||
case StateKind::BindingPatternFinishAsForm:
|
||||
node_kind = NodeKind::FormBindingPattern;
|
||||
|
||||
@@ -220,6 +220,8 @@ CARBON_PARSE_NODE_KIND_PATTERN(ParenPattern)
|
||||
CARBON_PARSE_NODE_KIND_PATTERN(TuplePattern)
|
||||
|
||||
CARBON_PARSE_NODE_KIND_PATTERN(StructPatternStart)
|
||||
CARBON_PARSE_NODE_KIND_PATTERN(StructPatternFieldLetBindingPattern)
|
||||
CARBON_PARSE_NODE_KIND_PATTERN(StructPatternFieldVarBindingPattern)
|
||||
CARBON_PARSE_NODE_KIND_PATTERN(StructPatternDesignatedField)
|
||||
CARBON_PARSE_NODE_KIND_PATTERN(StructPattern)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ let {s};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 's'
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '}' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '}' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern 's' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern 's' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: ├─LetDecl ';'
|
||||
// CHECK:STDOUT: ├─FileEnd ''
|
||||
|
||||
+5
-5
@@ -70,12 +70,12 @@ let {ref s: str, i: i32} = {.s = "hello ref shorthand", .i = 4};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 's'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StringTypeLiteral 'str'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'i'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -107,7 +107,7 @@ let {ref s: str, i: i32} = {.s = "hello ref shorthand", .i = 4};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'i'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -168,12 +168,12 @@ let {ref s: str, i: i32} = {.s = "hello ref shorthand", .i = 4};
|
||||
// CHECK:STDOUT: │ │ │ ╭─RefBindingName 'ref'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StringTypeLiteral 'str'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'i'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
|
||||
+32
-32
@@ -370,12 +370,12 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -391,12 +391,12 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─RefBindingName 'ref'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -419,7 +419,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'm'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -434,7 +434,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructFieldDesignator '.'
|
||||
@@ -464,7 +464,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructFieldDesignator '.'
|
||||
@@ -472,12 +472,12 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'a'
|
||||
// CHECK:STDOUT: │ │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'b'
|
||||
// CHECK:STDOUT: │ │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternDesignatedField '='
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
@@ -494,7 +494,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature ',' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse ',' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse ',' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ',' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ',' has_error
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
@@ -510,7 +510,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature '=' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '=' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '=' has_error
|
||||
// CHECK:STDOUT: │ │ │ ╭─LetBindingPattern '=' has_error
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternFieldLetBindingPattern '=' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '='
|
||||
// CHECK:STDOUT: │ │ │ ├─IdentifierNameExpr 'y'
|
||||
// CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error
|
||||
@@ -599,7 +599,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature ',' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse ',' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse ',' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ',' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ',' has_error
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
@@ -650,7 +650,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature ':' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -665,7 +665,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '}' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -680,7 +680,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -785,7 +785,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'foo'
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '.' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '.' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern 'foo' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern 'foo' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -800,12 +800,12 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -820,12 +820,12 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'foo'
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse 'y' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse 'y' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern 'foo' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern 'foo' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -840,7 +840,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature '!' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '!' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '!' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern '!' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern '!' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -917,7 +917,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature '"foo"' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '"foo"' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─InvalidParse '"foo"' has_error
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern '"foo"' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern '"foo"' has_error
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructFieldDesignator '.'
|
||||
@@ -941,13 +941,13 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─TuplePatternStart '('
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'z'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
@@ -969,13 +969,13 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─TuplePatternStart '('
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'z'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
@@ -997,18 +997,18 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternStart '{'
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'z'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
@@ -1024,7 +1024,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─UnderscoreName '_'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ ╭─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─VariablePattern 'var'
|
||||
// CHECK:STDOUT: │ ├─VariableInitializer '='
|
||||
@@ -1037,7 +1037,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─RefBindingName 'ref' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
// CHECK:STDOUT: │ │ ╭─StructLiteralStart '{'
|
||||
@@ -1048,7 +1048,7 @@ let {var _: i32} = {};
|
||||
// CHECK:STDOUT: │ │ │ ╭─UnderscoreName '_'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':' has_error
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternFieldVarBindingPattern ':' has_error
|
||||
// CHECK:STDOUT: │ │ ├─VariablePattern 'var' has_error
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}' has_error
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
|
||||
+8
-8
@@ -316,7 +316,7 @@ var unused (unused y: i32) = (0,);
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ╭─UnusedPattern 'unused'
|
||||
// CHECK:STDOUT: │ │ ├─VariablePattern 'var'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
@@ -337,7 +337,7 @@ var unused (unused y: i32) = (0,);
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ╭─VariablePattern 'var'
|
||||
// CHECK:STDOUT: │ │ ├─UnusedPattern 'unused'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
@@ -350,12 +350,12 @@ var unused (unused y: i32) = (0,);
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─LetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldLetBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ╭─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─UnusedPattern 'unused'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
@@ -367,12 +367,12 @@ var unused (unused y: i32) = (0,);
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─UnusedPattern 'unused'
|
||||
// CHECK:STDOUT: │ │ ╭─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─VariablePattern 'var'
|
||||
@@ -385,12 +385,12 @@ var unused (unused y: i32) = (0,);
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'x'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'y'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ╭─StructPattern '}'
|
||||
// CHECK:STDOUT: │ │ ╭─UnusedPattern 'unused'
|
||||
// CHECK:STDOUT: │ ├─VariablePattern 'var'
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ let (x: (), var (y: (), var z: ())) = ((), ((), ()));
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ │ ╭─TupleLiteralStart '('
|
||||
// CHECK:STDOUT: │ │ │ ├─TupleLiteral ')'
|
||||
// CHECK:STDOUT: │ │ │ ╭─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ │ ╭─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─VariablePattern 'var'
|
||||
// CHECK:STDOUT: │ ├─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─LetInitializer '='
|
||||
|
||||
+3
-3
@@ -63,12 +63,12 @@ var {.s = s: str, i: 32} = {.s = "hello mixed", .i = 1};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 's'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─StringTypeLiteral 'str'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─PatternListComma ','
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'i'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntLiteral '32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ╭─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─VariablePattern 'var'
|
||||
// CHECK:STDOUT: │ ├─VariableInitializer '='
|
||||
@@ -101,7 +101,7 @@ var {.s = s: str, i: 32} = {.s = "hello mixed", .i = 1};
|
||||
// CHECK:STDOUT: │ │ │ ╭─IdentifierNameNotBeforeSignature 'i'
|
||||
// CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':'
|
||||
// CHECK:STDOUT: │ │ │ ├─IntLiteral '32'
|
||||
// CHECK:STDOUT: │ │ ├─VarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ├─StructPatternFieldVarBindingPattern ':'
|
||||
// CHECK:STDOUT: │ │ ╭─StructPattern '}'
|
||||
// CHECK:STDOUT: │ ├─VariablePattern 'var'
|
||||
// CHECK:STDOUT: │ ├─VariableInitializer '='
|
||||
|
||||
@@ -1594,6 +1594,36 @@ struct StructTypeLiteral {
|
||||
using StructPatternStart =
|
||||
LeafNode<NodeKind::StructPatternStart, Lex::OpenCurlyBraceTokenIndex>;
|
||||
|
||||
// shorthand let binding in a struct pattern such as `let {a: i32}`.
|
||||
struct StructPatternFieldLetBindingPattern {
|
||||
static constexpr auto Kind =
|
||||
NodeKind::StructPatternFieldLetBindingPattern.Define(
|
||||
{.category = NodeCategory::Pattern, .child_count = 3});
|
||||
|
||||
// TODO: is there some way to reuse AnyRuntimeBindingPatternName here?
|
||||
NodeIdOneOf<IdentifierNameNotBeforeSignature, SelfValueName, UnderscoreName,
|
||||
RefBindingName, RuntimeBindingName>
|
||||
name;
|
||||
BindingPatternTypeStartId introducer;
|
||||
Lex::ColonTokenIndex token;
|
||||
AnyExprId type;
|
||||
};
|
||||
|
||||
// shorthand var binding in a struct pattern such as `var {a: i32}`.
|
||||
struct StructPatternFieldVarBindingPattern {
|
||||
static constexpr auto Kind =
|
||||
NodeKind::StructPatternFieldVarBindingPattern.Define(
|
||||
{.category = NodeCategory::Pattern, .child_count = 3});
|
||||
|
||||
// TODO: is there some way to reuse AnyRuntimeBindingPatternName here?
|
||||
NodeIdOneOf<IdentifierNameNotBeforeSignature, SelfValueName, UnderscoreName,
|
||||
RuntimeBindingName>
|
||||
name;
|
||||
BindingPatternTypeStartId introducer;
|
||||
Lex::ColonTokenIndex token;
|
||||
AnyExprId type;
|
||||
};
|
||||
|
||||
// `.a = pattern`
|
||||
struct StructPatternDesignatedField {
|
||||
static constexpr auto Kind = NodeKind::StructPatternDesignatedField.Define(
|
||||
@@ -1605,8 +1635,9 @@ struct StructPatternDesignatedField {
|
||||
};
|
||||
|
||||
using StructPatternFieldId =
|
||||
NodeIdOneOf<StructPatternDesignatedField, LetBindingPattern,
|
||||
VariablePattern, VarBindingPattern, UnusedPattern,
|
||||
NodeIdOneOf<StructPatternDesignatedField,
|
||||
StructPatternFieldLetBindingPattern, VariablePattern,
|
||||
StructPatternFieldVarBindingPattern, UnusedPattern,
|
||||
UnderscoreName, DefaultValuePattern>;
|
||||
|
||||
struct StructPattern {
|
||||
|
||||
@@ -160,6 +160,7 @@ CARBON_SEM_IR_INST_KIND(StringLiteral)
|
||||
CARBON_SEM_IR_INST_KIND(StructAccess)
|
||||
CARBON_SEM_IR_INST_KIND(StructInit)
|
||||
CARBON_SEM_IR_INST_KIND(StructLiteral)
|
||||
CARBON_SEM_IR_INST_KIND(StructPattern)
|
||||
CARBON_SEM_IR_INST_KIND(StructType)
|
||||
CARBON_SEM_IR_INST_KIND(StructValue)
|
||||
CARBON_SEM_IR_INST_KIND(SymbolicBinding)
|
||||
|
||||
@@ -65,7 +65,11 @@ auto GetFirstBindingNameFromPatternId(const File& sem_ir, InstId pattern_id)
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Look through struct patterns.
|
||||
if (auto struct_patt = inst.TryAs<StructPattern>()) {
|
||||
auto block = sem_ir.inst_blocks().Get(struct_patt->elements_id);
|
||||
work_list.append(block.rbegin(), block.rend());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto ref_pattern = inst.TryAs<RefParamPattern>()) {
|
||||
// TODO: This introduces a name, but we don't model it as a binding.
|
||||
|
||||
@@ -2177,6 +2177,21 @@ struct StructLiteral {
|
||||
InstBlockId elements_id;
|
||||
};
|
||||
|
||||
// A struct pattern, such as `{.x = y: i32, z: i32}`.
|
||||
struct StructPattern {
|
||||
static constexpr auto Kind =
|
||||
InstKind::StructPattern.Define<Parse::StructPatternId>(
|
||||
{.ir_name = "struct_pattern",
|
||||
.expr_category = ExprCategory::Pattern,
|
||||
.constant_kind = InstConstantKind::Always,
|
||||
.is_lowered = false});
|
||||
|
||||
// Always a PatternType whose scrutinee type is a struct of the scrutinee
|
||||
// types of the elements.
|
||||
TypeId type_id;
|
||||
InstBlockId elements_id;
|
||||
};
|
||||
|
||||
// The type of a struct.
|
||||
struct StructType {
|
||||
static constexpr auto Kind = InstKind::StructType.Define<
|
||||
|
||||
Reference in new issue
Block a user