authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-13 16:15:00-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-13 16:15:00-05:00
logf73044dae598da2b84bff7977be5a8e02093902a
tree892a4c07e5655404e94381f075f370d0e510008e
parent2a73700c0fc177fb8781b277a6ba5017dce875b9
parent0699b29ce0c5d264bf39c5f88fa6025b61ca6303
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10879 from Vexu/err

make some errors point to the end of the previous token

6 files changed, 137 insertions(+), 81 deletions(-)

lib/std/zig/Ast.zig+51-6
...@@ -64,6 +64,24 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void...@@ -64,6 +64,24 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void
64 return @import("./render.zig").renderTree(buffer, tree);64 return @import("./render.zig").renderTree(buffer, tree);
65}65}
6666
67/// Returns an extra offset for column and byte offset of errors that
68/// should point after the token in the error message.
69pub fn errorOffset(tree: Ast, error_tag: Error.Tag, token: TokenIndex) u32 {
70 return switch (error_tag) {
71 .expected_semi_after_decl,
72 .expected_semi_after_stmt,
73 .expected_comma_after_field,
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}
84
67pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location {85pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location {
68 var loc = Location{86 var loc = Location{
69 .line = 0,87 .line = 0,
...@@ -216,14 +234,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -216,14 +234,10 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
216 });234 });
217 },235 },
218 .expected_semi_or_else => {236 .expected_semi_or_else => {
219 return stream.print("expected ';' or 'else', found '{s}'", .{237 return stream.writeAll("expected ';' or 'else' after statement");
220 token_tags[parse_error.token].symbol(),
221 });
222 },238 },
223 .expected_semi_or_lbrace => {239 .expected_semi_or_lbrace => {
224 return stream.print("expected ';' or '{{', found '{s}'", .{240 return stream.writeAll("expected ';' or block after function prototype");
225 token_tags[parse_error.token].symbol(),
226 });
227 },241 },
228 .expected_statement => {242 .expected_statement => {
229 return stream.print("expected statement, found '{s}'", .{243 return stream.print("expected statement, found '{s}'", .{
...@@ -306,6 +320,28 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {...@@ -306,6 +320,28 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
306 return stream.writeAll("function prototype has parameter after varargs");320 return stream.writeAll("function prototype has parameter after varargs");
307 },321 },
308322
323 .expected_semi_after_decl => {
324 return stream.writeAll("expected ';' after declaration");
325 },
326 .expected_semi_after_stmt => {
327 return stream.writeAll("expected ';' after statement");
328 },
329 .expected_comma_after_field => {
330 return stream.writeAll("expected ',' after field");
331 },
332 .expected_comma_after_arg => {
333 return stream.writeAll("expected ',' after argument");
334 },
335 .expected_comma_after_param => {
336 return stream.writeAll("expected ',' after parameter");
337 },
338 .expected_comma_after_initializer => {
339 return stream.writeAll("expected ',' after initializer");
340 },
341 .expected_comma_after_switch_prong => {
342 return stream.writeAll("expected ',' after switch prong");
343 },
344
309 .expected_token => {345 .expected_token => {
310 const found_tag = token_tags[parse_error.token];346 const found_tag = token_tags[parse_error.token];
311 const expected_symbol = parse_error.extra.expected_tag.symbol();347 const expected_symbol = parse_error.extra.expected_tag.symbol();
...@@ -2495,6 +2531,15 @@ pub const Error = struct {...@@ -2495,6 +2531,15 @@ pub const Error = struct {
2495 unattached_doc_comment,2531 unattached_doc_comment,
2496 varargs_nonfinal,2532 varargs_nonfinal,
24972533
2534 // these have `token` set to token after which a semicolon was expected
2535 expected_semi_after_decl,
2536 expected_semi_after_stmt,
2537 expected_comma_after_field,
2538 expected_comma_after_arg,
2539 expected_comma_after_param,
2540 expected_comma_after_initializer,
2541 expected_comma_after_switch_prong,
2542
2498 /// `expected_tag` is populated.2543 /// `expected_tag` is populated.
2499 expected_token,2544 expected_token,
2500 };2545 };
lib/std/zig/parse.zig+58-49
...@@ -160,6 +160,12 @@ const Parser = struct {...@@ -160,6 +160,12 @@ const Parser = struct {
160 .extra = .{ .expected_tag = expected_token },160 .extra = .{ .expected_tag = expected_token },
161 });161 });
162 }162 }
163
164 fn warnExpectedAfter(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void {
165 @setCold(true);
166 try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i - 1 });
167 }
168
163 fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {169 fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {
164 @setCold(true);170 @setCold(true);
165 try p.errors.append(p.gpa, msg);171 try p.errors.append(p.gpa, msg);
...@@ -258,7 +264,7 @@ const Parser = struct {...@@ -258,7 +264,7 @@ const Parser = struct {
258 }264 }
259 // There is not allowed to be a decl after a field with no comma.265 // There is not allowed to be a decl after a field with no comma.
260 // Report error but recover parser.266 // Report error but recover parser.
261 try p.warnExpected(.comma);267 try p.warnExpectedAfter(.expected_comma_after_field);
262 p.findNextContainerMember();268 p.findNextContainerMember();
263 }269 }
264 },270 },
...@@ -361,7 +367,7 @@ const Parser = struct {...@@ -361,7 +367,7 @@ const Parser = struct {
361 }367 }
362 // There is not allowed to be a decl after a field with no comma.368 // There is not allowed to be a decl after a field with no comma.
363 // Report error but recover parser.369 // Report error but recover parser.
364 try p.warnExpected(.comma);370 try p.warnExpectedAfter(.expected_comma_after_field);
365 p.findNextContainerMember();371 p.findNextContainerMember();
366 }372 }
367 },373 },
...@@ -579,7 +585,7 @@ const Parser = struct {...@@ -579,7 +585,7 @@ const Parser = struct {
579 // Since parseBlock only return error.ParseError on585 // Since parseBlock only return error.ParseError on
580 // a missing '}' we can assume this function was586 // a missing '}' we can assume this function was
581 // supposed to end here.587 // supposed to end here.
582 try p.warn(.expected_semi_or_lbrace);588 try p.warnExpectedAfter(.expected_semi_or_lbrace);
583 return null_node;589 return null_node;
584 },590 },
585 }591 }
...@@ -592,7 +598,7 @@ const Parser = struct {...@@ -592,7 +598,7 @@ const Parser = struct {
592 const thread_local_token = p.eatToken(.keyword_threadlocal);598 const thread_local_token = p.eatToken(.keyword_threadlocal);
593 const var_decl = try p.parseVarDecl();599 const var_decl = try p.parseVarDecl();
594 if (var_decl != 0) {600 if (var_decl != 0) {
595 _ = try p.expectToken(.semicolon);601 try p.expectSemicolon(.expected_semi_after_decl, false);
596 return var_decl;602 return var_decl;
597 }603 }
598 if (thread_local_token != null) {604 if (thread_local_token != null) {
...@@ -620,7 +626,7 @@ const Parser = struct {...@@ -620,7 +626,7 @@ const Parser = struct {
620 fn expectUsingNamespace(p: *Parser) !Node.Index {626 fn expectUsingNamespace(p: *Parser) !Node.Index {
621 const usingnamespace_token = p.assertToken(.keyword_usingnamespace);627 const usingnamespace_token = p.assertToken(.keyword_usingnamespace);
622 const expr = try p.expectExpr();628 const expr = try p.expectExpr();
623 _ = try p.expectToken(.semicolon);629 try p.expectSemicolon(.expected_semi_after_decl, false);
624 return p.addNode(.{630 return p.addNode(.{
625 .tag = .@"usingnamespace",631 .tag = .@"usingnamespace",
626 .main_token = usingnamespace_token,632 .main_token = usingnamespace_token,
...@@ -857,7 +863,7 @@ const Parser = struct {...@@ -857,7 +863,7 @@ const Parser = struct {
857863
858 const var_decl = try p.parseVarDecl();864 const var_decl = try p.parseVarDecl();
859 if (var_decl != 0) {865 if (var_decl != 0) {
860 _ = try p.expectTokenRecoverable(.semicolon);866 try p.expectSemicolon(.expected_semi_after_decl, true);
861 return var_decl;867 return var_decl;
862 }868 }
863869
...@@ -921,7 +927,7 @@ const Parser = struct {...@@ -921,7 +927,7 @@ const Parser = struct {
921927
922 const assign_expr = try p.parseAssignExpr();928 const assign_expr = try p.parseAssignExpr();
923 if (assign_expr != 0) {929 if (assign_expr != 0) {
924 _ = try p.expectTokenRecoverable(.semicolon);930 try p.expectSemicolon(.expected_semi_after_stmt, true);
925 return assign_expr;931 return assign_expr;
926 }932 }
927933
...@@ -990,7 +996,7 @@ const Parser = struct {...@@ -990,7 +996,7 @@ const Parser = struct {
990 };996 };
991 _ = p.eatToken(.keyword_else) orelse {997 _ = p.eatToken(.keyword_else) orelse {
992 if (else_required) {998 if (else_required) {
993 try p.warn(.expected_semi_or_else);999 try p.warnExpectedAfter(.expected_semi_or_else);
994 }1000 }
995 return p.addNode(.{1001 return p.addNode(.{
996 .tag = .if_simple,1002 .tag = .if_simple,
...@@ -1085,7 +1091,7 @@ const Parser = struct {...@@ -1085,7 +1091,7 @@ const Parser = struct {
1085 };1091 };
1086 _ = p.eatToken(.keyword_else) orelse {1092 _ = p.eatToken(.keyword_else) orelse {
1087 if (else_required) {1093 if (else_required) {
1088 try p.warn(.expected_semi_or_else);1094 try p.warnExpectedAfter(.expected_semi_or_else);
1089 }1095 }
1090 return p.addNode(.{1096 return p.addNode(.{
1091 .tag = .for_simple,1097 .tag = .for_simple,
...@@ -1160,7 +1166,7 @@ const Parser = struct {...@@ -1160,7 +1166,7 @@ const Parser = struct {
1160 };1166 };
1161 _ = p.eatToken(.keyword_else) orelse {1167 _ = p.eatToken(.keyword_else) orelse {
1162 if (else_required) {1168 if (else_required) {
1163 try p.warn(.expected_semi_or_else);1169 try p.warnExpectedAfter(.expected_semi_or_else);
1164 }1170 }
1165 if (cont_expr == 0) {1171 if (cont_expr == 0) {
1166 return p.addNode(.{1172 return p.addNode(.{
...@@ -1211,7 +1217,7 @@ const Parser = struct {...@@ -1211,7 +1217,7 @@ const Parser = struct {
1211 }1217 }
1212 const assign_expr = try p.parseAssignExpr();1218 const assign_expr = try p.parseAssignExpr();
1213 if (assign_expr != 0) {1219 if (assign_expr != 0) {
1214 _ = try p.expectTokenRecoverable(.semicolon);1220 try p.expectSemicolon(.expected_semi_after_stmt, true);
1215 return assign_expr;1221 return assign_expr;
1216 }1222 }
1217 return null_node;1223 return null_node;
...@@ -2044,7 +2050,7 @@ const Parser = struct {...@@ -2044,7 +2050,7 @@ const Parser = struct {
2044 },2050 },
2045 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2051 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2046 // Likely just a missing comma; give error but continue parsing.2052 // Likely just a missing comma; give error but continue parsing.
2047 else => try p.warnExpected(.comma),2053 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2048 }2054 }
2049 if (p.eatToken(.r_brace)) |_| break;2055 if (p.eatToken(.r_brace)) |_| break;
2050 const next = try p.expectFieldInit();2056 const next = try p.expectFieldInit();
...@@ -2085,7 +2091,7 @@ const Parser = struct {...@@ -2085,7 +2091,7 @@ const Parser = struct {
2085 },2091 },
2086 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2092 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2087 // Likely just a missing comma; give error but continue parsing.2093 // Likely just a missing comma; give error but continue parsing.
2088 else => try p.warnExpected(.comma),2094 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2089 }2095 }
2090 }2096 }
2091 const comma = (p.token_tags[p.tok_i - 2] == .comma);2097 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2164,7 +2170,7 @@ const Parser = struct {...@@ -2164,7 +2170,7 @@ const Parser = struct {
2164 },2170 },
2165 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),2171 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2166 // Likely just a missing comma; give error but continue parsing.2172 // Likely just a missing comma; give error but continue parsing.
2167 else => try p.warnExpected(.comma),2173 else => try p.warnExpectedAfter(.expected_comma_after_arg),
2168 }2174 }
2169 }2175 }
2170 const comma = (p.token_tags[p.tok_i - 2] == .comma);2176 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2220,7 +2226,7 @@ const Parser = struct {...@@ -2220,7 +2226,7 @@ const Parser = struct {
2220 },2226 },
2221 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),2227 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
2222 // Likely just a missing comma; give error but continue parsing.2228 // Likely just a missing comma; give error but continue parsing.
2223 else => try p.warnExpected(.comma),2229 else => try p.warnExpectedAfter(.expected_comma_after_arg),
2224 }2230 }
2225 }2231 }
2226 const comma = (p.token_tags[p.tok_i - 2] == .comma);2232 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2461,7 +2467,7 @@ const Parser = struct {...@@ -2461,7 +2467,7 @@ const Parser = struct {
2461 },2467 },
2462 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2468 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2463 // Likely just a missing comma; give error but continue parsing.2469 // Likely just a missing comma; give error but continue parsing.
2464 else => try p.warnExpected(.comma),2470 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2465 }2471 }
2466 if (p.eatToken(.r_brace)) |_| break;2472 if (p.eatToken(.r_brace)) |_| break;
2467 const next = try p.expectFieldInit();2473 const next = try p.expectFieldInit();
...@@ -2513,7 +2519,7 @@ const Parser = struct {...@@ -2513,7 +2519,7 @@ const Parser = struct {
2513 },2519 },
2514 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2520 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2515 // Likely just a missing comma; give error but continue parsing.2521 // Likely just a missing comma; give error but continue parsing.
2516 else => try p.warnExpected(.comma),2522 else => try p.warnExpectedAfter(.expected_comma_after_initializer),
2517 }2523 }
2518 }2524 }
2519 const comma = (p.token_tags[p.tok_i - 2] == .comma);2525 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -2574,7 +2580,7 @@ const Parser = struct {...@@ -2574,7 +2580,7 @@ const Parser = struct {
2574 },2580 },
2575 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),2581 .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
2576 // Likely just a missing comma; give error but continue parsing.2582 // Likely just a missing comma; give error but continue parsing.
2577 else => try p.warnExpected(.comma),2583 else => try p.warnExpectedAfter(.expected_comma_after_field),
2578 }2584 }
2579 }2585 }
2580 return p.addNode(.{2586 return p.addNode(.{
...@@ -3229,6 +3235,10 @@ const Parser = struct {...@@ -3229,6 +3235,10 @@ const Parser = struct {
3229 .rhs = p.nextToken(),3235 .rhs = p.nextToken(),
3230 },3236 },
3231 }),3237 }),
3238 .l_brace => {
3239 // this a misplaced `.{`, handle the error somewhere else
3240 return null_node;
3241 },
3232 else => {3242 else => {
3233 p.tok_i += 1;3243 p.tok_i += 1;
3234 try p.warn(.expected_suffix_op);3244 try p.warn(.expected_suffix_op);
...@@ -3389,7 +3399,24 @@ const Parser = struct {...@@ -3389,7 +3399,24 @@ const Parser = struct {
33893399
3390 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?3400 /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng?
3391 fn parseSwitchProngList(p: *Parser) !Node.SubRange {3401 fn parseSwitchProngList(p: *Parser) !Node.SubRange {
3392 return ListParseFn(parseSwitchProng)(p);3402 const scratch_top = p.scratch.items.len;
3403 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3404
3405 while (true) {
3406 const item = try parseSwitchProng(p);
3407 if (item == 0) break;
3408
3409 try p.scratch.append(p.gpa, item);
3410
3411 switch (p.token_tags[p.tok_i]) {
3412 .comma => p.tok_i += 1,
3413 // All possible delimiters.
3414 .colon, .r_paren, .r_brace, .r_bracket => break,
3415 // Likely just a missing comma; give error but continue parsing.
3416 else => try p.warnExpectedAfter(.expected_comma_after_switch_prong),
3417 }
3418 }
3419 return p.listToSpan(p.scratch.items[scratch_top..]);
3393 }3420 }
33943421
3395 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?3422 /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl?
...@@ -3415,7 +3442,7 @@ const Parser = struct {...@@ -3415,7 +3442,7 @@ const Parser = struct {
3415 },3442 },
3416 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),3443 .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
3417 // Likely just a missing comma; give error but continue parsing.3444 // Likely just a missing comma; give error but continue parsing.
3418 else => try p.warnExpected(.comma),3445 else => try p.warnExpectedAfter(.expected_comma_after_param),
3419 }3446 }
3420 }3447 }
3421 if (varargs == .nonfinal) {3448 if (varargs == .nonfinal) {
...@@ -3429,33 +3456,6 @@ const Parser = struct {...@@ -3429,33 +3456,6 @@ const Parser = struct {
3429 };3456 };
3430 }3457 }
34313458
3432 const NodeParseFn = fn (p: *Parser) Error!Node.Index;
3433
3434 fn ListParseFn(comptime nodeParseFn: anytype) (fn (p: *Parser) Error!Node.SubRange) {
3435 return struct {
3436 pub fn parse(p: *Parser) Error!Node.SubRange {
3437 const scratch_top = p.scratch.items.len;
3438 defer p.scratch.shrinkRetainingCapacity(scratch_top);
3439
3440 while (true) {
3441 const item = try nodeParseFn(p);
3442 if (item == 0) break;
3443
3444 try p.scratch.append(p.gpa, item);
3445
3446 switch (p.token_tags[p.tok_i]) {
3447 .comma => p.tok_i += 1,
3448 // All possible delimiters.
3449 .colon, .r_paren, .r_brace, .r_bracket => break,
3450 // Likely just a missing comma; give error but continue parsing.
3451 else => try p.warnExpected(.comma),
3452 }
3453 }
3454 return p.listToSpan(p.scratch.items[scratch_top..]);
3455 }
3456 }.parse;
3457 }
3458
3459 /// FnCallArguments <- LPAREN ExprList RPAREN3459 /// FnCallArguments <- LPAREN ExprList RPAREN
3460 /// ExprList <- (Expr COMMA)* Expr?3460 /// ExprList <- (Expr COMMA)* Expr?
3461 fn parseBuiltinCall(p: *Parser) !Node.Index {3461 fn parseBuiltinCall(p: *Parser) !Node.Index {
...@@ -3486,7 +3486,7 @@ const Parser = struct {...@@ -3486,7 +3486,7 @@ const Parser = struct {
3486 break;3486 break;
3487 },3487 },
3488 // Likely just a missing comma; give error but continue parsing.3488 // Likely just a missing comma; give error but continue parsing.
3489 else => try p.warnExpected(.comma),3489 else => try p.warnExpectedAfter(.expected_comma_after_arg),
3490 }3490 }
3491 }3491 }
3492 const comma = (p.token_tags[p.tok_i - 2] == .comma);3492 const comma = (p.token_tags[p.tok_i - 2] == .comma);
...@@ -3582,7 +3582,7 @@ const Parser = struct {...@@ -3582,7 +3582,7 @@ const Parser = struct {
3582 }3582 }
35833583
3584 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?3584 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?
3585 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !Node.Index {3585 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;3586 const if_token = p.eatToken(.keyword_if) orelse return null_node;
3587 _ = try p.expectToken(.l_paren);3587 _ = try p.expectToken(.l_paren);
3588 const condition = try p.expectExpr();3588 const condition = try p.expectExpr();
...@@ -3670,6 +3670,15 @@ const Parser = struct {...@@ -3670,6 +3670,15 @@ const Parser = struct {
3670 }3670 }
3671 }3671 }
36723672
3673 fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void {
3674 if (p.token_tags[p.tok_i] == .semicolon) {
3675 _ = p.nextToken();
3676 return;
3677 }
3678 try p.warnExpectedAfter(error_tag);
3679 if (!recoverable) return error.ParseError;
3680 }
3681
3673 fn nextToken(p: *Parser) TokenIndex {3682 fn nextToken(p: *Parser) TokenIndex {
3674 const result = p.tok_i;3683 const result = p.tok_i;
3675 p.tok_i += 1;3684 p.tok_i += 1;
src/Module.zig+2-1
...@@ -2995,13 +2995,14 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2995,13 +2995,14 @@ 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 try file.tree.renderError(parse_err, msg.writer());2999 try file.tree.renderError(parse_err, msg.writer());
2999 const err_msg = try gpa.create(ErrorMsg);3000 const err_msg = try gpa.create(ErrorMsg);
3000 err_msg.* = .{3001 err_msg.* = .{
3001 .src_loc = .{3002 .src_loc = .{
3002 .file_scope = file,3003 .file_scope = file,
3003 .parent_decl_node = 0,3004 .parent_decl_node = 0,
3004 .lazy = .{ .byte_abs = token_starts[parse_err.token] },3005 .lazy = .{ .byte_abs = token_starts[parse_err.token] + extra_offset },
3005 },3006 },
3006 .msg = msg.toOwnedSlice(),3007 .msg = msg.toOwnedSlice(),
3007 };3008 };
src/main.zig+3-2
...@@ -4040,13 +4040,14 @@ fn printErrMsgToStdErr(...@@ -4040,13 +4040,14 @@ fn printErrMsgToStdErr(
4040 notes_len += 1;4040 notes_len += 1;
4041 }4041 }
40424042
4043 const extra_offset = tree.errorOffset(parse_error.tag, parse_error.token);
4043 const message: Compilation.AllErrors.Message = .{4044 const message: Compilation.AllErrors.Message = .{
4044 .src = .{4045 .src = .{
4045 .src_path = path,4046 .src_path = path,
4046 .msg = text,4047 .msg = text,
4047 .byte_offset = @intCast(u32, start_loc.line_start),4048 .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset,
4048 .line = @intCast(u32, start_loc.line),4049 .line = @intCast(u32, start_loc.line),
4049 .column = @intCast(u32, start_loc.column),4050 .column = @intCast(u32, start_loc.column) + extra_offset,
4050 .source_line = source_line,4051 .source_line = source_line,
4051 .notes = notes_buffer[0..notes_len],4052 .notes = notes_buffer[0..notes_len],
4052 },4053 },
test/compile_errors.zig+22-22
...@@ -2171,7 +2171,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -2171,7 +2171,7 @@ pub fn addCases(ctx: *TestContext) !void {
2171 \\ _ = x;2171 \\ _ = x;
2172 \\}2172 \\}
2173 , &[_][]const u8{2173 , &[_][]const u8{
2174 "tmp.zig:3:7: error: expected ',', found 'align'",2174 "tmp.zig:3:6: error: expected ',' after field",
2175 });2175 });
21762176
2177 ctx.objErrStage1("bad alignment type",2177 ctx.objErrStage1("bad alignment type",
...@@ -4704,7 +4704,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4704,7 +4704,7 @@ pub fn addCases(ctx: *TestContext) !void {
4704 \\ var bad = {};4704 \\ var bad = {};
4705 \\}4705 \\}
4706 , &[_][]const u8{4706 , &[_][]const u8{
4707 "tmp.zig:5:5: error: expected ';', found 'var'",4707 "tmp.zig:4:9: error: expected ';' after statement",
4708 });4708 });
47094709
4710 ctx.objErrStage1("implicit semicolon - block expr",4710 ctx.objErrStage1("implicit semicolon - block expr",
...@@ -4715,7 +4715,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4715,7 +4715,7 @@ pub fn addCases(ctx: *TestContext) !void {
4715 \\ var bad = {};4715 \\ var bad = {};
4716 \\}4716 \\}
4717 , &[_][]const u8{4717 , &[_][]const u8{
4718 "tmp.zig:5:5: error: expected ';', found 'var'",4718 "tmp.zig:4:11: error: expected ';' after statement",
4719 });4719 });
47204720
4721 ctx.objErrStage1("implicit semicolon - comptime statement",4721 ctx.objErrStage1("implicit semicolon - comptime statement",
...@@ -4726,7 +4726,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4726,7 +4726,7 @@ pub fn addCases(ctx: *TestContext) !void {
4726 \\ var bad = {};4726 \\ var bad = {};
4727 \\}4727 \\}
4728 , &[_][]const u8{4728 , &[_][]const u8{
4729 "tmp.zig:5:5: error: expected ';', found 'var'",4729 "tmp.zig:4:18: error: expected ';' after statement",
4730 });4730 });
47314731
4732 ctx.objErrStage1("implicit semicolon - comptime expression",4732 ctx.objErrStage1("implicit semicolon - comptime expression",
...@@ -4737,7 +4737,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4737,7 +4737,7 @@ pub fn addCases(ctx: *TestContext) !void {
4737 \\ var bad = {};4737 \\ var bad = {};
4738 \\}4738 \\}
4739 , &[_][]const u8{4739 , &[_][]const u8{
4740 "tmp.zig:5:5: error: expected ';', found 'var'",4740 "tmp.zig:4:20: error: expected ';' after statement",
4741 });4741 });
47424742
4743 ctx.objErrStage1("implicit semicolon - defer",4743 ctx.objErrStage1("implicit semicolon - defer",
...@@ -4748,7 +4748,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4748,7 +4748,7 @@ pub fn addCases(ctx: *TestContext) !void {
4748 \\ var bad = {};4748 \\ var bad = {};
4749 \\}4749 \\}
4750 , &[_][]const u8{4750 , &[_][]const u8{
4751 "tmp.zig:5:5: error: expected ';', found 'var'",4751 "tmp.zig:4:15: error: expected ';' after statement",
4752 });4752 });
47534753
4754 ctx.objErrStage1("implicit semicolon - if statement",4754 ctx.objErrStage1("implicit semicolon - if statement",
...@@ -4759,7 +4759,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4759,7 +4759,7 @@ pub fn addCases(ctx: *TestContext) !void {
4759 \\ var bad = {};4759 \\ var bad = {};
4760 \\}4760 \\}
4761 , &[_][]const u8{4761 , &[_][]const u8{
4762 "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",4762 "tmp.zig:4:18: error: expected ';' or 'else' after statement",
4763 });4763 });
47644764
4765 ctx.objErrStage1("implicit semicolon - if expression",4765 ctx.objErrStage1("implicit semicolon - if expression",
...@@ -4770,7 +4770,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4770,7 +4770,7 @@ pub fn addCases(ctx: *TestContext) !void {
4770 \\ var bad = {};4770 \\ var bad = {};
4771 \\}4771 \\}
4772 , &[_][]const u8{4772 , &[_][]const u8{
4773 "tmp.zig:5:5: error: expected ';', found 'var'",4773 "tmp.zig:4:20: error: expected ';' after statement",
4774 });4774 });
47754775
4776 ctx.objErrStage1("implicit semicolon - if-else statement",4776 ctx.objErrStage1("implicit semicolon - if-else statement",
...@@ -4781,7 +4781,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4781,7 +4781,7 @@ pub fn addCases(ctx: *TestContext) !void {
4781 \\ var bad = {};4781 \\ var bad = {};
4782 \\}4782 \\}
4783 , &[_][]const u8{4783 , &[_][]const u8{
4784 "tmp.zig:5:5: error: expected ';', found 'var'",4784 "tmp.zig:4:28: error: expected ';' after statement",
4785 });4785 });
47864786
4787 ctx.objErrStage1("implicit semicolon - if-else expression",4787 ctx.objErrStage1("implicit semicolon - if-else expression",
...@@ -4792,7 +4792,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4792,7 +4792,7 @@ pub fn addCases(ctx: *TestContext) !void {
4792 \\ var bad = {};4792 \\ var bad = {};
4793 \\}4793 \\}
4794 , &[_][]const u8{4794 , &[_][]const u8{
4795 "tmp.zig:5:5: error: expected ';', found 'var'",4795 "tmp.zig:4:28: error: expected ';' after statement",
4796 });4796 });
47974797
4798 ctx.objErrStage1("implicit semicolon - if-else-if statement",4798 ctx.objErrStage1("implicit semicolon - if-else-if statement",
...@@ -4803,7 +4803,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4803,7 +4803,7 @@ pub fn addCases(ctx: *TestContext) !void {
4803 \\ var bad = {};4803 \\ var bad = {};
4804 \\}4804 \\}
4805 , &[_][]const u8{4805 , &[_][]const u8{
4806 "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",4806 "tmp.zig:4:37: error: expected ';' or 'else' after statement",
4807 });4807 });
48084808
4809 ctx.objErrStage1("implicit semicolon - if-else-if expression",4809 ctx.objErrStage1("implicit semicolon - if-else-if expression",
...@@ -4814,7 +4814,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4814,7 +4814,7 @@ pub fn addCases(ctx: *TestContext) !void {
4814 \\ var bad = {};4814 \\ var bad = {};
4815 \\}4815 \\}
4816 , &[_][]const u8{4816 , &[_][]const u8{
4817 "tmp.zig:5:5: error: expected ';', found 'var'",4817 "tmp.zig:4:37: error: expected ';' after statement",
4818 });4818 });
48194819
4820 ctx.objErrStage1("implicit semicolon - if-else-if-else statement",4820 ctx.objErrStage1("implicit semicolon - if-else-if-else statement",
...@@ -4825,7 +4825,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4825,7 +4825,7 @@ pub fn addCases(ctx: *TestContext) !void {
4825 \\ var bad = {};4825 \\ var bad = {};
4826 \\}4826 \\}
4827 , &[_][]const u8{4827 , &[_][]const u8{
4828 "tmp.zig:5:5: error: expected ';', found 'var'",4828 "tmp.zig:4:47: error: expected ';' after statement",
4829 });4829 });
48304830
4831 ctx.objErrStage1("implicit semicolon - if-else-if-else expression",4831 ctx.objErrStage1("implicit semicolon - if-else-if-else expression",
...@@ -4836,7 +4836,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4836,7 +4836,7 @@ pub fn addCases(ctx: *TestContext) !void {
4836 \\ var bad = {};4836 \\ var bad = {};
4837 \\}4837 \\}
4838 , &[_][]const u8{4838 , &[_][]const u8{
4839 "tmp.zig:5:5: error: expected ';', found 'var'",4839 "tmp.zig:4:45: error: expected ';' after statement",
4840 });4840 });
48414841
4842 ctx.objErrStage1("implicit semicolon - test statement",4842 ctx.objErrStage1("implicit semicolon - test statement",
...@@ -4847,7 +4847,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4847,7 +4847,7 @@ pub fn addCases(ctx: *TestContext) !void {
4847 \\ var bad = {};4847 \\ var bad = {};
4848 \\}4848 \\}
4849 , &[_][]const u8{4849 , &[_][]const u8{
4850 "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",4850 "tmp.zig:4:24: error: expected ';' or 'else' after statement",
4851 });4851 });
48524852
4853 ctx.objErrStage1("implicit semicolon - test expression",4853 ctx.objErrStage1("implicit semicolon - test expression",
...@@ -4858,7 +4858,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4858,7 +4858,7 @@ pub fn addCases(ctx: *TestContext) !void {
4858 \\ var bad = {};4858 \\ var bad = {};
4859 \\}4859 \\}
4860 , &[_][]const u8{4860 , &[_][]const u8{
4861 "tmp.zig:5:5: error: expected ';', found 'var'",4861 "tmp.zig:4:26: error: expected ';' after statement",
4862 });4862 });
48634863
4864 ctx.objErrStage1("implicit semicolon - while statement",4864 ctx.objErrStage1("implicit semicolon - while statement",
...@@ -4869,7 +4869,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4869,7 +4869,7 @@ pub fn addCases(ctx: *TestContext) !void {
4869 \\ var bad = {};4869 \\ var bad = {};
4870 \\}4870 \\}
4871 , &[_][]const u8{4871 , &[_][]const u8{
4872 "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",4872 "tmp.zig:4:21: error: expected ';' or 'else' after statement",
4873 });4873 });
48744874
4875 ctx.objErrStage1("implicit semicolon - while expression",4875 ctx.objErrStage1("implicit semicolon - while expression",
...@@ -4880,7 +4880,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4880,7 +4880,7 @@ pub fn addCases(ctx: *TestContext) !void {
4880 \\ var bad = {};4880 \\ var bad = {};
4881 \\}4881 \\}
4882 , &[_][]const u8{4882 , &[_][]const u8{
4883 "tmp.zig:5:5: error: expected ';', found 'var'",4883 "tmp.zig:4:23: error: expected ';' after statement",
4884 });4884 });
48854885
4886 ctx.objErrStage1("implicit semicolon - while-continue statement",4886 ctx.objErrStage1("implicit semicolon - while-continue statement",
...@@ -4891,7 +4891,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4891,7 +4891,7 @@ pub fn addCases(ctx: *TestContext) !void {
4891 \\ var bad = {};4891 \\ var bad = {};
4892 \\}4892 \\}
4893 , &[_][]const u8{4893 , &[_][]const u8{
4894 "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",4894 "tmp.zig:4:26: error: expected ';' or 'else' after statement",
4895 });4895 });
48964896
4897 ctx.objErrStage1("implicit semicolon - while-continue expression",4897 ctx.objErrStage1("implicit semicolon - while-continue expression",
...@@ -4902,7 +4902,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4902,7 +4902,7 @@ pub fn addCases(ctx: *TestContext) !void {
4902 \\ var bad = {};4902 \\ var bad = {};
4903 \\}4903 \\}
4904 , &[_][]const u8{4904 , &[_][]const u8{
4905 "tmp.zig:5:5: error: expected ';', found 'var'",4905 "tmp.zig:4:28: error: expected ';' after statement",
4906 });4906 });
49074907
4908 ctx.objErrStage1("implicit semicolon - for statement",4908 ctx.objErrStage1("implicit semicolon - for statement",
...@@ -4913,7 +4913,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4913,7 +4913,7 @@ pub fn addCases(ctx: *TestContext) !void {
4913 \\ var bad = {};4913 \\ var bad = {};
4914 \\}4914 \\}
4915 , &[_][]const u8{4915 , &[_][]const u8{
4916 "tmp.zig:5:5: error: expected ';' or 'else', found 'var'",4916 "tmp.zig:4:24: error: expected ';' or 'else' after statement",
4917 });4917 });
49184918
4919 ctx.objErrStage1("implicit semicolon - for expression",4919 ctx.objErrStage1("implicit semicolon - for expression",
...@@ -4924,7 +4924,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -4924,7 +4924,7 @@ pub fn addCases(ctx: *TestContext) !void {
4924 \\ var bad = {};4924 \\ var bad = {};
4925 \\}4925 \\}
4926 , &[_][]const u8{4926 , &[_][]const u8{
4927 "tmp.zig:5:5: error: expected ';', found 'var'",4927 "tmp.zig:4:26: error: expected ';' after statement",
4928 });4928 });
49294929
4930 ctx.objErrStage1("multiple function definitions",4930 ctx.objErrStage1("multiple function definitions",
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:7: error: expected ',', found 'align'",696 ":3:6: error: expected ',' after field",
697 });697 });
698698
699 // Redundant non-exhaustive enum mark.699 // Redundant non-exhaustive enum mark.