Skip to content

Commit fc5631b

Browse files
committed
Unused binding marker and diagnostics, part 1: parsing
Modifies the parser to accept "unused" as a pattern operator. Handling in "check" is left as TODO here and implemented in the next part. Updates a single test that contain "unused" identifier.
1 parent 103c49a commit fc5631b

File tree

10 files changed

+155
-45
lines changed

10 files changed

+155
-45
lines changed

toolchain/check/handle_binding_pattern.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,4 +414,8 @@ auto HandleParseNode(Context& context, Parse::TemplateBindingNameId node_id)
414414
return true;
415415
}
416416

417+
auto HandleParseNode(Context& context, Parse::UnusedPatternId node_id) -> bool {
418+
return context.TODO(node_id, "unused");
419+
}
420+
417421
} // namespace Carbon::Check

toolchain/check/testdata/class/import_base.carbon

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ base class Base {
2121
fn Unused[self: Self]();
2222

2323
var x: i32;
24-
var unused: i32;
24+
var unused_y: i32;
2525
}
2626

2727
class Child {
@@ -35,7 +35,7 @@ library "[[@TEST_NAME]]";
3535
import library "a";
3636

3737
fn Run() {
38-
var a: Child = {.base = {.x = 0, .unused = 1}};
38+
var a: Child = {.base = {.x = 0, .unused_y = 1}};
3939
a.x = 2;
4040
a.F();
4141
}
@@ -54,8 +54,8 @@ fn Run() {
5454
// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete]
5555
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
5656
// CHECK:STDOUT: %Base.elem: type = unbound_element_type %Base, %i32 [concrete]
57-
// CHECK:STDOUT: %struct_type.x.unused: type = struct_type {.x: %i32, .unused: %i32} [concrete]
58-
// CHECK:STDOUT: %complete_type.20c: <witness> = complete_type_witness %struct_type.x.unused [concrete]
57+
// CHECK:STDOUT: %struct_type.x.unused_y: type = struct_type {.x: %i32, .unused_y: %i32} [concrete]
58+
// CHECK:STDOUT: %complete_type.cf1: <witness> = complete_type_witness %struct_type.x.unused_y [concrete]
5959
// CHECK:STDOUT: %Child: type = class_type @Child [concrete]
6060
// CHECK:STDOUT: %Child.elem: type = unbound_element_type %Child, %Base [concrete]
6161
// CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %Base} [concrete]
@@ -104,16 +104,16 @@ fn Run() {
104104
// CHECK:STDOUT: %.loc8: %Base.elem = field_decl x, element0 [concrete]
105105
// CHECK:STDOUT: %int_32.loc9: Core.IntLiteral = int_value 32 [concrete = constants.%int_32]
106106
// CHECK:STDOUT: %i32.loc9: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32]
107-
// CHECK:STDOUT: %.loc9: %Base.elem = field_decl unused, element1 [concrete]
108-
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%struct_type.x.unused [concrete = constants.%complete_type.20c]
107+
// CHECK:STDOUT: %.loc9: %Base.elem = field_decl unused_y, element1 [concrete]
108+
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%struct_type.x.unused_y [concrete = constants.%complete_type.cf1]
109109
// CHECK:STDOUT: complete_type_witness = %complete_type
110110
// CHECK:STDOUT:
111111
// CHECK:STDOUT: !members:
112112
// CHECK:STDOUT: .Self = constants.%Base
113113
// CHECK:STDOUT: .F = %Base.F.decl
114114
// CHECK:STDOUT: .Unused = %Base.Unused.decl
115115
// CHECK:STDOUT: .x = %.loc8
116-
// CHECK:STDOUT: .unused = %.loc9
116+
// CHECK:STDOUT: .unused_y = %.loc9
117117
// CHECK:STDOUT: }
118118
// CHECK:STDOUT:
119119
// CHECK:STDOUT: class @Child {
@@ -143,17 +143,17 @@ fn Run() {
143143
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
144144
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
145145
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
146-
// CHECK:STDOUT: %struct_type.x.unused.7d5: type = struct_type {.x: %i32, .unused: %i32} [concrete]
147-
// CHECK:STDOUT: %complete_type.90f: <witness> = complete_type_witness %struct_type.x.unused.7d5 [concrete]
146+
// CHECK:STDOUT: %struct_type.x.unused_y.9fc: type = struct_type {.x: %i32, .unused_y: %i32} [concrete]
147+
// CHECK:STDOUT: %complete_type.2da: <witness> = complete_type_witness %struct_type.x.unused_y.9fc [concrete]
148148
// CHECK:STDOUT: %struct_type.base.b1e: type = struct_type {.base: %Base} [concrete]
149149
// CHECK:STDOUT: %complete_type.15c: <witness> = complete_type_witness %struct_type.base.b1e [concrete]
150150
// CHECK:STDOUT: %pattern_type.1bd: type = pattern_type %Child [concrete]
151151
// CHECK:STDOUT: %int_0.5c6: Core.IntLiteral = int_value 0 [concrete]
152152
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
153-
// CHECK:STDOUT: %struct_type.x.unused.c45: type = struct_type {.x: Core.IntLiteral, .unused: Core.IntLiteral} [concrete]
154-
// CHECK:STDOUT: %struct.9cc: %struct_type.x.unused.c45 = struct_value (%int_0.5c6, %int_1.5b8) [concrete]
155-
// CHECK:STDOUT: %struct_type.base.6c7: type = struct_type {.base: %struct_type.x.unused.c45} [concrete]
156-
// CHECK:STDOUT: %struct.133: %struct_type.base.6c7 = struct_value (%struct.9cc) [concrete]
153+
// CHECK:STDOUT: %struct_type.x.unused_y.76a: type = struct_type {.x: Core.IntLiteral, .unused_y: Core.IntLiteral} [concrete]
154+
// CHECK:STDOUT: %struct.0bf: %struct_type.x.unused_y.76a = struct_value (%int_0.5c6, %int_1.5b8) [concrete]
155+
// CHECK:STDOUT: %struct_type.base.503: type = struct_type {.base: %struct_type.x.unused_y.76a} [concrete]
156+
// CHECK:STDOUT: %struct.cb5: %struct_type.base.503 = struct_value (%struct.0bf) [concrete]
157157
// CHECK:STDOUT: %ImplicitAs.type.cc7: type = generic_interface_type @ImplicitAs [concrete]
158158
// CHECK:STDOUT: %ImplicitAs.generic: %ImplicitAs.type.cc7 = struct_value () [concrete]
159159
// CHECK:STDOUT: %ImplicitAs.type.bd9: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete]
@@ -199,12 +199,12 @@ fn Run() {
199199
// CHECK:STDOUT: import Core//prelude
200200
// CHECK:STDOUT: import Core//prelude/...
201201
// CHECK:STDOUT: }
202-
// CHECK:STDOUT: %Main.import_ref.239: <witness> = import_ref Main//a, loc10_1, loaded [concrete = constants.%complete_type.90f]
202+
// CHECK:STDOUT: %Main.import_ref.8f2: <witness> = import_ref Main//a, loc10_1, loaded [concrete = constants.%complete_type.2da]
203203
// CHECK:STDOUT: %Main.import_ref.1f3 = import_ref Main//a, inst{{[0-9A-F]+}} [no loc], unloaded
204204
// CHECK:STDOUT: %Main.import_ref.e8f: %Base.F.type = import_ref Main//a, loc5_21, loaded [concrete = constants.%Base.F]
205205
// CHECK:STDOUT: %Main.import_ref.8bf = import_ref Main//a, loc6_26, unloaded
206206
// CHECK:STDOUT: %Main.import_ref.e67: %Base.elem = import_ref Main//a, loc8_8, loaded [concrete = %.720]
207-
// CHECK:STDOUT: %Main.import_ref.2e4 = import_ref Main//a, loc9_13, unloaded
207+
// CHECK:STDOUT: %Main.import_ref.edd = import_ref Main//a, loc9_15, unloaded
208208
// CHECK:STDOUT: %Main.import_ref.c5f: <witness> = import_ref Main//a, loc14_1, loaded [concrete = constants.%complete_type.15c]
209209
// CHECK:STDOUT: %Main.import_ref.9a9 = import_ref Main//a, inst{{[0-9A-F]+}} [no loc], unloaded
210210
// CHECK:STDOUT: %Main.import_ref.7e5 = import_ref Main//a, loc13_20, unloaded
@@ -240,14 +240,14 @@ fn Run() {
240240
// CHECK:STDOUT: }
241241
// CHECK:STDOUT:
242242
// CHECK:STDOUT: class @Base [from "a.carbon"] {
243-
// CHECK:STDOUT: complete_type_witness = imports.%Main.import_ref.239
243+
// CHECK:STDOUT: complete_type_witness = imports.%Main.import_ref.8f2
244244
// CHECK:STDOUT:
245245
// CHECK:STDOUT: !members:
246246
// CHECK:STDOUT: .Self = imports.%Main.import_ref.1f3
247247
// CHECK:STDOUT: .F = imports.%Main.import_ref.e8f
248248
// CHECK:STDOUT: .Unused = imports.%Main.import_ref.8bf
249249
// CHECK:STDOUT: .x = imports.%Main.import_ref.e67
250-
// CHECK:STDOUT: .unused = imports.%Main.import_ref.2e4
250+
// CHECK:STDOUT: .unused_y = imports.%Main.import_ref.edd
251251
// CHECK:STDOUT: }
252252
// CHECK:STDOUT:
253253
// CHECK:STDOUT: fn @Run() {
@@ -259,29 +259,29 @@ fn Run() {
259259
// CHECK:STDOUT: %a.var: ref %Child = var %a.var_patt
260260
// CHECK:STDOUT: %int_0: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
261261
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
262-
// CHECK:STDOUT: %.loc7_47.1: %struct_type.x.unused.c45 = struct_literal (%int_0, %int_1) [concrete = constants.%struct.9cc]
263-
// CHECK:STDOUT: %.loc7_48.1: %struct_type.base.6c7 = struct_literal (%.loc7_47.1) [concrete = constants.%struct.133]
264-
// CHECK:STDOUT: %impl.elem0.loc7_47.1: %.1a5 = impl_witness_access constants.%ImplicitAs.impl_witness.09b, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.13e]
265-
// CHECK:STDOUT: %bound_method.loc7_47.1: <bound method> = bound_method %int_0, %impl.elem0.loc7_47.1 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.7ff]
266-
// CHECK:STDOUT: %specific_fn.loc7_47.1: <specific function> = specific_function %impl.elem0.loc7_47.1, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
267-
// CHECK:STDOUT: %bound_method.loc7_47.2: <bound method> = bound_method %int_0, %specific_fn.loc7_47.1 [concrete = constants.%bound_method.29e]
268-
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_47.1: init %i32 = call %bound_method.loc7_47.2(%int_0) [concrete = constants.%int_0.263]
269-
// CHECK:STDOUT: %.loc7_47.2: init %i32 = converted %int_0, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_47.1 [concrete = constants.%int_0.263]
270-
// CHECK:STDOUT: %.loc7_48.2: ref %Base = class_element_access %a.var, element0
271-
// CHECK:STDOUT: %.loc7_47.3: ref %i32 = class_element_access %.loc7_48.2, element0
272-
// CHECK:STDOUT: %.loc7_47.4: init %i32 = initialize_from %.loc7_47.2 to %.loc7_47.3 [concrete = constants.%int_0.263]
273-
// CHECK:STDOUT: %impl.elem0.loc7_47.2: %.1a5 = impl_witness_access constants.%ImplicitAs.impl_witness.09b, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.13e]
274-
// CHECK:STDOUT: %bound_method.loc7_47.3: <bound method> = bound_method %int_1, %impl.elem0.loc7_47.2 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.b66]
275-
// CHECK:STDOUT: %specific_fn.loc7_47.2: <specific function> = specific_function %impl.elem0.loc7_47.2, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
276-
// CHECK:STDOUT: %bound_method.loc7_47.4: <bound method> = bound_method %int_1, %specific_fn.loc7_47.2 [concrete = constants.%bound_method.c7c]
277-
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_47.2: init %i32 = call %bound_method.loc7_47.4(%int_1) [concrete = constants.%int_1.47b]
278-
// CHECK:STDOUT: %.loc7_47.5: init %i32 = converted %int_1, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_47.2 [concrete = constants.%int_1.47b]
279-
// CHECK:STDOUT: %.loc7_47.6: ref %i32 = class_element_access %.loc7_48.2, element1
280-
// CHECK:STDOUT: %.loc7_47.7: init %i32 = initialize_from %.loc7_47.5 to %.loc7_47.6 [concrete = constants.%int_1.47b]
281-
// CHECK:STDOUT: %.loc7_47.8: init %Base = class_init (%.loc7_47.4, %.loc7_47.7), %.loc7_48.2 [concrete = constants.%Base.val]
282-
// CHECK:STDOUT: %.loc7_48.3: init %Base = converted %.loc7_47.1, %.loc7_47.8 [concrete = constants.%Base.val]
283-
// CHECK:STDOUT: %.loc7_48.4: init %Child = class_init (%.loc7_48.3), %a.var [concrete = constants.%Child.val]
284-
// CHECK:STDOUT: %.loc7_3: init %Child = converted %.loc7_48.1, %.loc7_48.4 [concrete = constants.%Child.val]
262+
// CHECK:STDOUT: %.loc7_49.1: %struct_type.x.unused_y.76a = struct_literal (%int_0, %int_1) [concrete = constants.%struct.0bf]
263+
// CHECK:STDOUT: %.loc7_50.1: %struct_type.base.503 = struct_literal (%.loc7_49.1) [concrete = constants.%struct.cb5]
264+
// CHECK:STDOUT: %impl.elem0.loc7_49.1: %.1a5 = impl_witness_access constants.%ImplicitAs.impl_witness.09b, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.13e]
265+
// CHECK:STDOUT: %bound_method.loc7_49.1: <bound method> = bound_method %int_0, %impl.elem0.loc7_49.1 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.7ff]
266+
// CHECK:STDOUT: %specific_fn.loc7_49.1: <specific function> = specific_function %impl.elem0.loc7_49.1, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
267+
// CHECK:STDOUT: %bound_method.loc7_49.2: <bound method> = bound_method %int_0, %specific_fn.loc7_49.1 [concrete = constants.%bound_method.29e]
268+
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_49.1: init %i32 = call %bound_method.loc7_49.2(%int_0) [concrete = constants.%int_0.263]
269+
// CHECK:STDOUT: %.loc7_49.2: init %i32 = converted %int_0, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_49.1 [concrete = constants.%int_0.263]
270+
// CHECK:STDOUT: %.loc7_50.2: ref %Base = class_element_access %a.var, element0
271+
// CHECK:STDOUT: %.loc7_49.3: ref %i32 = class_element_access %.loc7_50.2, element0
272+
// CHECK:STDOUT: %.loc7_49.4: init %i32 = initialize_from %.loc7_49.2 to %.loc7_49.3 [concrete = constants.%int_0.263]
273+
// CHECK:STDOUT: %impl.elem0.loc7_49.2: %.1a5 = impl_witness_access constants.%ImplicitAs.impl_witness.09b, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.13e]
274+
// CHECK:STDOUT: %bound_method.loc7_49.3: <bound method> = bound_method %int_1, %impl.elem0.loc7_49.2 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.b66]
275+
// CHECK:STDOUT: %specific_fn.loc7_49.2: <specific function> = specific_function %impl.elem0.loc7_49.2, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
276+
// CHECK:STDOUT: %bound_method.loc7_49.4: <bound method> = bound_method %int_1, %specific_fn.loc7_49.2 [concrete = constants.%bound_method.c7c]
277+
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_49.2: init %i32 = call %bound_method.loc7_49.4(%int_1) [concrete = constants.%int_1.47b]
278+
// CHECK:STDOUT: %.loc7_49.5: init %i32 = converted %int_1, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc7_49.2 [concrete = constants.%int_1.47b]
279+
// CHECK:STDOUT: %.loc7_49.6: ref %i32 = class_element_access %.loc7_50.2, element1
280+
// CHECK:STDOUT: %.loc7_49.7: init %i32 = initialize_from %.loc7_49.5 to %.loc7_49.6 [concrete = constants.%int_1.47b]
281+
// CHECK:STDOUT: %.loc7_49.8: init %Base = class_init (%.loc7_49.4, %.loc7_49.7), %.loc7_50.2 [concrete = constants.%Base.val]
282+
// CHECK:STDOUT: %.loc7_50.3: init %Base = converted %.loc7_49.1, %.loc7_49.8 [concrete = constants.%Base.val]
283+
// CHECK:STDOUT: %.loc7_50.4: init %Child = class_init (%.loc7_50.3), %a.var [concrete = constants.%Child.val]
284+
// CHECK:STDOUT: %.loc7_3: init %Child = converted %.loc7_50.1, %.loc7_50.4 [concrete = constants.%Child.val]
285285
// CHECK:STDOUT: assign %a.var, %.loc7_3
286286
// CHECK:STDOUT: %Child.ref: type = name_ref Child, imports.%Main.Child [concrete = constants.%Child]
287287
// CHECK:STDOUT: %a: ref %Child = ref_binding a, %a.var

toolchain/lex/token_kind.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ CARBON_KEYWORD_TOKEN(Type, "type")
218218
// Underscore is tokenized as a keyword because it's part of identifiers.
219219
CARBON_KEYWORD_TOKEN(Underscore, "_")
220220
CARBON_KEYWORD_TOKEN(Unsafe, "unsafe")
221+
CARBON_KEYWORD_TOKEN(Unused, "unused")
221222
CARBON_KEYWORD_TOKEN(Virtual, "virtual")
222223
CARBON_TOKEN_WITH_VIRTUAL_NODE(
223224
CARBON_KEYWORD_TOKEN(Where, "where"))

toolchain/parse/handle_pattern.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ auto HandlePattern(Context& context) -> void {
1818
context.PushStateForPattern(StateKind::VariablePattern,
1919
state.in_var_pattern);
2020
break;
21+
case Lex::TokenKind::Unused:
22+
context.PushStateForPattern(StateKind::UnusedPattern,
23+
state.in_var_pattern);
24+
break;
2125
default:
2226
context.PushStateForPattern(StateKind::BindingPattern,
2327
state.in_var_pattern);

toolchain/parse/handle_unused.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include "toolchain/parse/context.h"
6+
#include "toolchain/parse/handle.h"
7+
8+
namespace Carbon::Parse {
9+
10+
auto HandleUnusedPattern(Context& context) -> void {
11+
auto state = context.PopState();
12+
context.PushState(StateKind::FinishUnusedPattern);
13+
context.ConsumeChecked(Lex::TokenKind::Unused);
14+
15+
context.PushStateForPattern(StateKind::Pattern, state.in_var_pattern);
16+
}
17+
18+
auto HandleFinishUnusedPattern(Context& context) -> void {
19+
auto state = context.PopState();
20+
context.AddNode(NodeKind::UnusedPattern, state.token, state.has_error);
21+
22+
// Propagate errors to the parent state so that they can take different
23+
// actions on invalid patterns.
24+
if (state.has_error) {
25+
context.ReturnErrorOnState();
26+
}
27+
}
28+
29+
} // namespace Carbon::Parse

toolchain/parse/node_ids.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ using AnyPackagingDeclId =
171171
NodeIdOneOf<ImportDeclId, LibraryDeclId, PackageDeclId>;
172172
using AnyPointerDeferenceExprId =
173173
NodeIdOneOf<PrefixOperatorStarId, PointerMemberAccessExprId>;
174-
using AnyRuntimeBindingPatternName =
174+
using AnyRuntimeBindingPatternNameId =
175175
NodeIdOneOf<IdentifierNameNotBeforeParamsId, SelfValueNameId,
176176
UnderscoreNameId>;
177177

toolchain/parse/node_kind.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ CARBON_PARSE_NODE_KIND(ArrayExprComma)
170170
CARBON_PARSE_NODE_KIND(ArrayExpr)
171171

172172
CARBON_PARSE_NODE_KIND(RefBindingName)
173+
CARBON_PARSE_NODE_KIND(UnusedPattern)
173174
CARBON_PARSE_NODE_KIND(LetBindingPattern)
174175
CARBON_PARSE_NODE_KIND(AssociatedConstantNameAndType)
175176
CARBON_PARSE_NODE_KIND(VarBindingPattern)

toolchain/parse/state.def

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,10 @@ CARBON_PARSE_STATE(ParenExprFinish)
10351035
// ...
10361036
// ^
10371037
// 1. BindingPattern
1038+
//
1039+
// ...
1040+
// ^
1041+
// 1. UnusedPattern
10381042
CARBON_PARSE_STATE(Pattern)
10391043

10401044
// Handles the initial part of a binding pattern, enqueuing type expression
@@ -1085,6 +1089,21 @@ CARBON_PARSE_STATE(VariablePattern)
10851089
// (state done)
10861090
CARBON_PARSE_STATE(FinishVariablePattern)
10871091

1092+
// Handles `unused` in a pattern context.
1093+
//
1094+
// unused ...
1095+
// ^~~~~~
1096+
// 1. Pattern
1097+
// 2. FinishUnusedPattern
1098+
CARBON_PARSE_STATE(UnusedPattern)
1099+
1100+
// Finishes `unused` in a pattern context.
1101+
//
1102+
// unused ...
1103+
// ^
1104+
// (state done)
1105+
CARBON_PARSE_STATE(FinishUnusedPattern)
1106+
10881107
// Handles a single statement. While typically within a statement block, this
10891108
// can also be used for error recovery where we expect a statement block and
10901109
// are missing braces.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
//
5+
// AUTOUPDATE
6+
// TIP: To test this file alone, run:
7+
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/var/fail_unused.carbon
8+
// TIP: To dump output, run:
9+
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/var/fail_unused.carbon
10+
11+
var unused x: i32;
12+
// CHECK:STDERR: fail_unused.carbon:[[@LINE+4]]:5: error: found `ref` inside `var` pattern [RefInsideVar]
13+
// CHECK:STDERR: var ref unused y: i32;
14+
// CHECK:STDERR: ^~~
15+
// CHECK:STDERR:
16+
var ref unused y: i32;
17+
var unused _: i32;
18+
19+
// CHECK:STDOUT: - filename: fail_unused.carbon
20+
// CHECK:STDOUT: parse_tree: [
21+
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
22+
// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'},
23+
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'x'},
24+
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
25+
// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
26+
// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 4},
27+
// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 5},
28+
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 7},
29+
// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'},
30+
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeParams', text: 'unused', has_error: yes},
31+
// CHECK:STDOUT: {kind: 'InvalidParse', text: 'unused', has_error: yes},
32+
// CHECK:STDOUT: {kind: 'VarBindingPattern', text: 'ref', has_error: yes, subtree_size: 3},
33+
// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', has_error: yes, subtree_size: 4},
34+
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 6},
35+
// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'},
36+
// CHECK:STDOUT: {kind: 'UnderscoreName', text: '_'},
37+
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
38+
// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
39+
// CHECK:STDOUT: {kind: 'UnusedPattern', text: 'unused', subtree_size: 4},
40+
// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 5},
41+
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 7},
42+
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
43+
// CHECK:STDOUT: ]

0 commit comments

Comments
 (0)