authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-18 13:53:47+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-18 13:53:47+02:00
log53241f288e40a9e97a5425cb0e1ac7dbbc9de852
treed63dda15c2615440408100e213e8c97dfd7c4d52
parent56e9575e827208b3df5c90472826f52bfc8342c0
parent6b65590715d0871c11635fc49cb1fc471a60ea59
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10913 from Vexu/err

further parser error improvements

10 files changed, 353 insertions(+), 254 deletions(-)

doc/langref.html.in+1-1
...@@ -10405,7 +10405,7 @@ pub fn main() !void {...@@ -10405,7 +10405,7 @@ pub fn main() !void {
10405 <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.10405 <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.
10406 This is why it is an error to pass a string literal to a mutable slice, like this:10406 This is why it is an error to pass a string literal to a mutable slice, like this:
10407 </p>10407 </p>
10408 {#code_begin|test_err|expected type '[]u8'#}10408 {#code_begin|test_err|cannot cast pointer to array literal to slice type '[]u8'#}
10409fn foo(s: []u8) void {10409fn foo(s: []u8) void {
10410 _ = s;10410 _ = s;
10411}10411}
lib/std/zig/Ast.zig+46-48
...@@ -66,20 +66,11 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void...@@ -66,20 +66,11 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void
6666
67/// Returns an extra offset for column and byte offset of errors that67/// Returns an extra offset for column and byte offset of errors that
68/// should point after the token in the error message.68/// should point after the token in the error message.
69pub fn errorOffset(tree: Ast, error_tag: Error.Tag, token: TokenIndex) u32 {69pub fn errorOffset(tree: Ast, parse_error: Error) u32 {
70 return switch (error_tag) {70 return if (parse_error.token_is_prev)
71 .expected_semi_after_decl,71 @intCast(u32, tree.tokenSlice(parse_error.token).len)
72 .expected_semi_after_stmt,72 else
73 .expected_comma_after_field,73 0;
74 .expected_comma_after_arg,
75 .expected_comma_after_param,
76 .expected_comma_after_initializer,
77 .expected_comma_after_switch_prong,
78 .expected_semi_or_else,
79 .expected_semi_or_lbrace,
80 => @intCast(u32, tree.tokenSlice(token).len),
81 else => 0,
82 };
83}74}
8475
85pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location {76pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location {
...@@ -162,22 +153,22 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -162,22 +153,22 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
162 },153 },
163 .expected_block => {154 .expected_block => {
164 return stream.print("expected block or field, found '{s}'", .{155 return stream.print("expected block or field, found '{s}'", .{
165 token_tags[parse_error.token].symbol(),156 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
166 });157 });
167 },158 },
168 .expected_block_or_assignment => {159 .expected_block_or_assignment => {
169 return stream.print("expected block or assignment, found '{s}'", .{160 return stream.print("expected block or assignment, found '{s}'", .{
170 token_tags[parse_error.token].symbol(),161 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
171 });162 });
172 },163 },
173 .expected_block_or_expr => {164 .expected_block_or_expr => {
174 return stream.print("expected block or expression, found '{s}'", .{165 return stream.print("expected block or expression, found '{s}'", .{
175 token_tags[parse_error.token].symbol(),166 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
176 });167 });
177 },168 },
178 .expected_block_or_field => {169 .expected_block_or_field => {
179 return stream.print("expected block or field, found '{s}'", .{170 return stream.print("expected block or field, found '{s}'", .{
180 token_tags[parse_error.token].symbol(),171 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
181 });172 });
182 },173 },
183 .expected_container_members => {174 .expected_container_members => {
...@@ -187,42 +178,42 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -187,42 +178,42 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
187 },178 },
188 .expected_expr => {179 .expected_expr => {
189 return stream.print("expected expression, found '{s}'", .{180 return stream.print("expected expression, found '{s}'", .{
190 token_tags[parse_error.token].symbol(),181 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
191 });182 });
192 },183 },
193 .expected_expr_or_assignment => {184 .expected_expr_or_assignment => {
194 return stream.print("expected expression or assignment, found '{s}'", .{185 return stream.print("expected expression or assignment, found '{s}'", .{
195 token_tags[parse_error.token].symbol(),186 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
196 });187 });
197 },188 },
198 .expected_fn => {189 .expected_fn => {
199 return stream.print("expected function, found '{s}'", .{190 return stream.print("expected function, found '{s}'", .{
200 token_tags[parse_error.token].symbol(),191 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
201 });192 });
202 },193 },
203 .expected_inlinable => {194 .expected_inlinable => {
204 return stream.print("expected 'while' or 'for', found '{s}'", .{195 return stream.print("expected 'while' or 'for', found '{s}'", .{
205 token_tags[parse_error.token].symbol(),196 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
206 });197 });
207 },198 },
208 .expected_labelable => {199 .expected_labelable => {
209 return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{200 return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{
210 token_tags[parse_error.token].symbol(),201 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
211 });202 });
212 },203 },
213 .expected_param_list => {204 .expected_param_list => {
214 return stream.print("expected parameter list, found '{s}'", .{205 return stream.print("expected parameter list, found '{s}'", .{
215 token_tags[parse_error.token].symbol(),206 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
216 });207 });
217 },208 },
218 .expected_prefix_expr => {209 .expected_prefix_expr => {
219 return stream.print("expected prefix expression, found '{s}'", .{210 return stream.print("expected prefix expression, found '{s}'", .{
220 token_tags[parse_error.token].symbol(),211 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
221 });212 });
222 },213 },
223 .expected_primary_type_expr => {214 .expected_primary_type_expr => {
224 return stream.print("expected primary type expression, found '{s}'", .{215 return stream.print("expected primary type expression, found '{s}'", .{
225 token_tags[parse_error.token].symbol(),216 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
226 });217 });
227 },218 },
228 .expected_pub_item => {219 .expected_pub_item => {
...@@ -230,7 +221,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -230,7 +221,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
230 },221 },
231 .expected_return_type => {222 .expected_return_type => {
232 return stream.print("expected return type expression, found '{s}'", .{223 return stream.print("expected return type expression, found '{s}'", .{
233 token_tags[parse_error.token].symbol(),224 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
234 });225 });
235 },226 },
236 .expected_semi_or_else => {227 .expected_semi_or_else => {
...@@ -244,39 +235,34 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -244,39 +235,34 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
244 token_tags[parse_error.token].symbol(),235 token_tags[parse_error.token].symbol(),
245 });236 });
246 },237 },
247 .expected_string_literal => {
248 return stream.print("expected string literal, found '{s}'", .{
249 token_tags[parse_error.token].symbol(),
250 });
251 },
252 .expected_suffix_op => {238 .expected_suffix_op => {
253 return stream.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{239 return stream.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{
254 token_tags[parse_error.token].symbol(),240 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
255 });241 });
256 },242 },
257 .expected_type_expr => {243 .expected_type_expr => {
258 return stream.print("expected type expression, found '{s}'", .{244 return stream.print("expected type expression, found '{s}'", .{
259 token_tags[parse_error.token].symbol(),245 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
260 });246 });
261 },247 },
262 .expected_var_decl => {248 .expected_var_decl => {
263 return stream.print("expected variable declaration, found '{s}'", .{249 return stream.print("expected variable declaration, found '{s}'", .{
264 token_tags[parse_error.token].symbol(),250 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
265 });251 });
266 },252 },
267 .expected_var_decl_or_fn => {253 .expected_var_decl_or_fn => {
268 return stream.print("expected variable declaration or function, found '{s}'", .{254 return stream.print("expected variable declaration or function, found '{s}'", .{
269 token_tags[parse_error.token].symbol(),255 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
270 });256 });
271 },257 },
272 .expected_loop_payload => {258 .expected_loop_payload => {
273 return stream.print("expected loop payload, found '{s}'", .{259 return stream.print("expected loop payload, found '{s}'", .{
274 token_tags[parse_error.token].symbol(),260 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
275 });261 });
276 },262 },
277 .expected_container => {263 .expected_container => {
278 return stream.print("expected a struct, enum or union, found '{s}'", .{264 return stream.print("expected a struct, enum or union, found '{s}'", .{
279 token_tags[parse_error.token].symbol(),265 token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
280 });266 });
281 },267 },
282 .extern_fn_body => {268 .extern_fn_body => {
...@@ -305,11 +291,6 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -305,11 +291,6 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
305 .invalid_bit_range => {291 .invalid_bit_range => {
306 return stream.writeAll("bit range not allowed on slices and arrays");292 return stream.writeAll("bit range not allowed on slices and arrays");
307 },293 },
308 .invalid_token => {
309 return stream.print("invalid token: '{s}'", .{
310 token_tags[parse_error.token].symbol(),
311 });
312 },
313 .same_line_doc_comment => {294 .same_line_doc_comment => {
314 return stream.writeAll("same line documentation comment");295 return stream.writeAll("same line documentation comment");
315 },296 },
...@@ -319,6 +300,9 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -319,6 +300,9 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
319 .varargs_nonfinal => {300 .varargs_nonfinal => {
320 return stream.writeAll("function prototype has parameter after varargs");301 return stream.writeAll("function prototype has parameter after varargs");
321 },302 },
303 .expected_continue_expr => {
304 return stream.writeAll("expected ':' before while continue expression");
305 },
322306
323 .expected_semi_after_decl => {307 .expected_semi_after_decl => {
324 return stream.writeAll("expected ';' after declaration");308 return stream.writeAll("expected ';' after declaration");
...@@ -341,9 +325,19 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -341,9 +325,19 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
341 .expected_comma_after_switch_prong => {325 .expected_comma_after_switch_prong => {
342 return stream.writeAll("expected ',' after switch prong");326 return stream.writeAll("expected ',' after switch prong");
343 },327 },
328 .expected_initializer => {
329 return stream.writeAll("expected field initializer");
330 },
331
332 .previous_field => {
333 return stream.writeAll("field before declarations here");
334 },
335 .next_field => {
336 return stream.writeAll("field after declarations here");
337 },
344338
345 .expected_token => {339 .expected_token => {
346 const found_tag = token_tags[parse_error.token];340 const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)];
347 const expected_symbol = parse_error.extra.expected_tag.symbol();341 const expected_symbol = parse_error.extra.expected_tag.symbol();
348 switch (found_tag) {342 switch (found_tag) {
349 .invalid => return stream.print("expected '{s}', found invalid bytes", .{343 .invalid => return stream.print("expected '{s}', found invalid bytes", .{
...@@ -2483,6 +2477,9 @@ pub const full = struct {...@@ -2483,6 +2477,9 @@ pub const full = struct {
24832477
2484pub const Error = struct {2478pub const Error = struct {
2485 tag: Tag,2479 tag: Tag,
2480 is_note: bool = false,
2481 /// True if `token` points to the token before the token causing an issue.
2482 token_is_prev: bool = false,
2486 token: TokenIndex,2483 token: TokenIndex,
2487 extra: union {2484 extra: union {
2488 none: void,2485 none: void,
...@@ -2511,7 +2508,6 @@ pub const Error = struct {...@@ -2511,7 +2508,6 @@ pub const Error = struct {
2511 expected_semi_or_else,2508 expected_semi_or_else,
2512 expected_semi_or_lbrace,2509 expected_semi_or_lbrace,
2513 expected_statement,2510 expected_statement,
2514 expected_string_literal,
2515 expected_suffix_op,2511 expected_suffix_op,
2516 expected_type_expr,2512 expected_type_expr,
2517 expected_var_decl,2513 expected_var_decl,
...@@ -2526,12 +2522,10 @@ pub const Error = struct {...@@ -2526,12 +2522,10 @@ pub const Error = struct {
2526 extra_volatile_qualifier,2522 extra_volatile_qualifier,
2527 ptr_mod_on_array_child_type,2523 ptr_mod_on_array_child_type,
2528 invalid_bit_range,2524 invalid_bit_range,
2529 invalid_token,
2530 same_line_doc_comment,2525 same_line_doc_comment,
2531 unattached_doc_comment,2526 unattached_doc_comment,
2532 varargs_nonfinal,2527 varargs_nonfinal,
25332528 expected_continue_expr,
2534 // these have `token` set to token after which a semicolon was expected
2535 expected_semi_after_decl,2529 expected_semi_after_decl,
2536 expected_semi_after_stmt,2530 expected_semi_after_stmt,
2537 expected_comma_after_field,2531 expected_comma_after_field,
...@@ -2539,6 +2533,10 @@ pub const Error = struct {...@@ -2539,6 +2533,10 @@ pub const Error = struct {
2539 expected_comma_after_param,2533 expected_comma_after_param,
2540 expected_comma_after_initializer,2534 expected_comma_after_initializer,
2541 expected_comma_after_switch_prong,2535 expected_comma_after_switch_prong,
2536 expected_initializer,
2537
2538 previous_field,
2539 next_field,
25422540
2543 /// `expected_tag` is populated.2541 /// `expected_tag` is populated.
2544 expected_token,2542 expected_token,
lib/std/zig/parse.zig+106-99
...@@ -91,6 +91,9 @@ const Parser = struct {...@@ -91,6 +91,9 @@ const Parser = struct {
91 extra_data: std.ArrayListUnmanaged(Node.Index),91 extra_data: std.ArrayListUnmanaged(Node.Index),
92 scratch: std.ArrayListUnmanaged(Node.Index),92 scratch: std.ArrayListUnmanaged(Node.Index),
9393
94 /// Used for the error note of decl_between_fields error.
95 last_field: TokenIndex = undefined,
96
94 const SmallSpan = union(enum) {97 const SmallSpan = union(enum) {
95 zero_or_one: Node.Index,98 zero_or_one: Node.Index,
96 multi: Node.SubRange,99 multi: Node.SubRange,
...@@ -147,11 +150,6 @@ const Parser = struct {...@@ -147,11 +150,6 @@ const Parser = struct {
147 return result;150 return result;
148 }151 }
149152
150 fn warn(p: *Parser, tag: Ast.Error.Tag) error{OutOfMemory}!void {
151 @setCold(true);
152 try p.warnMsg(.{ .tag = tag, .token = p.tok_i });
153 }
154
155 fn warnExpected(p: *Parser, expected_token: Token.Tag) error{OutOfMemory}!void {153 fn warnExpected(p: *Parser, expected_token: Token.Tag) error{OutOfMemory}!void {
156 @setCold(true);154 @setCold(true);
157 try p.warnMsg(.{155 try p.warnMsg(.{
...@@ -161,13 +159,53 @@ const Parser = struct {...@@ -161,13 +159,53 @@ const Parser = struct {
161 });159 });
162 }160 }
163161
164 fn warnExpectedAfter(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void {162 fn warn(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void {
165 @setCold(true);163 @setCold(true);
166 try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i - 1 });164 try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i });
167 }165 }
168166
169 fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {167 fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {
170 @setCold(true);168 @setCold(true);
169 switch (msg.tag) {
170 .expected_semi_after_decl,
171 .expected_semi_after_stmt,
172 .expected_comma_after_field,
173 .expected_comma_after_arg,
174 .expected_comma_after_param,
175 .expected_comma_after_initializer,
176 .expected_comma_after_switch_prong,
177 .expected_semi_or_else,
178 .expected_semi_or_lbrace,
179 .expected_token,
180 .expected_block,
181 .expected_block_or_assignment,
182 .expected_block_or_expr,
183 .expected_block_or_field,
184 .expected_container_members,
185 .expected_expr,
186 .expected_expr_or_assignment,
187 .expected_fn,
188 .expected_inlinable,
189 .expected_labelable,
190 .expected_param_list,
191 .expected_prefix_expr,
192 .expected_primary_type_expr,
193 .expected_pub_item,
194 .expected_return_type,
195 .expected_suffix_op,
196 .expected_type_expr,
197 .expected_var_decl,
198 .expected_var_decl_or_fn,
199 .expected_loop_payload,
200 .expected_container,
201 => if (msg.token != 0 and !p.tokensOnSameLine(msg.token - 1, msg.token)) {
202 var copy = msg;
203 copy.token_is_prev = true;
204 copy.token -= 1;
205 return p.errors.append(p.gpa, copy);
206 },
207 else => {},
208 }
171 try p.errors.append(p.gpa, msg);209 try p.errors.append(p.gpa, msg);
172 }210 }
173211
...@@ -235,6 +273,8 @@ const Parser = struct {...@@ -235,6 +273,8 @@ const Parser = struct {
235 .keyword_comptime => switch (p.token_tags[p.tok_i + 1]) {273 .keyword_comptime => switch (p.token_tags[p.tok_i + 1]) {
236 .identifier => {274 .identifier => {
237 p.tok_i += 1;275 p.tok_i += 1;
276 const identifier = p.tok_i;
277 defer p.last_field = identifier;
238 const container_field = try p.expectContainerFieldRecoverable();278 const container_field = try p.expectContainerFieldRecoverable();
239 if (container_field != 0) {279 if (container_field != 0) {
240 switch (field_state) {280 switch (field_state) {
...@@ -245,6 +285,16 @@ const Parser = struct {...@@ -245,6 +285,16 @@ const Parser = struct {
245 .tag = .decl_between_fields,285 .tag = .decl_between_fields,
246 .token = p.nodes.items(.main_token)[node],286 .token = p.nodes.items(.main_token)[node],
247 });287 });
288 try p.warnMsg(.{
289 .tag = .previous_field,
290 .is_note = true,
291 .token = p.last_field,
292 });
293 try p.warnMsg(.{
294 .tag = .next_field,
295 .is_note = true,
296 .token = identifier,
297 });
248 // Continue parsing; error will be reported later.298 // Continue parsing; error will be reported later.
249 field_state = .err;299 field_state = .err;
250 },300 },
...@@ -264,7 +314,7 @@ const Parser = struct {...@@ -264,7 +314,7 @@ const Parser = struct {
264 }314 }
265 // There is not allowed to be a decl after a field with no comma.315 // There is not allowed to be a decl after a field with no comma.
266 // Report error but recover parser.316 // Report error but recover parser.
267 try p.warnExpectedAfter(.expected_comma_after_field);317 try p.warn(.expected_comma_after_field);
268 p.findNextContainerMember();318 p.findNextContainerMember();
269 }319 }
270 },320 },
...@@ -338,6 +388,8 @@ const Parser = struct {...@@ -338,6 +388,8 @@ const Parser = struct {
338 trailing = p.token_tags[p.tok_i - 1] == .semicolon;388 trailing = p.token_tags[p.tok_i - 1] == .semicolon;
339 },389 },
340 .identifier => {390 .identifier => {
391 const identifier = p.tok_i;
392 defer p.last_field = identifier;
341 const container_field = try p.expectContainerFieldRecoverable();393 const container_field = try p.expectContainerFieldRecoverable();
342 if (container_field != 0) {394 if (container_field != 0) {
343 switch (field_state) {395 switch (field_state) {
...@@ -348,6 +400,14 @@ const Parser = struct {...@@ -348,6 +400,14 @@ const Parser = struct {
348 .tag = .decl_between_fields,400 .tag = .decl_between_fields,
349 .token = p.nodes.items(.main_token)[node],401 .token = p.nodes.items(.main_token)[node],
350 });402 });
403 try p.warnMsg(.{
404 .tag = .previous_field,
405 .token = p.last_field,
406 });
407 try p.warnMsg(.{
408 .tag = .next_field,
409 .token = identifier,
410 });
351 // Continue parsing; error will be reported later.411 // Continue parsing; error will be reported later.
352 field_state = .err;412 field_state = .err;
353 },413 },
...@@ -367,7 +427,7 @@ const Parser = struct {...@@ -367,7 +427,7 @@ const Parser = struct {
367 }427 }
368 // There is not allowed to be a decl after a field with no comma.428 // There is not allowed to be a decl after a field with no comma.
369 // Report error but recover parser.429 // Report error but recover parser.
370 try p.warnExpectedAfter(.expected_comma_after_field);430 try p.warn(.expected_comma_after_field);
371 p.findNextContainerMember();431 p.findNextContainerMember();
372 }432 }
373 },433 },
...@@ -585,7 +645,7 @@ const Parser = struct {...@@ -585,7 +645,7 @@ const Parser = struct {
585 // Since parseBlock only return error.ParseError on645 // Since parseBlock only return error.ParseError on
586 // a missing '}' we can assume this function was646 // a missing '}' we can assume this function was
587 // supposed to end here.647 // supposed to end here.
588 try p.warnExpectedAfter(.expected_semi_or_lbrace);648 try p.warn(.expected_semi_or_lbrace);
589 return null_node;649 return null_node;
590 },650 },
591 }651 }
...@@ -996,7 +1056,7 @@ const Parser = struct {...@@ -996,7 +1056,7 @@ const Parser = struct {
996 };1056 };
997 _ = p.eatToken(.keyword_else) orelse {1057 _ = p.eatToken(.keyword_else) orelse {
998 if (else_required) {1058 if (else_required) {
999 try p.warnExpectedAfter(.expected_semi_or_else);1059 try p.warn(.expected_semi_or_else);
1000 }1060 }
1001 return p.addNode(.{1061 return p.addNode(.{
1002 .tag = .if_simple,1062 .tag = .if_simple,
...@@ -1091,7 +1151,7 @@ const Parser = struct {...@@ -1091,7 +1151,7 @@ const Parser = struct {
1091 };1151 };
1092 _ = p.eatToken(.keyword_else) orelse {1152 _ = p.eatToken(.keyword_else) orelse {
1093 if (else_required) {1153 if (else_required) {
1094 try p.warnExpectedAfter(.expected_semi_or_else);1154 try p.warn(.expected_semi_or_else);
1095 }1155 }
1096 return p.addNode(.{1156 return p.addNode(.{
1097 .tag = .for_simple,1157 .tag = .for_simple,
...@@ -1166,7 +1226,7 @@ const Parser = struct {...@@ -1166,7 +1226,7 @@ const Parser = struct {
1166 };1226 };
1167 _ = p.eatToken(.keyword_else) orelse {1227 _ = p.eatToken(.keyword_else) orelse {
1168 if (else_required) {1228 if (else_required) {
1169 try p.warnExpectedAfter(.expected_semi_or_else);1229 try p.warn(.expected_semi_or_else);
1170 }1230 }
1171 if (cont_expr == 0) {1231 if (cont_expr == 0) {
1172 return p.addNode(.{1232 return p.addNode(.{
...@@ -1402,7 +1462,8 @@ const Parser = struct {...@@ -1402,7 +1462,8 @@ const Parser = struct {
1402 }1462 }
1403 const rhs = try p.parseExprPrecedence(info.prec + 1);1463 const rhs = try p.parseExprPrecedence(info.prec + 1);
1404 if (rhs == 0) {1464 if (rhs == 0) {
1405 return p.fail(.invalid_token);1465 try p.warn(.expected_expr);
1466 return node;
1406 }1467 }
14071468
1408 node = try p.addNode(.{1469 node = try p.addNode(.{
...@@ -1881,7 +1942,7 @@ const Parser = struct {...@@ -1881,7 +1942,7 @@ const Parser = struct {
18811942
1882 /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?1943 /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
1883 fn parseIfExpr(p: *Parser) !Node.Index {1944 fn parseIfExpr(p: *Parser) !Node.Index {
1884 return p.parseIf(parseExpr);1945 return p.parseIf(expectExpr);
1885 }1946 }
18861947
1887 /// Block <- LBRACE Statement* RBRACE1948 /// Block <- LBRACE Statement* RBRACE
...@@ -2050,7 +2111,7 @@ const Parser = struct {...@@ -2050,7 +2111,7 @@ const Parser = struct {
2050 },2111 },
2051 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2112 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2052 // Likely just a missing comma; give error but continue parsing.2113 // Likely just a missing comma; give error but continue parsing.
2053 else => try p.warnExpectedAfter(.expected_comma_after_initializer),2114 else => try p.warn(.expected_comma_after_initializer),
2054 }2115 }
2055 if (p.eatToken(.r_brace)) |_| break;2116 if (p.eatToken(.r_brace)) |_| break;
2056 const next = try p.expectFieldInit();2117 const next = try p.expectFieldInit();
...@@ -2091,7 +2152,7 @@ const Parser = struct {...@@ -2091,7 +2152,7 @@ const Parser = struct {
2091 },2152 },
2092 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2153 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2093 // Likely just a missing comma; give error but continue parsing.2154 // Likely just a missing comma; give error but continue parsing.
2094 else => try p.warnExpectedAfter(.expected_comma_after_initializer),2155 else => try p.warn(.expected_comma_after_initializer),
2095 }2156 }
2096 }2157 }
2097 const comma = (p.token_tags[p.tok_i - 2] == .comma);2158 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2170,7 +2231,7 @@ const Parser = struct {...@@ -2170,7 +2231,7 @@ const Parser = struct {
2170 },2231 },
2171 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),2232 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2172 // Likely just a missing comma; give error but continue parsing.2233 // Likely just a missing comma; give error but continue parsing.
2173 else => try p.warnExpectedAfter(.expected_comma_after_arg),2234 else => try p.warn(.expected_comma_after_arg),
2174 }2235 }
2175 }2236 }
2176 const comma = (p.token_tags[p.tok_i - 2] == .comma);2237 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2226,7 +2287,7 @@ const Parser = struct {...@@ -2226,7 +2287,7 @@ const Parser = struct {
2226 },2287 },
2227 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),2288 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2228 // Likely just a missing comma; give error but continue parsing.2289 // Likely just a missing comma; give error but continue parsing.
2229 else => try p.warnExpectedAfter(.expected_comma_after_arg),2290 else => try p.warn(.expected_comma_after_arg),
2230 }2291 }
2231 }2292 }
2232 const comma = (p.token_tags[p.tok_i - 2] == .comma);2293 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2349,7 +2410,7 @@ const Parser = struct {...@@ -2349,7 +2410,7 @@ const Parser = struct {
23492410
2350 .builtin => return p.parseBuiltinCall(),2411 .builtin => return p.parseBuiltinCall(),
2351 .keyword_fn => return p.parseFnProto(),2412 .keyword_fn => return p.parseFnProto(),
2352 .keyword_if => return p.parseIf(parseTypeExpr),2413 .keyword_if => return p.parseIf(expectTypeExpr),
2353 .keyword_switch => return p.expectSwitchExpr(),2414 .keyword_switch => return p.expectSwitchExpr(),
23542415
2355 .keyword_extern,2416 .keyword_extern,
...@@ -2467,7 +2528,7 @@ const Parser = struct {...@@ -2467,7 +2528,7 @@ const Parser = struct {
2467 },2528 },
2468 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2529 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2469 // Likely just a missing comma; give error but continue parsing.2530 // Likely just a missing comma; give error but continue parsing.
2470 else => try p.warnExpectedAfter(.expected_comma_after_initializer),2531 else => try p.warn(.expected_comma_after_initializer),
2471 }2532 }
2472 if (p.eatToken(.r_brace)) |_| break;2533 if (p.eatToken(.r_brace)) |_| break;
2473 const next = try p.expectFieldInit();2534 const next = try p.expectFieldInit();
...@@ -2519,7 +2580,7 @@ const Parser = struct {...@@ -2519,7 +2580,7 @@ const Parser = struct {
2519 },2580 },
2520 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2581 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2521 // Likely just a missing comma; give error but continue parsing.2582 // Likely just a missing comma; give error but continue parsing.
2522 else => try p.warnExpectedAfter(.expected_comma_after_initializer),2583 else => try p.warn(.expected_comma_after_initializer),
2523 }2584 }
2524 }2585 }
2525 const comma = (p.token_tags[p.tok_i - 2] == .comma);2586 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2580,7 +2641,7 @@ const Parser = struct {...@@ -2580,7 +2641,7 @@ const Parser = struct {
2580 },2641 },
2581 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2642 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2582 // Likely just a missing comma; give error but continue parsing.2643 // Likely just a missing comma; give error but continue parsing.
2583 else => try p.warnExpectedAfter(.expected_comma_after_field),2644 else => try p.warn(.expected_comma_after_field),
2584 }2645 }
2585 }2646 }
2586 return p.addNode(.{2647 return p.addNode(.{
...@@ -2879,7 +2940,7 @@ const Parser = struct {...@@ -2879,7 +2940,7 @@ const Parser = struct {
2879 p.tok_i += 2;2940 p.tok_i += 2;
2880 return identifier;2941 return identifier;
2881 }2942 }
2882 return 0;2943 return null_node;
2883 }2944 }
28842945
2885 /// FieldInit <- DOT IDENTIFIER EQUAL Expr2946 /// FieldInit <- DOT IDENTIFIER EQUAL Expr
...@@ -2896,15 +2957,23 @@ const Parser = struct {...@@ -2896,15 +2957,23 @@ const Parser = struct {
2896 }2957 }
28972958
2898 fn expectFieldInit(p: *Parser) !Node.Index {2959 fn expectFieldInit(p: *Parser) !Node.Index {
2899 _ = try p.expectToken(.period);2960 if (p.token_tags[p.tok_i] != .period or
2900 _ = try p.expectToken(.identifier);2961 p.token_tags[p.tok_i + 1] != .identifier or
2901 _ = try p.expectToken(.equal);2962 p.token_tags[p.tok_i + 2] != .equal)
2963 return p.fail(.expected_initializer);
2964
2965 p.tok_i += 3;
2902 return p.expectExpr();2966 return p.expectExpr();
2903 }2967 }
29042968
2905 /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN2969 /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
2906 fn parseWhileContinueExpr(p: *Parser) !Node.Index {2970 fn parseWhileContinueExpr(p: *Parser) !Node.Index {
2907 _ = p.eatToken(.colon) orelse return null_node;2971 _ = p.eatToken(.colon) orelse {
2972 if (p.token_tags[p.tok_i] == .l_paren and
2973 p.tokensOnSameLine(p.tok_i - 1, p.tok_i))
2974 return p.fail(.expected_continue_expr);
2975 return null_node;
2976 };
2908 _ = try p.expectToken(.l_paren);2977 _ = try p.expectToken(.l_paren);
2909 const node = try p.parseAssignExpr();2978 const node = try p.parseAssignExpr();
2910 if (node == 0) return p.fail(.expected_expr_or_assignment);2979 if (node == 0) return p.fail(.expected_expr_or_assignment);
...@@ -3413,7 +3482,7 @@ const Parser = struct {...@@ -3413,7 +3482,7 @@ const Parser = struct {
3413 // All possible delimiters.3482 // All possible delimiters.
3414 .colon, .r_paren, .r_brace, .r_bracket => break,3483 .colon, .r_paren, .r_brace, .r_bracket => break,
3415 // Likely just a missing comma; give error but continue parsing.3484 // Likely just a missing comma; give error but continue parsing.
3416 else => try p.warnExpectedAfter(.expected_comma_after_switch_prong),3485 else => try p.warn(.expected_comma_after_switch_prong),
3417 }3486 }
3418 }3487 }
3419 return p.listToSpan(p.scratch.items[scratch_top..]);3488 return p.listToSpan(p.scratch.items[scratch_top..]);
...@@ -3442,7 +3511,7 @@ const Parser = struct {...@@ -3442,7 +3511,7 @@ const Parser = struct {
3442 },3511 },
3443 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),3512 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
3444 // Likely just a missing comma; give error but continue parsing.3513 // Likely just a missing comma; give error but continue parsing.
3445 else => try p.warnExpectedAfter(.expected_comma_after_param),3514 else => try p.warn(.expected_comma_after_param),
3446 }3515 }
3447 }3516 }
3448 if (varargs == .nonfinal) {3517 if (varargs == .nonfinal) {
...@@ -3486,7 +3555,7 @@ const Parser = struct {...@@ -3486,7 +3555,7 @@ const Parser = struct {
3486 break;3555 break;
3487 },3556 },
3488 // Likely just a missing comma; give error but continue parsing.3557 // Likely just a missing comma; give error but continue parsing.
3489 else => try p.warnExpectedAfter(.expected_comma_after_arg),3558 else => try p.warn(.expected_comma_after_arg),
3490 }3559 }
3491 }3560 }
3492 const comma = (p.token_tags[p.tok_i - 2] == .comma);3561 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -3530,57 +3599,6 @@ const Parser = struct {...@@ -3530,57 +3599,6 @@ const Parser = struct {
3530 }3599 }
3531 }3600 }
35323601
3533 // string literal or multiline string literal
3534 fn parseStringLiteral(p: *Parser) !Node.Index {
3535 switch (p.token_tags[p.tok_i]) {
3536 .string_literal => {
3537 const main_token = p.nextToken();
3538 return p.addNode(.{
3539 .tag = .string_literal,
3540 .main_token = main_token,
3541 .data = .{
3542 .lhs = undefined,
3543 .rhs = undefined,
3544 },
3545 });
3546 },
3547 .multiline_string_literal_line => {
3548 const first_line = p.nextToken();
3549 while (p.token_tags[p.tok_i] == .multiline_string_literal_line) {
3550 p.tok_i += 1;
3551 }
3552 return p.addNode(.{
3553 .tag = .multiline_string_literal,
3554 .main_token = first_line,
3555 .data = .{
3556 .lhs = first_line,
3557 .rhs = p.tok_i - 1,
3558 },
3559 });
3560 },
3561 else => return null_node,
3562 }
3563 }
3564
3565 fn expectStringLiteral(p: *Parser) !Node.Index {
3566 const node = try p.parseStringLiteral();
3567 if (node == 0) {
3568 return p.fail(.expected_string_literal);
3569 }
3570 return node;
3571 }
3572
3573 fn expectIntegerLiteral(p: *Parser) !Node.Index {
3574 return p.addNode(.{
3575 .tag = .integer_literal,
3576 .main_token = try p.expectToken(.integer_literal),
3577 .data = .{
3578 .lhs = undefined,
3579 .rhs = undefined,
3580 },
3581 });
3582 }
3583
3584 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?3602 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?
3585 fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {3603 fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {
3586 const if_token = p.eatToken(.keyword_if) orelse return null_node;3604 const if_token = p.eatToken(.keyword_if) orelse return null_node;
...@@ -3590,7 +3608,7 @@ const Parser = struct {...@@ -3590,7 +3608,7 @@ const Parser = struct {
3590 _ = try p.parsePtrPayload();3608 _ = try p.parsePtrPayload();
35913609
3592 const then_expr = try bodyParseFn(p);3610 const then_expr = try bodyParseFn(p);
3593 if (then_expr == 0) return p.fail(.invalid_token);3611 assert(then_expr != 0);
35943612
3595 _ = p.eatToken(.keyword_else) orelse return p.addNode(.{3613 _ = p.eatToken(.keyword_else) orelse return p.addNode(.{
3596 .tag = .if_simple,3614 .tag = .if_simple,
...@@ -3602,7 +3620,7 @@ const Parser = struct {...@@ -3602,7 +3620,7 @@ const Parser = struct {
3602 });3620 });
3603 _ = try p.parsePayload();3621 _ = try p.parsePayload();
3604 const else_expr = try bodyParseFn(p);3622 const else_expr = try bodyParseFn(p);
3605 if (else_expr == 0) return p.fail(.invalid_token);3623 assert(then_expr != 0);
36063624
3607 return p.addNode(.{3625 return p.addNode(.{
3608 .tag = .@"if",3626 .tag = .@"if",
...@@ -3649,25 +3667,14 @@ const Parser = struct {...@@ -3649,25 +3667,14 @@ const Parser = struct {
3649 }3667 }
36503668
3651 fn expectToken(p: *Parser, tag: Token.Tag) Error!TokenIndex {3669 fn expectToken(p: *Parser, tag: Token.Tag) Error!TokenIndex {
3652 const token = p.nextToken();3670 if (p.token_tags[p.tok_i] != tag) {
3653 if (p.token_tags[token] != tag) {
3654 p.tok_i -= 1; // Go back so that we can recover properly.
3655 return p.failMsg(.{3671 return p.failMsg(.{
3656 .tag = .expected_token,3672 .tag = .expected_token,
3657 .token = token,3673 .token = p.tok_i,
3658 .extra = .{ .expected_tag = tag },3674 .extra = .{ .expected_tag = tag },
3659 });3675 });
3660 }3676 }
3661 return token;3677 return p.nextToken();
3662 }
3663
3664 fn expectTokenRecoverable(p: *Parser, tag: Token.Tag) !?TokenIndex {
3665 if (p.token_tags[p.tok_i] != tag) {
3666 try p.warnExpected(tag);
3667 return null;
3668 } else {
3669 return p.nextToken();
3670 }
3671 }3678 }
36723679
3673 fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void {3680 fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void {
...@@ -3675,7 +3682,7 @@ const Parser = struct {...@@ -3675,7 +3682,7 @@ const Parser = struct {
3675 _ = p.nextToken();3682 _ = p.nextToken();
3676 return;3683 return;
3677 }3684 }
3678 try p.warnExpectedAfter(error_tag);3685 try p.warn(error_tag);
3679 if (!recoverable) return error.ParseError;3686 if (!recoverable) return error.ParseError;
3680 }3687 }
36813688
lib/std/zig/parser_test.zig+25-2
...@@ -226,6 +226,8 @@ test "zig fmt: decl between fields" {...@@ -226,6 +226,8 @@ test "zig fmt: decl between fields" {
226 \\};226 \\};
227 , &[_]Error{227 , &[_]Error{
228 .decl_between_fields,228 .decl_between_fields,
229 .previous_field,
230 .next_field,
229 });231 });
230}232}
231233
...@@ -5018,6 +5020,25 @@ test "zig fmt: make single-line if no trailing comma" {...@@ -5018,6 +5020,25 @@ test "zig fmt: make single-line if no trailing comma" {
5018 );5020 );
5019}5021}
50205022
5023test "zig fmt: while continue expr" {
5024 try testCanonical(
5025 \\test {
5026 \\ while (i > 0)
5027 \\ (i * 2);
5028 \\}
5029 \\
5030 );
5031 try testError(
5032 \\test {
5033 \\ while (i > 0) (i -= 1) {
5034 \\ print("test123", .{});
5035 \\ }
5036 \\}
5037 , &[_]Error{
5038 .expected_continue_expr,
5039 });
5040}
5041
5021test "zig fmt: error for invalid bit range" {5042test "zig fmt: error for invalid bit range" {
5022 try testError(5043 try testError(
5023 \\var x: []align(0:0:0)u8 = bar;5044 \\var x: []align(0:0:0)u8 = bar;
...@@ -5057,7 +5078,9 @@ test "recovery: block statements" {...@@ -5057,7 +5078,9 @@ test "recovery: block statements" {
5057 \\ inline;5078 \\ inline;
5058 \\}5079 \\}
5059 , &[_]Error{5080 , &[_]Error{
5060 .invalid_token,5081 .expected_expr,
5082 .expected_semi_after_stmt,
5083 .expected_statement,
5061 .expected_inlinable,5084 .expected_inlinable,
5062 });5085 });
5063}5086}
...@@ -5076,7 +5099,7 @@ test "recovery: missing comma" {...@@ -5076,7 +5099,7 @@ test "recovery: missing comma" {
5076 , &[_]Error{5099 , &[_]Error{
5077 .expected_comma_after_switch_prong,5100 .expected_comma_after_switch_prong,
5078 .expected_comma_after_switch_prong,5101 .expected_comma_after_switch_prong,
5079 .invalid_token,5102 .expected_expr,
5080 });5103 });
5081}5104}
50825105
lib/std/zig/tokenizer.zig+12-1
...@@ -322,7 +322,18 @@ pub const Token = struct {...@@ -322,7 +322,18 @@ pub const Token = struct {
322 }322 }
323323
324 pub fn symbol(tag: Tag) []const u8 {324 pub fn symbol(tag: Tag) []const u8 {
325 return tag.lexeme() orelse @tagName(tag);325 return tag.lexeme() orelse switch (tag) {
326 .invalid => "invalid bytes",
327 .identifier => "an identifier",
328 .string_literal, .multiline_string_literal_line => "a string literal",
329 .char_literal => "a character literal",
330 .eof => "EOF",
331 .builtin => "a builtin function",
332 .integer_literal => "an integer literal",
333 .float_literal => "a floating point literal",
334 .doc_comment, .container_doc_comment => "a document comment",
335 else => unreachable,
336 };
326 }337 }
327 };338 };
328};339};
src/Module.zig+15-4
...@@ -2995,7 +2995,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2995,7 +2995,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
2995 const token_starts = file.tree.tokens.items(.start);2995 const token_starts = file.tree.tokens.items(.start);
2996 const token_tags = file.tree.tokens.items(.tag);2996 const token_tags = file.tree.tokens.items(.tag);
29972997
2998 const extra_offset = file.tree.errorOffset(parse_err.tag, parse_err.token);2998 const extra_offset = file.tree.errorOffset(parse_err);
2999 try file.tree.renderError(parse_err, msg.writer());2999 try file.tree.renderError(parse_err, msg.writer());
3000 const err_msg = try gpa.create(ErrorMsg);3000 const err_msg = try gpa.create(ErrorMsg);
3001 err_msg.* = .{3001 err_msg.* = .{
...@@ -3006,14 +3006,25 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3006,14 +3006,25 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3006 },3006 },
3007 .msg = msg.toOwnedSlice(),3007 .msg = msg.toOwnedSlice(),
3008 };3008 };
3009 if (token_tags[parse_err.token] == .invalid) {3009 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
3010 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token).len);3010 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
3011 const byte_abs = token_starts[parse_err.token] + bad_off;3011 const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
3012 try mod.errNoteNonLazy(.{3012 try mod.errNoteNonLazy(.{
3013 .file_scope = file,3013 .file_scope = file,
3014 .parent_decl_node = 0,3014 .parent_decl_node = 0,
3015 .lazy = .{ .byte_abs = byte_abs },3015 .lazy = .{ .byte_abs = byte_abs },
3016 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});3016 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
3017 } else if (parse_err.tag == .decl_between_fields) {
3018 try mod.errNoteNonLazy(.{
3019 .file_scope = file,
3020 .parent_decl_node = 0,
3021 .lazy = .{ .byte_abs = token_starts[file.tree.errors[1].token] },
3022 }, err_msg, "field before declarations here", .{});
3023 try mod.errNoteNonLazy(.{
3024 .file_scope = file,
3025 .parent_decl_node = 0,
3026 .lazy = .{ .byte_abs = token_starts[file.tree.errors[2].token] },
3027 }, err_msg, "field after declarations here", .{});
3017 }3028 }
30183029
3019 {3030 {
src/main.zig+80-61
...@@ -3799,9 +3799,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -3799,9 +3799,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
3799 };3799 };
3800 defer tree.deinit(gpa);3800 defer tree.deinit(gpa);
38013801
3802 for (tree.errors) |parse_error| {3802 try printErrsMsgToStdErr(gpa, arena, tree.errors, tree, "<stdin>", color);
3803 try printErrMsgToStdErr(gpa, arena, parse_error, tree, "<stdin>", color);
3804 }
3805 var has_ast_error = false;3803 var has_ast_error = false;
3806 if (check_ast_flag) {3804 if (check_ast_flag) {
3807 const Module = @import("Module.zig");3805 const Module = @import("Module.zig");
...@@ -3989,9 +3987,7 @@ fn fmtPathFile(...@@ -3989,9 +3987,7 @@ fn fmtPathFile(
3989 var tree = try std.zig.parse(fmt.gpa, source_code);3987 var tree = try std.zig.parse(fmt.gpa, source_code);
3990 defer tree.deinit(fmt.gpa);3988 defer tree.deinit(fmt.gpa);
39913989
3992 for (tree.errors) |parse_error| {3990 try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree.errors, tree, file_path, fmt.color);
3993 try printErrMsgToStdErr(fmt.gpa, fmt.arena, parse_error, tree, file_path, fmt.color);
3994 }
3995 if (tree.errors.len != 0) {3991 if (tree.errors.len != 0) {
3996 fmt.any_error = true;3992 fmt.any_error = true;
3997 return;3993 return;
...@@ -4071,66 +4067,95 @@ fn fmtPathFile(...@@ -4071,66 +4067,95 @@ fn fmtPathFile(
4071 }4067 }
4072}4068}
40734069
4074fn printErrMsgToStdErr(4070fn printErrsMsgToStdErr(
4075 gpa: mem.Allocator,4071 gpa: mem.Allocator,
4076 arena: mem.Allocator,4072 arena: mem.Allocator,
4077 parse_error: Ast.Error,4073 parse_errors: []const Ast.Error,
4078 tree: Ast,4074 tree: Ast,
4079 path: []const u8,4075 path: []const u8,
4080 color: Color,4076 color: Color,
4081) !void {4077) !void {
4082 const lok_token = parse_error.token;4078 var i: usize = 0;
4083 const token_tags = tree.tokens.items(.tag);4079 while (i < parse_errors.len) : (i += 1) {
4084 const start_loc = tree.tokenLocation(0, lok_token);4080 const parse_error = parse_errors[i];
4085 const source_line = tree.source[start_loc.line_start..start_loc.line_end];4081 const lok_token = parse_error.token;
40864082 const token_tags = tree.tokens.items(.tag);
4087 var text_buf = std.ArrayList(u8).init(gpa);4083 const start_loc = tree.tokenLocation(0, lok_token);
4088 defer text_buf.deinit();4084 const source_line = tree.source[start_loc.line_start..start_loc.line_end];
4089 const writer = text_buf.writer();4085
4090 try tree.renderError(parse_error, writer);4086 var text_buf = std.ArrayList(u8).init(gpa);
4091 const text = text_buf.items;4087 defer text_buf.deinit();
40924088 const writer = text_buf.writer();
4093 var notes_buffer: [1]Compilation.AllErrors.Message = undefined;4089 try tree.renderError(parse_error, writer);
4094 var notes_len: usize = 0;4090 const text = text_buf.items;
40954091
4096 if (token_tags[parse_error.token] == .invalid) {4092 var notes_buffer: [2]Compilation.AllErrors.Message = undefined;
4097 const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token).len);4093 var notes_len: usize = 0;
4098 const byte_offset = @intCast(u32, start_loc.line_start) + bad_off;4094
4099 notes_buffer[notes_len] = .{4095 if (token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)] == .invalid) {
4096 const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token + @boolToInt(parse_error.token_is_prev)).len);
4097 const byte_offset = @intCast(u32, start_loc.line_start) + @intCast(u32, start_loc.column) + bad_off;
4098 notes_buffer[notes_len] = .{
4099 .src = .{
4100 .src_path = path,
4101 .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
4102 std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
4103 }),
4104 .byte_offset = byte_offset,
4105 .line = @intCast(u32, start_loc.line),
4106 .column = @intCast(u32, start_loc.column) + bad_off,
4107 .source_line = source_line,
4108 },
4109 };
4110 notes_len += 1;
4111 } else if (parse_error.tag == .decl_between_fields) {
4112 const prev_loc = tree.tokenLocation(0, parse_errors[i + 1].token);
4113 notes_buffer[0] = .{
4114 .src = .{
4115 .src_path = path,
4116 .msg = "field before declarations here",
4117 .byte_offset = @intCast(u32, prev_loc.line_start),
4118 .line = @intCast(u32, prev_loc.line),
4119 .column = @intCast(u32, prev_loc.column),
4120 .source_line = tree.source[prev_loc.line_start..prev_loc.line_end],
4121 },
4122 };
4123 const next_loc = tree.tokenLocation(0, parse_errors[i + 2].token);
4124 notes_buffer[1] = .{
4125 .src = .{
4126 .src_path = path,
4127 .msg = "field after declarations here",
4128 .byte_offset = @intCast(u32, next_loc.line_start),
4129 .line = @intCast(u32, next_loc.line),
4130 .column = @intCast(u32, next_loc.column),
4131 .source_line = tree.source[next_loc.line_start..next_loc.line_end],
4132 },
4133 };
4134 notes_len = 2;
4135 i += 2;
4136 }
4137
4138 const extra_offset = tree.errorOffset(parse_error);
4139 const message: Compilation.AllErrors.Message = .{
4100 .src = .{4140 .src = .{
4101 .src_path = path,4141 .src_path = path,
4102 .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{4142 .msg = text,
4103 std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),4143 .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset,
4104 }),
4105 .byte_offset = byte_offset,
4106 .line = @intCast(u32, start_loc.line),4144 .line = @intCast(u32, start_loc.line),
4107 .column = @intCast(u32, start_loc.column) + bad_off,4145 .column = @intCast(u32, start_loc.column) + extra_offset,
4108 .source_line = source_line,4146 .source_line = source_line,
4147 .notes = notes_buffer[0..notes_len],
4109 },4148 },
4110 };4149 };
4111 notes_len += 1;
4112 }
41134150
4114 const extra_offset = tree.errorOffset(parse_error.tag, parse_error.token);4151 const ttyconf: std.debug.TTY.Config = switch (color) {
4115 const message: Compilation.AllErrors.Message = .{4152 .auto => std.debug.detectTTYConfig(),
4116 .src = .{4153 .on => .escape_codes,
4117 .src_path = path,4154 .off => .no_color,
4118 .msg = text,4155 };
4119 .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset,
4120 .line = @intCast(u32, start_loc.line),
4121 .column = @intCast(u32, start_loc.column) + extra_offset,
4122 .source_line = source_line,
4123 .notes = notes_buffer[0..notes_len],
4124 },
4125 };
4126
4127 const ttyconf: std.debug.TTY.Config = switch (color) {
4128 .auto => std.debug.detectTTYConfig(),
4129 .on => .escape_codes,
4130 .off => .no_color,
4131 };
41324156
4133 message.renderToStdErr(ttyconf);4157 message.renderToStdErr(ttyconf);
4158 }
4134}4159}
41354160
4136pub const info_zen =4161pub const info_zen =
...@@ -4688,9 +4713,7 @@ pub fn cmdAstCheck(...@@ -4688,9 +4713,7 @@ pub fn cmdAstCheck(
4688 file.tree_loaded = true;4713 file.tree_loaded = true;
4689 defer file.tree.deinit(gpa);4714 defer file.tree.deinit(gpa);
46904715
4691 for (file.tree.errors) |parse_error| {4716 try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, file.sub_file_path, color);
4692 try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, file.sub_file_path, color);
4693 }
4694 if (file.tree.errors.len != 0) {4717 if (file.tree.errors.len != 0) {
4695 process.exit(1);4718 process.exit(1);
4696 }4719 }
...@@ -4816,9 +4839,7 @@ pub fn cmdChangelist(...@@ -4816,9 +4839,7 @@ pub fn cmdChangelist(
4816 file.tree_loaded = true;4839 file.tree_loaded = true;
4817 defer file.tree.deinit(gpa);4840 defer file.tree.deinit(gpa);
48184841
4819 for (file.tree.errors) |parse_error| {4842 try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, old_source_file, .auto);
4820 try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, old_source_file, .auto);
4821 }
4822 if (file.tree.errors.len != 0) {4843 if (file.tree.errors.len != 0) {
4823 process.exit(1);4844 process.exit(1);
4824 }4845 }
...@@ -4855,9 +4876,7 @@ pub fn cmdChangelist(...@@ -4855,9 +4876,7 @@ pub fn cmdChangelist(
4855 var new_tree = try std.zig.parse(gpa, new_source);4876 var new_tree = try std.zig.parse(gpa, new_source);
4856 defer new_tree.deinit(gpa);4877 defer new_tree.deinit(gpa);
48574878
4858 for (new_tree.errors) |parse_error| {4879 try printErrsMsgToStdErr(gpa, arena, new_tree.errors, new_tree, new_source_file, .auto);
4859 try printErrMsgToStdErr(gpa, arena, parse_error, new_tree, new_source_file, .auto);
4860 }
4861 if (new_tree.errors.len != 0) {4880 if (new_tree.errors.len != 0) {
4862 process.exit(1);4881 process.exit(1);
4863 }4882 }
src/stage1/ir.cpp+27-4
...@@ -7843,7 +7843,7 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou...@@ -7843,7 +7843,7 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
7843 bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 07843 bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0
7844 || !actual_type->data.pointer.is_const);7844 || !actual_type->data.pointer.is_const);
78457845
7846 if (const_ok && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,7846 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
7847 array_type->data.array.child_type, source_node,7847 array_type->data.array.child_type, source_node,
7848 !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk &&7848 !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk &&
7849 (slice_ptr_type->data.pointer.sentinel == nullptr ||7849 (slice_ptr_type->data.pointer.sentinel == nullptr ||
...@@ -7851,6 +7851,14 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou...@@ -7851,6 +7851,14 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
7851 const_values_equal(ira->codegen, array_type->data.array.sentinel,7851 const_values_equal(ira->codegen, array_type->data.array.sentinel,
7852 slice_ptr_type->data.pointer.sentinel))))7852 slice_ptr_type->data.pointer.sentinel))))
7853 {7853 {
7854 if (!const_ok) {
7855 ErrorMsg *msg = ir_add_error_node(ira, source_node,
7856 buf_sprintf("cannot cast pointer to array literal to slice type '%s'",
7857 buf_ptr(&wanted_type->name)));
7858 add_error_note(ira->codegen, msg, source_node,
7859 buf_sprintf("cast discards const qualifier"));
7860 return ira->codegen->invalid_inst_gen;
7861 }
7854 // If the pointers both have ABI align, it works.7862 // If the pointers both have ABI align, it works.
7855 // Or if the array length is 0, alignment doesn't matter.7863 // Or if the array length is 0, alignment doesn't matter.
7856 bool ok_align = array_type->data.array.len == 0 ||7864 bool ok_align = array_type->data.array.len == 0 ||
...@@ -8208,8 +8216,16 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou...@@ -8208,8 +8216,16 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
8208 ZigType *wanted_child = wanted_type->data.pointer.child_type;8216 ZigType *wanted_child = wanted_type->data.pointer.child_type;
8209 bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const);8217 bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const);
8210 if (wanted_child->id == ZigTypeIdArray && (is_array_init || field_count == 0) &&8218 if (wanted_child->id == ZigTypeIdArray && (is_array_init || field_count == 0) &&
8211 wanted_child->data.array.len == field_count && (const_ok || field_count == 0))8219 wanted_child->data.array.len == field_count)
8212 {8220 {
8221 if (!const_ok && field_count != 0) {
8222 ErrorMsg *msg = ir_add_error_node(ira, source_node,
8223 buf_sprintf("cannot cast pointer to array literal to '%s'",
8224 buf_ptr(&wanted_type->name)));
8225 add_error_note(ira->codegen, msg, source_node,
8226 buf_sprintf("cast discards const qualifier"));
8227 return ira->codegen->invalid_inst_gen;
8228 }
8213 Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child);8229 Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child);
8214 if (res->value->type->id == ZigTypeIdPointer)8230 if (res->value->type->id == ZigTypeIdPointer)
8215 return res;8231 return res;
...@@ -8241,6 +8257,13 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou...@@ -8241,6 +8257,13 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
8241 res = ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile);8257 res = ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile);
82428258
8243 return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, res, wanted_type, nullptr);8259 return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, res, wanted_type, nullptr);
8260 } else if (!slice_type->data.pointer.is_const && actual_type->data.pointer.is_const && field_count != 0) {
8261 ErrorMsg *msg = ir_add_error_node(ira, source_node,
8262 buf_sprintf("cannot cast pointer to array literal to slice type '%s'",
8263 buf_ptr(&wanted_type->name)));
8264 add_error_note(ira->codegen, msg, source_node,
8265 buf_sprintf("cast discards const qualifier"));
8266 return ira->codegen->invalid_inst_gen;
8244 }8267 }
8245 }8268 }
8246 }8269 }
...@@ -15068,7 +15091,7 @@ static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirI...@@ -15068,7 +15091,7 @@ static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirI
15068 return ira->codegen->invalid_inst_gen;15091 return ira->codegen->invalid_inst_gen;
15069 if (actual_array_type->id != ZigTypeIdArray) {15092 if (actual_array_type->id != ZigTypeIdArray) {
15070 ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node,15093 ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node,
15071 buf_sprintf("array literal requires address-of operator to coerce to slice type '%s'",15094 buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'",
15072 buf_ptr(&actual_array_type->name)));15095 buf_ptr(&actual_array_type->name)));
15073 return ira->codegen->invalid_inst_gen;15096 return ira->codegen->invalid_inst_gen;
15074 }15097 }
...@@ -17473,7 +17496,7 @@ static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira,...@@ -17473,7 +17496,7 @@ static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
1747317496
17474 if (is_slice(container_type)) {17497 if (is_slice(container_type)) {
17475 ir_add_error_node(ira, instruction->init_array_type_source_node,17498 ir_add_error_node(ira, instruction->init_array_type_source_node,
17476 buf_sprintf("array literal requires address-of operator to coerce to slice type '%s'",17499 buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'",
17477 buf_ptr(&container_type->name)));17500 buf_ptr(&container_type->name)));
17478 return ira->codegen->invalid_inst_gen;17501 return ira->codegen->invalid_inst_gen;
17479 }17502 }
test/compile_errors.zig+40-33
...@@ -86,9 +86,12 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -86,9 +86,12 @@ pub fn addCases(ctx: *TestContext) !void {
86 \\ _ = c;86 \\ _ = c;
87 \\}87 \\}
88 , &[_][]const u8{88 , &[_][]const u8{
89 "tmp.zig:2:31: error: expected type '[][]const u8', found '*const struct:2:31'",89 "tmp.zig:2:31: error: cannot cast pointer to array literal to slice type '[][]const u8'",
90 "tmp.zig:6:33: error: expected type '*[2][]const u8', found '*const struct:6:33'",90 "tmp.zig:2:31: note: cast discards const qualifier",
91 "tmp.zig:6:33: error: cannot cast pointer to array literal to '*[2][]const u8'",
92 "tmp.zig:6:33: note: cast discards const qualifier",
91 "tmp.zig:11:21: error: expected type '*S', found '*const struct:11:21'",93 "tmp.zig:11:21: error: expected type '*S', found '*const struct:11:21'",
94 "tmp.zig:11:21: note: cast discards const qualifier",
92 });95 });
9396
94 ctx.objErrStage1("@Type() union payload is undefined",97 ctx.objErrStage1("@Type() union payload is undefined",
...@@ -874,6 +877,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -874,6 +877,8 @@ pub fn addCases(ctx: *TestContext) !void {
874 \\}877 \\}
875 , &[_][]const u8{878 , &[_][]const u8{
876 "tmp.zig:6:5: error: declarations are not allowed between container fields",879 "tmp.zig:6:5: error: declarations are not allowed between container fields",
880 "tmp.zig:5:5: note: field before declarations here",
881 "tmp.zig:9:5: note: field after declarations here",
877 });882 });
878883
879 ctx.objErrStage1("non-extern function with var args",884 ctx.objErrStage1("non-extern function with var args",
...@@ -1540,7 +1545,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1540,7 +1545,7 @@ pub fn addCases(ctx: *TestContext) !void {
1540 \\ std.debug.assert(bad_float < 1.0);1545 \\ std.debug.assert(bad_float < 1.0);
1541 \\}1546 \\}
1542 , &[_][]const u8{1547 , &[_][]const u8{
1543 "tmp.zig:5:29: error: invalid token: '.'",1548 "tmp.zig:5:29: error: expected expression, found '.'",
1544 });1549 });
15451550
1546 ctx.objErrStage1("invalid exponent in float literal - 1",1551 ctx.objErrStage1("invalid exponent in float literal - 1",
...@@ -1549,7 +1554,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1549,7 +1554,7 @@ pub fn addCases(ctx: *TestContext) !void {
1549 \\ _ = bad;1554 \\ _ = bad;
1550 \\}1555 \\}
1551 , &[_][]const u8{1556 , &[_][]const u8{
1552 "tmp.zig:2:21: error: expected expression, found 'invalid'",1557 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1553 "tmp.zig:2:28: note: invalid byte: 'a'",1558 "tmp.zig:2:28: note: invalid byte: 'a'",
1554 });1559 });
15551560
...@@ -1559,7 +1564,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1559,7 +1564,7 @@ pub fn addCases(ctx: *TestContext) !void {
1559 \\ _ = bad;1564 \\ _ = bad;
1560 \\}1565 \\}
1561 , &[_][]const u8{1566 , &[_][]const u8{
1562 "tmp.zig:2:21: error: expected expression, found 'invalid'",1567 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1563 "tmp.zig:2:29: note: invalid byte: 'F'",1568 "tmp.zig:2:29: note: invalid byte: 'F'",
1564 });1569 });
15651570
...@@ -1569,7 +1574,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1569,7 +1574,7 @@ pub fn addCases(ctx: *TestContext) !void {
1569 \\ _ = bad;1574 \\ _ = bad;
1570 \\}1575 \\}
1571 , &[_][]const u8{1576 , &[_][]const u8{
1572 "tmp.zig:2:21: error: expected expression, found 'invalid'",1577 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1573 "tmp.zig:2:23: note: invalid byte: '_'",1578 "tmp.zig:2:23: note: invalid byte: '_'",
1574 });1579 });
15751580
...@@ -1579,7 +1584,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1579,7 +1584,7 @@ pub fn addCases(ctx: *TestContext) !void {
1579 \\ _ = bad;1584 \\ _ = bad;
1580 \\}1585 \\}
1581 , &[_][]const u8{1586 , &[_][]const u8{
1582 "tmp.zig:2:21: error: expected expression, found 'invalid'",1587 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1583 "tmp.zig:2:23: note: invalid byte: '.'",1588 "tmp.zig:2:23: note: invalid byte: '.'",
1584 });1589 });
15851590
...@@ -1589,7 +1594,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1589,7 +1594,7 @@ pub fn addCases(ctx: *TestContext) !void {
1589 \\ _ = bad;1594 \\ _ = bad;
1590 \\}1595 \\}
1591 , &[_][]const u8{1596 , &[_][]const u8{
1592 "tmp.zig:2:21: error: expected expression, found 'invalid'",1597 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1593 "tmp.zig:2:25: note: invalid byte: ';'",1598 "tmp.zig:2:25: note: invalid byte: ';'",
1594 });1599 });
15951600
...@@ -1599,7 +1604,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1599,7 +1604,7 @@ pub fn addCases(ctx: *TestContext) !void {
1599 \\ _ = bad;1604 \\ _ = bad;
1600 \\}1605 \\}
1601 , &[_][]const u8{1606 , &[_][]const u8{
1602 "tmp.zig:2:21: error: expected expression, found 'invalid'",1607 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1603 "tmp.zig:2:25: note: invalid byte: '_'",1608 "tmp.zig:2:25: note: invalid byte: '_'",
1604 });1609 });
16051610
...@@ -1609,7 +1614,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1609,7 +1614,7 @@ pub fn addCases(ctx: *TestContext) !void {
1609 \\ _ = bad;1614 \\ _ = bad;
1610 \\}1615 \\}
1611 , &[_][]const u8{1616 , &[_][]const u8{
1612 "tmp.zig:2:21: error: expected expression, found 'invalid'",1617 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1613 "tmp.zig:2:26: note: invalid byte: '_'",1618 "tmp.zig:2:26: note: invalid byte: '_'",
1614 });1619 });
16151620
...@@ -1619,7 +1624,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1619,7 +1624,7 @@ pub fn addCases(ctx: *TestContext) !void {
1619 \\ _ = bad;1624 \\ _ = bad;
1620 \\}1625 \\}
1621 , &[_][]const u8{1626 , &[_][]const u8{
1622 "tmp.zig:2:21: error: expected expression, found 'invalid'",1627 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1623 "tmp.zig:2:26: note: invalid byte: '_'",1628 "tmp.zig:2:26: note: invalid byte: '_'",
1624 });1629 });
16251630
...@@ -1629,7 +1634,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1629,7 +1634,7 @@ pub fn addCases(ctx: *TestContext) !void {
1629 \\ _ = bad;1634 \\ _ = bad;
1630 \\}1635 \\}
1631 , &[_][]const u8{1636 , &[_][]const u8{
1632 "tmp.zig:2:21: error: expected expression, found 'invalid'",1637 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1633 "tmp.zig:2:28: note: invalid byte: ';'",1638 "tmp.zig:2:28: note: invalid byte: ';'",
1634 });1639 });
16351640
...@@ -1639,7 +1644,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1639,7 +1644,7 @@ pub fn addCases(ctx: *TestContext) !void {
1639 \\ _ = bad;1644 \\ _ = bad;
1640 \\}1645 \\}
1641 , &[_][]const u8{1646 , &[_][]const u8{
1642 "tmp.zig:2:21: error: expected expression, found 'invalid'",1647 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1643 "tmp.zig:2:23: note: invalid byte: '_'",1648 "tmp.zig:2:23: note: invalid byte: '_'",
1644 });1649 });
16451650
...@@ -1649,7 +1654,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1649,7 +1654,7 @@ pub fn addCases(ctx: *TestContext) !void {
1649 \\ _ = bad;1654 \\ _ = bad;
1650 \\}1655 \\}
1651 , &[_][]const u8{1656 , &[_][]const u8{
1652 "tmp.zig:2:21: error: expected expression, found 'invalid'",1657 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1653 "tmp.zig:2:25: note: invalid byte: '_'",1658 "tmp.zig:2:25: note: invalid byte: '_'",
1654 });1659 });
16551660
...@@ -1659,7 +1664,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1659,7 +1664,7 @@ pub fn addCases(ctx: *TestContext) !void {
1659 \\ _ = bad;1664 \\ _ = bad;
1660 \\}1665 \\}
1661 , &[_][]const u8{1666 , &[_][]const u8{
1662 "tmp.zig:2:21: error: expected expression, found 'invalid'",1667 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1663 "tmp.zig:2:28: note: invalid byte: '_'",1668 "tmp.zig:2:28: note: invalid byte: '_'",
1664 });1669 });
16651670
...@@ -1669,7 +1674,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1669,7 +1674,7 @@ pub fn addCases(ctx: *TestContext) !void {
1669 \\ _ = bad;1674 \\ _ = bad;
1670 \\}1675 \\}
1671 , &[_][]const u8{1676 , &[_][]const u8{
1672 "tmp.zig:2:21: error: expected expression, found 'invalid'",1677 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1673 "tmp.zig:2:23: note: invalid byte: 'x'",1678 "tmp.zig:2:23: note: invalid byte: 'x'",
1674 });1679 });
16751680
...@@ -1679,7 +1684,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1679,7 +1684,7 @@ pub fn addCases(ctx: *TestContext) !void {
1679 \\ _ = bad;1684 \\ _ = bad;
1680 \\}1685 \\}
1681 , &[_][]const u8{1686 , &[_][]const u8{
1682 "tmp.zig:2:21: error: expected expression, found 'invalid'",1687 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1683 "tmp.zig:2:23: note: invalid byte: '_'",1688 "tmp.zig:2:23: note: invalid byte: '_'",
1684 });1689 });
16851690
...@@ -1689,7 +1694,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1689,7 +1694,7 @@ pub fn addCases(ctx: *TestContext) !void {
1689 \\ _ = bad;1694 \\ _ = bad;
1690 \\}1695 \\}
1691 , &[_][]const u8{1696 , &[_][]const u8{
1692 "tmp.zig:2:21: error: expected expression, found 'invalid'",1697 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1693 "tmp.zig:2:27: note: invalid byte: 'p'",1698 "tmp.zig:2:27: note: invalid byte: 'p'",
1694 });1699 });
16951700
...@@ -1699,7 +1704,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1699,7 +1704,7 @@ pub fn addCases(ctx: *TestContext) !void {
1699 \\ _ = bad;1704 \\ _ = bad;
1700 \\}1705 \\}
1701 , &[_][]const u8{1706 , &[_][]const u8{
1702 "tmp.zig:2:21: error: expected expression, found 'invalid'",1707 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1703 "tmp.zig:2:26: note: invalid byte: ';'",1708 "tmp.zig:2:26: note: invalid byte: ';'",
1704 });1709 });
17051710
...@@ -1709,7 +1714,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1709,7 +1714,7 @@ pub fn addCases(ctx: *TestContext) !void {
1709 \\ _ = bad;1714 \\ _ = bad;
1710 \\}1715 \\}
1711 , &[_][]const u8{1716 , &[_][]const u8{
1712 "tmp.zig:2:21: error: expected expression, found 'invalid'",1717 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1713 "tmp.zig:2:28: note: invalid byte: ';'",1718 "tmp.zig:2:28: note: invalid byte: ';'",
1714 });1719 });
17151720
...@@ -1719,7 +1724,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1719,7 +1724,7 @@ pub fn addCases(ctx: *TestContext) !void {
1719 \\ _ = bad;1724 \\ _ = bad;
1720 \\}1725 \\}
1721 , &[_][]const u8{1726 , &[_][]const u8{
1722 "tmp.zig:2:21: error: expected expression, found 'invalid'",1727 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1723 "tmp.zig:2:28: note: invalid byte: ';'",1728 "tmp.zig:2:28: note: invalid byte: ';'",
1724 });1729 });
17251730
...@@ -1729,7 +1734,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1729,7 +1734,7 @@ pub fn addCases(ctx: *TestContext) !void {
1729 \\ _ = bad;1734 \\ _ = bad;
1730 \\}1735 \\}
1731 , &[_][]const u8{1736 , &[_][]const u8{
1732 "tmp.zig:2:21: error: expected expression, found 'invalid'",1737 "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
1733 "tmp.zig:2:28: note: invalid byte: ';'",1738 "tmp.zig:2:28: note: invalid byte: ';'",
1734 });1739 });
17351740
...@@ -1962,7 +1967,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1962,7 +1967,7 @@ pub fn addCases(ctx: *TestContext) !void {
1962 \\ _ = geo_data;1967 \\ _ = geo_data;
1963 \\}1968 \\}
1964 , &[_][]const u8{1969 , &[_][]const u8{
1965 "tmp.zig:4:30: error: array literal requires address-of operator to coerce to slice type '[][2]f32'",1970 "tmp.zig:4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'",
1966 });1971 });
19671972
1968 ctx.objErrStage1("slicing of global undefined pointer",1973 ctx.objErrStage1("slicing of global undefined pointer",
...@@ -2171,7 +2176,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -2171,7 +2176,7 @@ pub fn addCases(ctx: *TestContext) !void {
2171 \\ _ = x;2176 \\ _ = x;
2172 \\}2177 \\}
2173 , &[_][]const u8{2178 , &[_][]const u8{
2174 "tmp.zig:3:6: error: expected ',' after field",2179 "tmp.zig:3:7: error: expected ',' after field",
2175 });2180 });
21762181
2177 ctx.objErrStage1("bad alignment type",2182 ctx.objErrStage1("bad alignment type",
...@@ -2537,7 +2542,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -2537,7 +2542,7 @@ pub fn addCases(ctx: *TestContext) !void {
2537 \\ _ = x;2542 \\ _ = x;
2538 \\}2543 \\}
2539 , &[_][]const u8{2544 , &[_][]const u8{
2540 "tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'",2545 "tmp.zig:2:15: error: array literal requires address-of operator (&) to coerce to slice type '[]u8'",
2541 });2546 });
25422547
2543 ctx.objErrStage1("slice passed as array init type",2548 ctx.objErrStage1("slice passed as array init type",
...@@ -2546,7 +2551,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -2546,7 +2551,7 @@ pub fn addCases(ctx: *TestContext) !void {
2546 \\ _ = x;2551 \\ _ = x;
2547 \\}2552 \\}
2548 , &[_][]const u8{2553 , &[_][]const u8{
2549 "tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'",2554 "tmp.zig:2:15: error: array literal requires address-of operator (&) to coerce to slice type '[]u8'",
2550 });2555 });
25512556
2552 ctx.objErrStage1("inferred array size invalid here",2557 ctx.objErrStage1("inferred array size invalid here",
...@@ -3493,7 +3498,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -3493,7 +3498,8 @@ pub fn addCases(ctx: *TestContext) !void {
3493 \\ _ = sliceA;3498 \\ _ = sliceA;
3494 \\}3499 \\}
3495 , &[_][]const u8{3500 , &[_][]const u8{
3496 "tmp.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",3501 "tmp.zig:3:27: error: cannot cast pointer to array literal to slice type '[]u8'",
3502 "tmp.zig:3:27: note: cast discards const qualifier",
3497 });3503 });
34983504
3499 ctx.objErrStage1("deref slice and get len field",3505 ctx.objErrStage1("deref slice and get len field",
...@@ -4865,11 +4871,11 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4865,11 +4871,11 @@ pub fn addCases(ctx: *TestContext) !void {
4865 \\export fn entry() void {4871 \\export fn entry() void {
4866 \\ while(true) {}4872 \\ while(true) {}
4867 \\ var good = {};4873 \\ var good = {};
4868 \\ while(true) ({})4874 \\ while(true) 1
4869 \\ var bad = {};4875 \\ var bad = {};
4870 \\}4876 \\}
4871 , &[_][]const u8{4877 , &[_][]const u8{
4872 "tmp.zig:4:21: error: expected ';' or 'else' after statement",4878 "tmp.zig:4:18: error: expected ';' or 'else' after statement",
4873 });4879 });
48744880
4875 ctx.objErrStage1("implicit semicolon - while expression",4881 ctx.objErrStage1("implicit semicolon - while expression",
...@@ -5733,7 +5739,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -5733,7 +5739,7 @@ pub fn addCases(ctx: *TestContext) !void {
5733 \\const foo = "a5739 \\const foo = "a
5734 \\b";5740 \\b";
5735 , &[_][]const u8{5741 , &[_][]const u8{
5736 "tmp.zig:1:13: error: expected expression, found 'invalid'",5742 "tmp.zig:1:13: error: expected expression, found 'invalid bytes'",
5737 "tmp.zig:1:15: note: invalid byte: '\\n'",5743 "tmp.zig:1:15: note: invalid byte: '\\n'",
5738 });5744 });
57395745
...@@ -7638,7 +7644,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -7638,7 +7644,7 @@ pub fn addCases(ctx: *TestContext) !void {
7638 \\ const a = '\U1234';7644 \\ const a = '\U1234';
7639 \\}7645 \\}
7640 , &[_][]const u8{7646 , &[_][]const u8{
7641 "tmp.zig:2:15: error: expected expression, found 'invalid'",7647 "tmp.zig:2:15: error: expected expression, found 'invalid bytes'",
7642 "tmp.zig:2:18: note: invalid byte: '1'",7648 "tmp.zig:2:18: note: invalid byte: '1'",
7643 });7649 });
76447650
...@@ -7654,7 +7660,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -7654,7 +7660,7 @@ pub fn addCases(ctx: *TestContext) !void {
7654 "fn foo() bool {\r\n" ++7660 "fn foo() bool {\r\n" ++
7655 " return true;\r\n" ++7661 " return true;\r\n" ++
7656 "}\r\n", &[_][]const u8{7662 "}\r\n", &[_][]const u8{
7657 "tmp.zig:1:1: error: expected test, comptime, var decl, or container field, found 'invalid'",7663 "tmp.zig:1:1: error: expected test, comptime, var decl, or container field, found 'invalid bytes'",
7658 "tmp.zig:1:1: note: invalid byte: '\\xff'",7664 "tmp.zig:1:1: note: invalid byte: '\\xff'",
7659 });7665 });
76607666
...@@ -8717,7 +8723,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -8717,7 +8723,8 @@ pub fn addCases(ctx: *TestContext) !void {
8717 \\ comptime ignore(@typeInfo(MyStruct).Struct.fields[0]);8723 \\ comptime ignore(@typeInfo(MyStruct).Struct.fields[0]);
8718 \\}8724 \\}
8719 , &[_][]const u8{8725 , &[_][]const u8{
8720 ":5:28: error: expected type '[]u8', found '*const [3:0]u8'",8726 ":5:28: error: cannot cast pointer to array literal to slice type '[]u8'",
8727 ":5:28: note: cast discards const qualifier",
8721 });8728 });
87228729
8723 ctx.objErrStage1("integer underflow error",8730 ctx.objErrStage1("integer underflow error",
test/stage2/cbe.zig+1-1
...@@ -693,7 +693,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -693,7 +693,7 @@ pub fn addCases(ctx: *TestContext) !void {
693 \\ _ = E1.a;693 \\ _ = E1.a;
694 \\}694 \\}
695 , &.{695 , &.{
696 ":3:6: error: expected ',' after field",696 ":3:7: error: expected ',' after field",
697 });697 });
698698
699 // Redundant non-exhaustive enum mark.699 // Redundant non-exhaustive enum mark.