diff --git a/toolchain/check/handle_pattern_list.cpp b/toolchain/check/handle_pattern_list.cpp index ab9b3f008c8b..0be2f7b5bc7f 100644 --- a/toolchain/check/handle_pattern_list.cpp +++ b/toolchain/check/handle_pattern_list.cpp @@ -157,6 +157,14 @@ auto HandleParseNode(Context& context, Parse::DefaultValueUnspecifiedId node_id) return context.TODO(node_id, "pattern default values"); } +auto HandleParseNode(Context& context, + Parse::DefaultValueExprStartId /*node_id*/) -> bool { + // We want to check the default value expression as a normal expression, + // and not convert it into a pattern. + EndEmptyExprRegionForPattern(context); + return true; +} + auto HandleParseNode(Context& context, Parse::DefaultValuePatternId node_id) -> bool { // On entry, the top of the node stack should have an expression for the @@ -205,6 +213,9 @@ auto HandleParseNode(Context& context, Parse::DefaultValuePatternId node_id) .default_value_id = default_value_id}); context.node_stack().Push(node_id, default_value_inst_id); + // We turned off expr region for pattern checking while parsing the default + // value expression, so turn it back on again for further pattern checking. + BeginExprRegionForPattern(context); return true; } diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index e1e065691d82..7210f9d04f69 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -498,6 +498,7 @@ class NodeStack { case Parse::NodeKind::ContinueStatementStart: case Parse::NodeKind::CorePackageName: case Parse::NodeKind::CppPackageName: + case Parse::NodeKind::DefaultValueExprStart: case Parse::NodeKind::ExportIntroducer: case Parse::NodeKind::FileEnd: case Parse::NodeKind::FileStart: diff --git a/toolchain/check/testdata/function/declaration/default_values.carbon b/toolchain/check/testdata/function/declaration/default_values.carbon index 8ec9f4a85605..a277684f419f 100644 --- a/toolchain/check/testdata/function/declaration/default_values.carbon +++ b/toolchain/check/testdata/function/declaration/default_values.carbon @@ -64,6 +64,13 @@ library "[[@TEST_NAME]]"; // CHECK:STDERR: fn Z(v: i32, x: i32 = 3, (y: i32 = 2, z: i32), w: i32 = 4, k: i32); +// --- nested.carbon +library "[[@TEST_NAME]]"; + +//@dump-sem-ir-begin +fn F(a: i32, (b: i32, (c: i32, (d: i32, e: i32))) = (1, (2, (3, 4)))); +//@dump-sem-ir-end + // --- basic.carbon library "[[@TEST_NAME]]"; @@ -72,6 +79,96 @@ library "[[@TEST_NAME]]"; fn F(x: i32 = 0); //@dump-sem-ir-end +// CHECK:STDOUT: --- nested.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %pattern_type.6b6: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %a.param_patt: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %a.patt: %pattern_type.6b6 = wrapper_binding_pattern a, %a.param_patt [concrete] +// CHECK:STDOUT: %b.param_patt: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %b.patt: %pattern_type.6b6 = wrapper_binding_pattern b, %b.param_patt [concrete] +// CHECK:STDOUT: %c.param_patt: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %c.patt: %pattern_type.6b6 = wrapper_binding_pattern c, %c.param_patt [concrete] +// CHECK:STDOUT: %d.param_patt: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %d.patt: %pattern_type.6b6 = wrapper_binding_pattern d, %d.param_patt [concrete] +// CHECK:STDOUT: %e.param_patt: %pattern_type.6b6 = value_param_pattern [concrete] +// CHECK:STDOUT: %e.patt: %pattern_type.6b6 = wrapper_binding_pattern e, %e.param_patt [concrete] +// CHECK:STDOUT: %tuple.type.e55: type = tuple_type (%i32, %i32) [concrete] +// CHECK:STDOUT: %pattern_type.394: type = pattern_type %tuple.type.e55 [concrete] +// CHECK:STDOUT: %.70d: %pattern_type.394 = tuple_pattern (%d.patt, %e.patt) [concrete] +// CHECK:STDOUT: %tuple.type.920: type = tuple_type (%i32, %tuple.type.e55) [concrete] +// CHECK:STDOUT: %pattern_type.e87: type = pattern_type %tuple.type.920 [concrete] +// CHECK:STDOUT: %.aa9: %pattern_type.e87 = tuple_pattern (%c.patt, %.70d) [concrete] +// CHECK:STDOUT: %tuple.type.007: type = tuple_type (%i32, %tuple.type.920) [concrete] +// CHECK:STDOUT: %pattern_type.802: type = pattern_type %tuple.type.007 [concrete] +// CHECK:STDOUT: %.203: %pattern_type.802 = tuple_pattern (%b.patt, %.aa9) [concrete] +// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] +// CHECK:STDOUT: %int_2.ecc: Core.IntLiteral = int_value 2 [concrete] +// CHECK:STDOUT: %int_3.1ba: Core.IntLiteral = int_value 3 [concrete] +// CHECK:STDOUT: %int_4.0c1: Core.IntLiteral = int_value 4 [concrete] +// CHECK:STDOUT: %tuple.type.f94: type = tuple_type (Core.IntLiteral, Core.IntLiteral) [concrete] +// CHECK:STDOUT: %tuple.302: %tuple.type.f94 = tuple_value (%int_3.1ba, %int_4.0c1) [concrete] +// CHECK:STDOUT: %tuple.type.bd0: type = tuple_type (Core.IntLiteral, %tuple.type.f94) [concrete] +// CHECK:STDOUT: %tuple.b26: %tuple.type.bd0 = tuple_value (%int_2.ecc, %tuple.302) [concrete] +// CHECK:STDOUT: %tuple.type.c4f: type = tuple_type (Core.IntLiteral, %tuple.type.bd0) [concrete] +// CHECK:STDOUT: %tuple.326: %tuple.type.c4f = tuple_value (%int_1.5b8, %tuple.b26) [concrete] +// CHECK:STDOUT: %.19b: %pattern_type.802 = default_value_pattern %.203, index: 0 [concrete] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %a.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%a.param_patt] +// CHECK:STDOUT: %a.patt: %pattern_type.6b6 = wrapper_binding_pattern a, %a.param_patt [concrete = constants.%a.patt] +// CHECK:STDOUT: %b.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%b.param_patt] +// CHECK:STDOUT: %b.patt: %pattern_type.6b6 = wrapper_binding_pattern b, %b.param_patt [concrete = constants.%b.patt] +// CHECK:STDOUT: %c.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%c.param_patt] +// CHECK:STDOUT: %c.patt: %pattern_type.6b6 = wrapper_binding_pattern c, %c.param_patt [concrete = constants.%c.patt] +// CHECK:STDOUT: %d.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%d.param_patt] +// CHECK:STDOUT: %d.patt: %pattern_type.6b6 = wrapper_binding_pattern d, %d.param_patt [concrete = constants.%d.patt] +// CHECK:STDOUT: %e.param_patt: %pattern_type.6b6 = value_param_pattern [concrete = constants.%e.param_patt] +// CHECK:STDOUT: %e.patt: %pattern_type.6b6 = wrapper_binding_pattern e, %e.param_patt [concrete = constants.%e.patt] +// CHECK:STDOUT: %.loc4_47: %pattern_type.394 = tuple_pattern (%d.patt, %e.patt) [concrete = constants.%.70d] +// CHECK:STDOUT: %.loc4_48: %pattern_type.e87 = tuple_pattern (%c.patt, %.loc4_47) [concrete = constants.%.aa9] +// CHECK:STDOUT: %.loc4_49: %pattern_type.802 = tuple_pattern (%b.patt, %.loc4_48) [concrete = constants.%.203] +// CHECK:STDOUT: %.loc4_51: %pattern_type.802 = default_value_pattern %.loc4_49, index: 0 [concrete = constants.%.19b] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] +// CHECK:STDOUT: %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc] +// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba] +// CHECK:STDOUT: %int_4: Core.IntLiteral = int_value 4 [concrete = constants.%int_4.0c1] +// CHECK:STDOUT: %.loc4_66: %tuple.type.f94 = tuple_literal (%int_3, %int_4) [concrete = constants.%tuple.302] +// CHECK:STDOUT: %.loc4_67: %tuple.type.bd0 = tuple_literal (%int_2, %.loc4_66) [concrete = constants.%tuple.b26] +// CHECK:STDOUT: %.loc4_68: %tuple.type.c4f = tuple_literal (%int_1, %.loc4_67) [concrete = constants.%tuple.326] +// CHECK:STDOUT: %a.param: %i32 = value_param call_param0 +// CHECK:STDOUT: %i32.loc4_9: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %a: %i32 = wrapper_binding a, %a.param +// CHECK:STDOUT: %b.param: %i32 = value_param call_param1 +// CHECK:STDOUT: %i32.loc4_18: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %b: %i32 = wrapper_binding b, %b.param +// CHECK:STDOUT: %c.param: %i32 = value_param call_param2 +// CHECK:STDOUT: %i32.loc4_27: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %c: %i32 = wrapper_binding c, %c.param +// CHECK:STDOUT: %d.param: %i32 = value_param call_param3 +// CHECK:STDOUT: %i32.loc4_36: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %d: %i32 = wrapper_binding d, %d.param +// CHECK:STDOUT: %e.param: %i32 = value_param call_param4 +// CHECK:STDOUT: %i32.loc4_44: type = type_literal constants.%i32 [concrete = constants.%i32] +// CHECK:STDOUT: %e: %i32 = wrapper_binding e, %e.param +// CHECK:STDOUT: %tuple.loc4_47: %tuple.type.e55 = tuple_value (%d.param, %e.param) +// CHECK:STDOUT: %tuple.loc4_48: %tuple.type.920 = tuple_value (%c.param, %tuple.loc4_47) +// CHECK:STDOUT: %tuple.loc4_49: %tuple.type.007 = tuple_value (%b.param, %tuple.loc4_48) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%a.param: %i32, %b.param: %i32, %c.param: %i32, %d.param: %i32, %e.param: %i32) default_values: { +// CHECK:STDOUT: constants.%tuple.326: %tuple.type.c4f = tuple_value (constants.%int_1.5b8, constants.%tuple.b26) [concrete] +// CHECK:STDOUT: }; +// CHECK:STDOUT: // CHECK:STDOUT: --- basic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/lex/token_kind.def b/toolchain/lex/token_kind.def index bd5b90b2f4e8..29cf3eb19843 100644 --- a/toolchain/lex/token_kind.def +++ b/toolchain/lex/token_kind.def @@ -92,7 +92,8 @@ CARBON_SYMBOL_TOKEN(Backslash, "\\") CARBON_SYMBOL_TOKEN(Caret, "^") CARBON_TOKEN_WITH_VIRTUAL_NODE( CARBON_SYMBOL_TOKEN(Colon, ":")) -CARBON_SYMBOL_TOKEN(Equal, "=") +CARBON_TOKEN_WITH_VIRTUAL_NODE( + CARBON_SYMBOL_TOKEN(Equal, "=")) CARBON_SYMBOL_TOKEN(Exclaim, "!") CARBON_SYMBOL_TOKEN(Greater, ">") CARBON_SYMBOL_TOKEN(Less, "<") diff --git a/toolchain/parse/handle_pattern_list.cpp b/toolchain/parse/handle_pattern_list.cpp index 8b9134b6f12b..bdf378af81d1 100644 --- a/toolchain/parse/handle_pattern_list.cpp +++ b/toolchain/parse/handle_pattern_list.cpp @@ -175,6 +175,10 @@ auto HandlePatternListElementCheckForDefaultValue(Context& context) -> void { return; } + // Add the first virtual node surrounding the value expr node, to facilitate + // handling in check. + context.AddLeafNode(NodeKind::DefaultValueExprStart, *equals_token); + state.token = *equals_token; state.kind = StateKind::PatternListElementFinishDefaultValue; context.PushState(state); diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index e03c1eb070a7..ab645b46b918 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -242,6 +242,7 @@ CARBON_PARSE_NODE_KIND_PATTERN(FormBindingPattern) CARBON_PARSE_NODE_KIND_PATTERN(TemplateBindingName) CARBON_PARSE_NODE_KIND_PATTERN(CompileTimeBindingPatternTypeStart) CARBON_PARSE_NODE_KIND_PATTERN(CompileTimeBindingPattern) +CARBON_PARSE_NODE_KIND_PATTERN(DefaultValueExprStart) CARBON_PARSE_NODE_KIND_PATTERN(DefaultValuePattern) CARBON_PARSE_NODE_KIND_EXPRESSION(DefaultValueUnspecified) diff --git a/toolchain/parse/testdata/function/default_values.carbon b/toolchain/parse/testdata/function/default_values.carbon index 4575139b3ea6..05de54f497d6 100644 --- a/toolchain/parse/testdata/function/default_values.carbon +++ b/toolchain/parse/testdata/function/default_values.carbon @@ -29,6 +29,7 @@ fn I(x: i32 = _); // CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':' // CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32' // CHECK:STDOUT: │ │ │ ╭─LetBindingPattern ':' +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─IntLiteral '0' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' // CHECK:STDOUT: │ ├─ExplicitParamList ')' @@ -47,6 +48,7 @@ fn I(x: i32 = _); // CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' // CHECK:STDOUT: │ │ │ ├─LetBindingPattern ':' // CHECK:STDOUT: │ │ │ ╭─TuplePattern ')' +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ │ ╭─TupleLiteralStart '(' // CHECK:STDOUT: │ │ │ │ ├─IntLiteral '1' // CHECK:STDOUT: │ │ │ │ ├─TupleLiteralComma ',' @@ -63,6 +65,7 @@ fn I(x: i32 = _); // CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32' // CHECK:STDOUT: │ │ │ ╭─LetBindingPattern ':' // CHECK:STDOUT: │ │ │ ╭─UnusedPattern 'unused' +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─IntLiteral '25' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' // CHECK:STDOUT: │ ├─ExplicitParamList ')' @@ -80,6 +83,7 @@ fn I(x: i32 = _); // CHECK:STDOUT: │ │ │ │ ├─BindingPatternTypeStart ':' // CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' // CHECK:STDOUT: │ │ │ │ ╭─LetBindingPattern ':' +// CHECK:STDOUT: │ │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ │ ├─IntLiteral '0' // CHECK:STDOUT: │ │ │ ├─DefaultValuePattern '=' // CHECK:STDOUT: │ │ ├─ExplicitParamList ')' @@ -94,6 +98,7 @@ fn I(x: i32 = _); // CHECK:STDOUT: │ │ │ ├─BindingPatternTypeStart ':' // CHECK:STDOUT: │ │ │ ├─IntTypeLiteral 'i32' // CHECK:STDOUT: │ │ │ ╭─LetBindingPattern ':' +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─DefaultValueUnspecified '_' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' // CHECK:STDOUT: │ ├─ExplicitParamList ')' diff --git a/toolchain/parse/testdata/struct/struct_pattern.carbon b/toolchain/parse/testdata/struct/struct_pattern.carbon index e9c05666ce29..1a5584593895 100644 --- a/toolchain/parse/testdata/struct/struct_pattern.carbon +++ b/toolchain/parse/testdata/struct/struct_pattern.carbon @@ -567,6 +567,7 @@ let {var _: i32} = {}; // CHECK:STDOUT: │ ╭─LetIntroducer 'let' // CHECK:STDOUT: │ │ ╭─StructPatternStart '{' // CHECK:STDOUT: │ │ │ ╭─InvalidParse '=' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─IdentifierNameExpr 'y' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error // CHECK:STDOUT: │ ├─StructPattern '}' has_error @@ -834,6 +835,7 @@ let {var _: i32} = {}; // CHECK:STDOUT: │ │ │ ╭─IdentifierNameExpr 'foo' // CHECK:STDOUT: │ │ │ ├─IdentifierNameNotBeforeSignature 'y' // CHECK:STDOUT: │ │ │ ╭─MemberAccessExpr '.' +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─IdentifierNameExpr 'y' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' // CHECK:STDOUT: │ ├─StructPattern '}' has_error @@ -959,6 +961,7 @@ let {var _: i32} = {}; // CHECK:STDOUT: │ ╭─LetIntroducer 'let' // CHECK:STDOUT: │ │ ╭─StructPatternStart '{' // CHECK:STDOUT: │ │ │ ╭─StringLiteral '"foo"' +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─InvalidParse ',' has_error // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error // CHECK:STDOUT: │ │ ├─PatternListComma ',' diff --git a/toolchain/parse/testdata/where_expr/fail_rewrite.carbon b/toolchain/parse/testdata/where_expr/fail_rewrite.carbon index 90db37d1dbcb..55530e3ee832 100644 --- a/toolchain/parse/testdata/where_expr/fail_rewrite.carbon +++ b/toolchain/parse/testdata/where_expr/fail_rewrite.carbon @@ -79,6 +79,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─IntTypeLiteral 'i32' // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'U' // CHECK:STDOUT: │ │ │ ├─DesignatorExpr '.' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error @@ -101,6 +102,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─ParenExpr ')' // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─BoolTypeLiteral 'bool' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error // CHECK:STDOUT: │ ├─ExplicitParamList ')' has_error @@ -120,6 +122,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─DesignatorExpr '.' // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─FloatTypeLiteral 'f32' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error // CHECK:STDOUT: │ ├─ExplicitParamList ')' has_error @@ -139,6 +142,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─DesignatorExpr '.' has_error // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ ├─UnsignedIntTypeLiteral 'u8' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error // CHECK:STDOUT: │ ├─ExplicitParamList ')' has_error @@ -159,6 +163,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─PostfixOperatorStar '*' // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ │ ╭─UnsignedIntTypeLiteral 'u64' // CHECK:STDOUT: │ │ │ ├─PostfixOperatorStar '*' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error @@ -182,6 +187,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─InfixOperatorPlus '+' // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ │ ╭─StructLiteralStart '{' // CHECK:STDOUT: │ │ │ ├─StructLiteral '}' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error @@ -207,6 +213,7 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A); // CHECK:STDOUT: │ │ │ │ ├─TupleLiteral ')' // CHECK:STDOUT: │ │ │ ├─WhereExpr 'where' has_error // CHECK:STDOUT: │ │ │ ╭─CompileTimeBindingPattern ':' has_error +// CHECK:STDOUT: │ │ │ ├─DefaultValueExprStart '=' // CHECK:STDOUT: │ │ │ │ ╭─IdentifierNameNotBeforeSignature 'A' // CHECK:STDOUT: │ │ │ ├─DesignatorExpr '.' // CHECK:STDOUT: │ │ ├─DefaultValuePattern '=' has_error diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 09762792a911..39c655367802 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -377,13 +377,22 @@ using DefaultValueUnspecified = LeafNode; +struct DefaultValueExprStart { + static constexpr auto Kind = + NodeKind::DefaultValueExprStart.Define({.child_count = 0}); + // This is a virtual token. The `=` token is owned by the + // DefaultValuePattern node. + Lex::EqualTokenIndex token; +}; + // A pattern with a default value specified: `pattern = expr`. struct DefaultValuePattern { static constexpr auto Kind = NodeKind::DefaultValuePattern.Define( - {.category = NodeCategory::Pattern, .child_count = 2}); + {.category = NodeCategory::Pattern, .child_count = 3}); AnyPatternId pattern; Lex::EqualTokenIndex token; + DefaultValueExprStartId start; AnyExprId default_value_expr; };