commit 53241f288e40a9e97a5425cb0e1ac7dbbc9de852 (tree)
parent 56e9575e827208b3df5c90472826f52bfc8342c0
Author: Veikka Tuominen <git@vexu.eu>
Date: Fri, 18 Feb 2022 13:53:47 +0200
Merge pull request #10913 from Vexu/err
further parser error improvements
Diffstat:
10 files changed, 353 insertions(+), 254 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
@@ -10405,7 +10405,7 @@ pub fn main() !void {
<p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.
This is why it is an error to pass a string literal to a mutable slice, like this:
</p>
- {#code_begin|test_err|expected type '[]u8'#}
+ {#code_begin|test_err|cannot cast pointer to array literal to slice type '[]u8'#}
fn foo(s: []u8) void {
_ = s;
}
diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig
@@ -66,20 +66,11 @@ pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void
/// Returns an extra offset for column and byte offset of errors that
/// should point after the token in the error message.
-pub fn errorOffset(tree: Ast, error_tag: Error.Tag, token: TokenIndex) u32 {
- return switch (error_tag) {
- .expected_semi_after_decl,
- .expected_semi_after_stmt,
- .expected_comma_after_field,
- .expected_comma_after_arg,
- .expected_comma_after_param,
- .expected_comma_after_initializer,
- .expected_comma_after_switch_prong,
- .expected_semi_or_else,
- .expected_semi_or_lbrace,
- => @intCast(u32, tree.tokenSlice(token).len),
- else => 0,
- };
+pub fn errorOffset(tree: Ast, parse_error: Error) u32 {
+ return if (parse_error.token_is_prev)
+ @intCast(u32, tree.tokenSlice(parse_error.token).len)
+ else
+ 0;
}
pub 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 {
},
.expected_block => {
return stream.print("expected block or field, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_block_or_assignment => {
return stream.print("expected block or assignment, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_block_or_expr => {
return stream.print("expected block or expression, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_block_or_field => {
return stream.print("expected block or field, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_container_members => {
@@ -187,42 +178,42 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
},
.expected_expr => {
return stream.print("expected expression, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_expr_or_assignment => {
return stream.print("expected expression or assignment, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_fn => {
return stream.print("expected function, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_inlinable => {
return stream.print("expected 'while' or 'for', found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_labelable => {
return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_param_list => {
return stream.print("expected parameter list, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_prefix_expr => {
return stream.print("expected prefix expression, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_primary_type_expr => {
return stream.print("expected primary type expression, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_pub_item => {
@@ -230,7 +221,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
},
.expected_return_type => {
return stream.print("expected return type expression, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_semi_or_else => {
@@ -244,39 +235,34 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
token_tags[parse_error.token].symbol(),
});
},
- .expected_string_literal => {
- return stream.print("expected string literal, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
- });
- },
.expected_suffix_op => {
return stream.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_type_expr => {
return stream.print("expected type expression, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_var_decl => {
return stream.print("expected variable declaration, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_var_decl_or_fn => {
return stream.print("expected variable declaration or function, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_loop_payload => {
return stream.print("expected loop payload, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.expected_container => {
return stream.print("expected a struct, enum or union, found '{s}'", .{
- token_tags[parse_error.token].symbol(),
+ token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
});
},
.extern_fn_body => {
@@ -305,11 +291,6 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
.invalid_bit_range => {
return stream.writeAll("bit range not allowed on slices and arrays");
},
- .invalid_token => {
- return stream.print("invalid token: '{s}'", .{
- token_tags[parse_error.token].symbol(),
- });
- },
.same_line_doc_comment => {
return stream.writeAll("same line documentation comment");
},
@@ -319,6 +300,9 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
.varargs_nonfinal => {
return stream.writeAll("function prototype has parameter after varargs");
},
+ .expected_continue_expr => {
+ return stream.writeAll("expected ':' before while continue expression");
+ },
.expected_semi_after_decl => {
return stream.writeAll("expected ';' after declaration");
@@ -341,9 +325,19 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
.expected_comma_after_switch_prong => {
return stream.writeAll("expected ',' after switch prong");
},
+ .expected_initializer => {
+ return stream.writeAll("expected field initializer");
+ },
+
+ .previous_field => {
+ return stream.writeAll("field before declarations here");
+ },
+ .next_field => {
+ return stream.writeAll("field after declarations here");
+ },
.expected_token => {
- const found_tag = token_tags[parse_error.token];
+ const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)];
const expected_symbol = parse_error.extra.expected_tag.symbol();
switch (found_tag) {
.invalid => return stream.print("expected '{s}', found invalid bytes", .{
@@ -2483,6 +2477,9 @@ pub const full = struct {
pub const Error = struct {
tag: Tag,
+ is_note: bool = false,
+ /// True if `token` points to the token before the token causing an issue.
+ token_is_prev: bool = false,
token: TokenIndex,
extra: union {
none: void,
@@ -2511,7 +2508,6 @@ pub const Error = struct {
expected_semi_or_else,
expected_semi_or_lbrace,
expected_statement,
- expected_string_literal,
expected_suffix_op,
expected_type_expr,
expected_var_decl,
@@ -2526,12 +2522,10 @@ pub const Error = struct {
extra_volatile_qualifier,
ptr_mod_on_array_child_type,
invalid_bit_range,
- invalid_token,
same_line_doc_comment,
unattached_doc_comment,
varargs_nonfinal,
-
- // these have `token` set to token after which a semicolon was expected
+ expected_continue_expr,
expected_semi_after_decl,
expected_semi_after_stmt,
expected_comma_after_field,
@@ -2539,6 +2533,10 @@ pub const Error = struct {
expected_comma_after_param,
expected_comma_after_initializer,
expected_comma_after_switch_prong,
+ expected_initializer,
+
+ previous_field,
+ next_field,
/// `expected_tag` is populated.
expected_token,
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
@@ -91,6 +91,9 @@ const Parser = struct {
extra_data: std.ArrayListUnmanaged(Node.Index),
scratch: std.ArrayListUnmanaged(Node.Index),
+ /// Used for the error note of decl_between_fields error.
+ last_field: TokenIndex = undefined,
+
const SmallSpan = union(enum) {
zero_or_one: Node.Index,
multi: Node.SubRange,
@@ -147,11 +150,6 @@ const Parser = struct {
return result;
}
- fn warn(p: *Parser, tag: Ast.Error.Tag) error{OutOfMemory}!void {
- @setCold(true);
- try p.warnMsg(.{ .tag = tag, .token = p.tok_i });
- }
-
fn warnExpected(p: *Parser, expected_token: Token.Tag) error{OutOfMemory}!void {
@setCold(true);
try p.warnMsg(.{
@@ -161,13 +159,53 @@ const Parser = struct {
});
}
- fn warnExpectedAfter(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void {
+ fn warn(p: *Parser, error_tag: AstError.Tag) error{OutOfMemory}!void {
@setCold(true);
- try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i - 1 });
+ try p.warnMsg(.{ .tag = error_tag, .token = p.tok_i });
}
fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void {
@setCold(true);
+ switch (msg.tag) {
+ .expected_semi_after_decl,
+ .expected_semi_after_stmt,
+ .expected_comma_after_field,
+ .expected_comma_after_arg,
+ .expected_comma_after_param,
+ .expected_comma_after_initializer,
+ .expected_comma_after_switch_prong,
+ .expected_semi_or_else,
+ .expected_semi_or_lbrace,
+ .expected_token,
+ .expected_block,
+ .expected_block_or_assignment,
+ .expected_block_or_expr,
+ .expected_block_or_field,
+ .expected_container_members,
+ .expected_expr,
+ .expected_expr_or_assignment,
+ .expected_fn,
+ .expected_inlinable,
+ .expected_labelable,
+ .expected_param_list,
+ .expected_prefix_expr,
+ .expected_primary_type_expr,
+ .expected_pub_item,
+ .expected_return_type,
+ .expected_suffix_op,
+ .expected_type_expr,
+ .expected_var_decl,
+ .expected_var_decl_or_fn,
+ .expected_loop_payload,
+ .expected_container,
+ => if (msg.token != 0 and !p.tokensOnSameLine(msg.token - 1, msg.token)) {
+ var copy = msg;
+ copy.token_is_prev = true;
+ copy.token -= 1;
+ return p.errors.append(p.gpa, copy);
+ },
+ else => {},
+ }
try p.errors.append(p.gpa, msg);
}
@@ -235,6 +273,8 @@ const Parser = struct {
.keyword_comptime => switch (p.token_tags[p.tok_i + 1]) {
.identifier => {
p.tok_i += 1;
+ const identifier = p.tok_i;
+ defer p.last_field = identifier;
const container_field = try p.expectContainerFieldRecoverable();
if (container_field != 0) {
switch (field_state) {
@@ -245,6 +285,16 @@ const Parser = struct {
.tag = .decl_between_fields,
.token = p.nodes.items(.main_token)[node],
});
+ try p.warnMsg(.{
+ .tag = .previous_field,
+ .is_note = true,
+ .token = p.last_field,
+ });
+ try p.warnMsg(.{
+ .tag = .next_field,
+ .is_note = true,
+ .token = identifier,
+ });
// Continue parsing; error will be reported later.
field_state = .err;
},
@@ -264,7 +314,7 @@ const Parser = struct {
}
// There is not allowed to be a decl after a field with no comma.
// Report error but recover parser.
- try p.warnExpectedAfter(.expected_comma_after_field);
+ try p.warn(.expected_comma_after_field);
p.findNextContainerMember();
}
},
@@ -338,6 +388,8 @@ const Parser = struct {
trailing = p.token_tags[p.tok_i - 1] == .semicolon;
},
.identifier => {
+ const identifier = p.tok_i;
+ defer p.last_field = identifier;
const container_field = try p.expectContainerFieldRecoverable();
if (container_field != 0) {
switch (field_state) {
@@ -348,6 +400,14 @@ const Parser = struct {
.tag = .decl_between_fields,
.token = p.nodes.items(.main_token)[node],
});
+ try p.warnMsg(.{
+ .tag = .previous_field,
+ .token = p.last_field,
+ });
+ try p.warnMsg(.{
+ .tag = .next_field,
+ .token = identifier,
+ });
// Continue parsing; error will be reported later.
field_state = .err;
},
@@ -367,7 +427,7 @@ const Parser = struct {
}
// There is not allowed to be a decl after a field with no comma.
// Report error but recover parser.
- try p.warnExpectedAfter(.expected_comma_after_field);
+ try p.warn(.expected_comma_after_field);
p.findNextContainerMember();
}
},
@@ -585,7 +645,7 @@ const Parser = struct {
// Since parseBlock only return error.ParseError on
// a missing '}' we can assume this function was
// supposed to end here.
- try p.warnExpectedAfter(.expected_semi_or_lbrace);
+ try p.warn(.expected_semi_or_lbrace);
return null_node;
},
}
@@ -996,7 +1056,7 @@ const Parser = struct {
};
_ = p.eatToken(.keyword_else) orelse {
if (else_required) {
- try p.warnExpectedAfter(.expected_semi_or_else);
+ try p.warn(.expected_semi_or_else);
}
return p.addNode(.{
.tag = .if_simple,
@@ -1091,7 +1151,7 @@ const Parser = struct {
};
_ = p.eatToken(.keyword_else) orelse {
if (else_required) {
- try p.warnExpectedAfter(.expected_semi_or_else);
+ try p.warn(.expected_semi_or_else);
}
return p.addNode(.{
.tag = .for_simple,
@@ -1166,7 +1226,7 @@ const Parser = struct {
};
_ = p.eatToken(.keyword_else) orelse {
if (else_required) {
- try p.warnExpectedAfter(.expected_semi_or_else);
+ try p.warn(.expected_semi_or_else);
}
if (cont_expr == 0) {
return p.addNode(.{
@@ -1402,7 +1462,8 @@ const Parser = struct {
}
const rhs = try p.parseExprPrecedence(info.prec + 1);
if (rhs == 0) {
- return p.fail(.invalid_token);
+ try p.warn(.expected_expr);
+ return node;
}
node = try p.addNode(.{
@@ -1881,7 +1942,7 @@ const Parser = struct {
/// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)?
fn parseIfExpr(p: *Parser) !Node.Index {
- return p.parseIf(parseExpr);
+ return p.parseIf(expectExpr);
}
/// Block <- LBRACE Statement* RBRACE
@@ -2050,7 +2111,7 @@ const Parser = struct {
},
.colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_initializer),
+ else => try p.warn(.expected_comma_after_initializer),
}
if (p.eatToken(.r_brace)) |_| break;
const next = try p.expectFieldInit();
@@ -2091,7 +2152,7 @@ const Parser = struct {
},
.colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_initializer),
+ else => try p.warn(.expected_comma_after_initializer),
}
}
const comma = (p.token_tags[p.tok_i - 2] == .comma);
@@ -2170,7 +2231,7 @@ const Parser = struct {
},
.colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_arg),
+ else => try p.warn(.expected_comma_after_arg),
}
}
const comma = (p.token_tags[p.tok_i - 2] == .comma);
@@ -2226,7 +2287,7 @@ const Parser = struct {
},
.colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_arg),
+ else => try p.warn(.expected_comma_after_arg),
}
}
const comma = (p.token_tags[p.tok_i - 2] == .comma);
@@ -2349,7 +2410,7 @@ const Parser = struct {
.builtin => return p.parseBuiltinCall(),
.keyword_fn => return p.parseFnProto(),
- .keyword_if => return p.parseIf(parseTypeExpr),
+ .keyword_if => return p.parseIf(expectTypeExpr),
.keyword_switch => return p.expectSwitchExpr(),
.keyword_extern,
@@ -2467,7 +2528,7 @@ const Parser = struct {
},
.colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_initializer),
+ else => try p.warn(.expected_comma_after_initializer),
}
if (p.eatToken(.r_brace)) |_| break;
const next = try p.expectFieldInit();
@@ -2519,7 +2580,7 @@ const Parser = struct {
},
.colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_initializer),
+ else => try p.warn(.expected_comma_after_initializer),
}
}
const comma = (p.token_tags[p.tok_i - 2] == .comma);
@@ -2580,7 +2641,7 @@ const Parser = struct {
},
.colon, .r_paren, .r_bracket => return p.failExpected(.r_brace),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_field),
+ else => try p.warn(.expected_comma_after_field),
}
}
return p.addNode(.{
@@ -2879,7 +2940,7 @@ const Parser = struct {
p.tok_i += 2;
return identifier;
}
- return 0;
+ return null_node;
}
/// FieldInit <- DOT IDENTIFIER EQUAL Expr
@@ -2896,15 +2957,23 @@ const Parser = struct {
}
fn expectFieldInit(p: *Parser) !Node.Index {
- _ = try p.expectToken(.period);
- _ = try p.expectToken(.identifier);
- _ = try p.expectToken(.equal);
+ if (p.token_tags[p.tok_i] != .period or
+ p.token_tags[p.tok_i + 1] != .identifier or
+ p.token_tags[p.tok_i + 2] != .equal)
+ return p.fail(.expected_initializer);
+
+ p.tok_i += 3;
return p.expectExpr();
}
/// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN
fn parseWhileContinueExpr(p: *Parser) !Node.Index {
- _ = p.eatToken(.colon) orelse return null_node;
+ _ = p.eatToken(.colon) orelse {
+ if (p.token_tags[p.tok_i] == .l_paren and
+ p.tokensOnSameLine(p.tok_i - 1, p.tok_i))
+ return p.fail(.expected_continue_expr);
+ return null_node;
+ };
_ = try p.expectToken(.l_paren);
const node = try p.parseAssignExpr();
if (node == 0) return p.fail(.expected_expr_or_assignment);
@@ -3413,7 +3482,7 @@ const Parser = struct {
// All possible delimiters.
.colon, .r_paren, .r_brace, .r_bracket => break,
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_switch_prong),
+ else => try p.warn(.expected_comma_after_switch_prong),
}
}
return p.listToSpan(p.scratch.items[scratch_top..]);
@@ -3442,7 +3511,7 @@ const Parser = struct {
},
.colon, .r_brace, .r_bracket => return p.failExpected(.r_paren),
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_param),
+ else => try p.warn(.expected_comma_after_param),
}
}
if (varargs == .nonfinal) {
@@ -3486,7 +3555,7 @@ const Parser = struct {
break;
},
// Likely just a missing comma; give error but continue parsing.
- else => try p.warnExpectedAfter(.expected_comma_after_arg),
+ else => try p.warn(.expected_comma_after_arg),
}
}
const comma = (p.token_tags[p.tok_i - 2] == .comma);
@@ -3530,57 +3599,6 @@ const Parser = struct {
}
}
- // string literal or multiline string literal
- fn parseStringLiteral(p: *Parser) !Node.Index {
- switch (p.token_tags[p.tok_i]) {
- .string_literal => {
- const main_token = p.nextToken();
- return p.addNode(.{
- .tag = .string_literal,
- .main_token = main_token,
- .data = .{
- .lhs = undefined,
- .rhs = undefined,
- },
- });
- },
- .multiline_string_literal_line => {
- const first_line = p.nextToken();
- while (p.token_tags[p.tok_i] == .multiline_string_literal_line) {
- p.tok_i += 1;
- }
- return p.addNode(.{
- .tag = .multiline_string_literal,
- .main_token = first_line,
- .data = .{
- .lhs = first_line,
- .rhs = p.tok_i - 1,
- },
- });
- },
- else => return null_node,
- }
- }
-
- fn expectStringLiteral(p: *Parser) !Node.Index {
- const node = try p.parseStringLiteral();
- if (node == 0) {
- return p.fail(.expected_string_literal);
- }
- return node;
- }
-
- fn expectIntegerLiteral(p: *Parser) !Node.Index {
- return p.addNode(.{
- .tag = .integer_literal,
- .main_token = try p.expectToken(.integer_literal),
- .data = .{
- .lhs = undefined,
- .rhs = undefined,
- },
- });
- }
-
/// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?
fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {
const if_token = p.eatToken(.keyword_if) orelse return null_node;
@@ -3590,7 +3608,7 @@ const Parser = struct {
_ = try p.parsePtrPayload();
const then_expr = try bodyParseFn(p);
- if (then_expr == 0) return p.fail(.invalid_token);
+ assert(then_expr != 0);
_ = p.eatToken(.keyword_else) orelse return p.addNode(.{
.tag = .if_simple,
@@ -3602,7 +3620,7 @@ const Parser = struct {
});
_ = try p.parsePayload();
const else_expr = try bodyParseFn(p);
- if (else_expr == 0) return p.fail(.invalid_token);
+ assert(then_expr != 0);
return p.addNode(.{
.tag = .@"if",
@@ -3649,25 +3667,14 @@ const Parser = struct {
}
fn expectToken(p: *Parser, tag: Token.Tag) Error!TokenIndex {
- const token = p.nextToken();
- if (p.token_tags[token] != tag) {
- p.tok_i -= 1; // Go back so that we can recover properly.
+ if (p.token_tags[p.tok_i] != tag) {
return p.failMsg(.{
.tag = .expected_token,
- .token = token,
+ .token = p.tok_i,
.extra = .{ .expected_tag = tag },
});
}
- return token;
- }
-
- fn expectTokenRecoverable(p: *Parser, tag: Token.Tag) !?TokenIndex {
- if (p.token_tags[p.tok_i] != tag) {
- try p.warnExpected(tag);
- return null;
- } else {
- return p.nextToken();
- }
+ return p.nextToken();
}
fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void {
@@ -3675,7 +3682,7 @@ const Parser = struct {
_ = p.nextToken();
return;
}
- try p.warnExpectedAfter(error_tag);
+ try p.warn(error_tag);
if (!recoverable) return error.ParseError;
}
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
@@ -226,6 +226,8 @@ test "zig fmt: decl between fields" {
\\};
, &[_]Error{
.decl_between_fields,
+ .previous_field,
+ .next_field,
});
}
@@ -5018,6 +5020,25 @@ test "zig fmt: make single-line if no trailing comma" {
);
}
+test "zig fmt: while continue expr" {
+ try testCanonical(
+ \\test {
+ \\ while (i > 0)
+ \\ (i * 2);
+ \\}
+ \\
+ );
+ try testError(
+ \\test {
+ \\ while (i > 0) (i -= 1) {
+ \\ print("test123", .{});
+ \\ }
+ \\}
+ , &[_]Error{
+ .expected_continue_expr,
+ });
+}
+
test "zig fmt: error for invalid bit range" {
try testError(
\\var x: []align(0:0:0)u8 = bar;
@@ -5057,7 +5078,9 @@ test "recovery: block statements" {
\\ inline;
\\}
, &[_]Error{
- .invalid_token,
+ .expected_expr,
+ .expected_semi_after_stmt,
+ .expected_statement,
.expected_inlinable,
});
}
@@ -5076,7 +5099,7 @@ test "recovery: missing comma" {
, &[_]Error{
.expected_comma_after_switch_prong,
.expected_comma_after_switch_prong,
- .invalid_token,
+ .expected_expr,
});
}
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
@@ -322,7 +322,18 @@ pub const Token = struct {
}
pub fn symbol(tag: Tag) []const u8 {
- return tag.lexeme() orelse @tagName(tag);
+ return tag.lexeme() orelse switch (tag) {
+ .invalid => "invalid bytes",
+ .identifier => "an identifier",
+ .string_literal, .multiline_string_literal_line => "a string literal",
+ .char_literal => "a character literal",
+ .eof => "EOF",
+ .builtin => "a builtin function",
+ .integer_literal => "an integer literal",
+ .float_literal => "a floating point literal",
+ .doc_comment, .container_doc_comment => "a document comment",
+ else => unreachable,
+ };
}
};
};
diff --git a/src/Module.zig b/src/Module.zig
@@ -2995,7 +2995,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
const token_starts = file.tree.tokens.items(.start);
const token_tags = file.tree.tokens.items(.tag);
- const extra_offset = file.tree.errorOffset(parse_err.tag, parse_err.token);
+ const extra_offset = file.tree.errorOffset(parse_err);
try file.tree.renderError(parse_err, msg.writer());
const err_msg = try gpa.create(ErrorMsg);
err_msg.* = .{
@@ -3006,14 +3006,25 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
},
.msg = msg.toOwnedSlice(),
};
- if (token_tags[parse_err.token] == .invalid) {
- const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token).len);
- const byte_abs = token_starts[parse_err.token] + bad_off;
+ if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
+ const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
+ const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
try mod.errNoteNonLazy(.{
.file_scope = file,
.parent_decl_node = 0,
.lazy = .{ .byte_abs = byte_abs },
}, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
+ } else if (parse_err.tag == .decl_between_fields) {
+ try mod.errNoteNonLazy(.{
+ .file_scope = file,
+ .parent_decl_node = 0,
+ .lazy = .{ .byte_abs = token_starts[file.tree.errors[1].token] },
+ }, err_msg, "field before declarations here", .{});
+ try mod.errNoteNonLazy(.{
+ .file_scope = file,
+ .parent_decl_node = 0,
+ .lazy = .{ .byte_abs = token_starts[file.tree.errors[2].token] },
+ }, err_msg, "field after declarations here", .{});
}
{
diff --git a/src/main.zig b/src/main.zig
@@ -3799,9 +3799,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
};
defer tree.deinit(gpa);
- for (tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, arena, parse_error, tree, "<stdin>", color);
- }
+ try printErrsMsgToStdErr(gpa, arena, tree.errors, tree, "<stdin>", color);
var has_ast_error = false;
if (check_ast_flag) {
const Module = @import("Module.zig");
@@ -3989,9 +3987,7 @@ fn fmtPathFile(
var tree = try std.zig.parse(fmt.gpa, source_code);
defer tree.deinit(fmt.gpa);
- for (tree.errors) |parse_error| {
- try printErrMsgToStdErr(fmt.gpa, fmt.arena, parse_error, tree, file_path, fmt.color);
- }
+ try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree.errors, tree, file_path, fmt.color);
if (tree.errors.len != 0) {
fmt.any_error = true;
return;
@@ -4071,66 +4067,95 @@ fn fmtPathFile(
}
}
-fn printErrMsgToStdErr(
+fn printErrsMsgToStdErr(
gpa: mem.Allocator,
arena: mem.Allocator,
- parse_error: Ast.Error,
+ parse_errors: []const Ast.Error,
tree: Ast,
path: []const u8,
color: Color,
) !void {
- const lok_token = parse_error.token;
- const token_tags = tree.tokens.items(.tag);
- const start_loc = tree.tokenLocation(0, lok_token);
- const source_line = tree.source[start_loc.line_start..start_loc.line_end];
-
- var text_buf = std.ArrayList(u8).init(gpa);
- defer text_buf.deinit();
- const writer = text_buf.writer();
- try tree.renderError(parse_error, writer);
- const text = text_buf.items;
-
- var notes_buffer: [1]Compilation.AllErrors.Message = undefined;
- var notes_len: usize = 0;
-
- if (token_tags[parse_error.token] == .invalid) {
- const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token).len);
- const byte_offset = @intCast(u32, start_loc.line_start) + bad_off;
- notes_buffer[notes_len] = .{
+ var i: usize = 0;
+ while (i < parse_errors.len) : (i += 1) {
+ const parse_error = parse_errors[i];
+ const lok_token = parse_error.token;
+ const token_tags = tree.tokens.items(.tag);
+ const start_loc = tree.tokenLocation(0, lok_token);
+ const source_line = tree.source[start_loc.line_start..start_loc.line_end];
+
+ var text_buf = std.ArrayList(u8).init(gpa);
+ defer text_buf.deinit();
+ const writer = text_buf.writer();
+ try tree.renderError(parse_error, writer);
+ const text = text_buf.items;
+
+ var notes_buffer: [2]Compilation.AllErrors.Message = undefined;
+ var notes_len: usize = 0;
+
+ if (token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)] == .invalid) {
+ const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token + @boolToInt(parse_error.token_is_prev)).len);
+ const byte_offset = @intCast(u32, start_loc.line_start) + @intCast(u32, start_loc.column) + bad_off;
+ notes_buffer[notes_len] = .{
+ .src = .{
+ .src_path = path,
+ .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
+ std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
+ }),
+ .byte_offset = byte_offset,
+ .line = @intCast(u32, start_loc.line),
+ .column = @intCast(u32, start_loc.column) + bad_off,
+ .source_line = source_line,
+ },
+ };
+ notes_len += 1;
+ } else if (parse_error.tag == .decl_between_fields) {
+ const prev_loc = tree.tokenLocation(0, parse_errors[i + 1].token);
+ notes_buffer[0] = .{
+ .src = .{
+ .src_path = path,
+ .msg = "field before declarations here",
+ .byte_offset = @intCast(u32, prev_loc.line_start),
+ .line = @intCast(u32, prev_loc.line),
+ .column = @intCast(u32, prev_loc.column),
+ .source_line = tree.source[prev_loc.line_start..prev_loc.line_end],
+ },
+ };
+ const next_loc = tree.tokenLocation(0, parse_errors[i + 2].token);
+ notes_buffer[1] = .{
+ .src = .{
+ .src_path = path,
+ .msg = "field after declarations here",
+ .byte_offset = @intCast(u32, next_loc.line_start),
+ .line = @intCast(u32, next_loc.line),
+ .column = @intCast(u32, next_loc.column),
+ .source_line = tree.source[next_loc.line_start..next_loc.line_end],
+ },
+ };
+ notes_len = 2;
+ i += 2;
+ }
+
+ const extra_offset = tree.errorOffset(parse_error);
+ const message: Compilation.AllErrors.Message = .{
.src = .{
.src_path = path,
- .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{
- std.zig.fmtEscapes(tree.source[byte_offset..][0..1]),
- }),
- .byte_offset = byte_offset,
+ .msg = text,
+ .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset,
.line = @intCast(u32, start_loc.line),
- .column = @intCast(u32, start_loc.column) + bad_off,
+ .column = @intCast(u32, start_loc.column) + extra_offset,
.source_line = source_line,
+ .notes = notes_buffer[0..notes_len],
},
};
- notes_len += 1;
- }
- const extra_offset = tree.errorOffset(parse_error.tag, parse_error.token);
- const message: Compilation.AllErrors.Message = .{
- .src = .{
- .src_path = path,
- .msg = text,
- .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset,
- .line = @intCast(u32, start_loc.line),
- .column = @intCast(u32, start_loc.column) + extra_offset,
- .source_line = source_line,
- .notes = notes_buffer[0..notes_len],
- },
- };
-
- const ttyconf: std.debug.TTY.Config = switch (color) {
- .auto => std.debug.detectTTYConfig(),
- .on => .escape_codes,
- .off => .no_color,
- };
+ const ttyconf: std.debug.TTY.Config = switch (color) {
+ .auto => std.debug.detectTTYConfig(),
+ .on => .escape_codes,
+ .off => .no_color,
+ };
- message.renderToStdErr(ttyconf);
+ message.renderToStdErr(ttyconf);
+ }
}
pub const info_zen =
@@ -4688,9 +4713,7 @@ pub fn cmdAstCheck(
file.tree_loaded = true;
defer file.tree.deinit(gpa);
- for (file.tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, file.sub_file_path, color);
- }
+ try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, file.sub_file_path, color);
if (file.tree.errors.len != 0) {
process.exit(1);
}
@@ -4816,9 +4839,7 @@ pub fn cmdChangelist(
file.tree_loaded = true;
defer file.tree.deinit(gpa);
- for (file.tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, old_source_file, .auto);
- }
+ try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, old_source_file, .auto);
if (file.tree.errors.len != 0) {
process.exit(1);
}
@@ -4855,9 +4876,7 @@ pub fn cmdChangelist(
var new_tree = try std.zig.parse(gpa, new_source);
defer new_tree.deinit(gpa);
- for (new_tree.errors) |parse_error| {
- try printErrMsgToStdErr(gpa, arena, parse_error, new_tree, new_source_file, .auto);
- }
+ try printErrsMsgToStdErr(gpa, arena, new_tree.errors, new_tree, new_source_file, .auto);
if (new_tree.errors.len != 0) {
process.exit(1);
}
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp
@@ -7843,7 +7843,7 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0
|| !actual_type->data.pointer.is_const);
- if (const_ok && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
+ if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
array_type->data.array.child_type, source_node,
!slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk &&
(slice_ptr_type->data.pointer.sentinel == nullptr ||
@@ -7851,6 +7851,14 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
const_values_equal(ira->codegen, array_type->data.array.sentinel,
slice_ptr_type->data.pointer.sentinel))))
{
+ if (!const_ok) {
+ ErrorMsg *msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("cannot cast pointer to array literal to slice type '%s'",
+ buf_ptr(&wanted_type->name)));
+ add_error_note(ira->codegen, msg, source_node,
+ buf_sprintf("cast discards const qualifier"));
+ return ira->codegen->invalid_inst_gen;
+ }
// If the pointers both have ABI align, it works.
// Or if the array length is 0, alignment doesn't matter.
bool ok_align = array_type->data.array.len == 0 ||
@@ -8208,8 +8216,16 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
ZigType *wanted_child = wanted_type->data.pointer.child_type;
bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const);
if (wanted_child->id == ZigTypeIdArray && (is_array_init || field_count == 0) &&
- wanted_child->data.array.len == field_count && (const_ok || field_count == 0))
+ wanted_child->data.array.len == field_count)
{
+ if (!const_ok && field_count != 0) {
+ ErrorMsg *msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("cannot cast pointer to array literal to '%s'",
+ buf_ptr(&wanted_type->name)));
+ add_error_note(ira->codegen, msg, source_node,
+ buf_sprintf("cast discards const qualifier"));
+ return ira->codegen->invalid_inst_gen;
+ }
Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child);
if (res->value->type->id == ZigTypeIdPointer)
return res;
@@ -8241,6 +8257,13 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou
res = ir_get_ref(ira, scope, source_node, res, actual_type->data.pointer.is_const, actual_type->data.pointer.is_volatile);
return ir_resolve_ptr_of_array_to_slice(ira, scope, source_node, res, wanted_type, nullptr);
+ } else if (!slice_type->data.pointer.is_const && actual_type->data.pointer.is_const && field_count != 0) {
+ ErrorMsg *msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("cannot cast pointer to array literal to slice type '%s'",
+ buf_ptr(&wanted_type->name)));
+ add_error_note(ira->codegen, msg, source_node,
+ buf_sprintf("cast discards const qualifier"));
+ return ira->codegen->invalid_inst_gen;
}
}
}
@@ -15068,7 +15091,7 @@ static Stage1AirInst *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, Stage1ZirI
return ira->codegen->invalid_inst_gen;
if (actual_array_type->id != ZigTypeIdArray) {
ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node,
- buf_sprintf("array literal requires address-of operator to coerce to slice type '%s'",
+ buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'",
buf_ptr(&actual_array_type->name)));
return ira->codegen->invalid_inst_gen;
}
@@ -17473,7 +17496,7 @@ static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
if (is_slice(container_type)) {
ir_add_error_node(ira, instruction->init_array_type_source_node,
- buf_sprintf("array literal requires address-of operator to coerce to slice type '%s'",
+ buf_sprintf("array literal requires address-of operator (&) to coerce to slice type '%s'",
buf_ptr(&container_type->name)));
return ira->codegen->invalid_inst_gen;
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
@@ -86,9 +86,12 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = c;
\\}
, &[_][]const u8{
- "tmp.zig:2:31: error: expected type '[][]const u8', found '*const struct:2:31'",
- "tmp.zig:6:33: error: expected type '*[2][]const u8', found '*const struct:6:33'",
+ "tmp.zig:2:31: error: cannot cast pointer to array literal to slice type '[][]const u8'",
+ "tmp.zig:2:31: note: cast discards const qualifier",
+ "tmp.zig:6:33: error: cannot cast pointer to array literal to '*[2][]const u8'",
+ "tmp.zig:6:33: note: cast discards const qualifier",
"tmp.zig:11:21: error: expected type '*S', found '*const struct:11:21'",
+ "tmp.zig:11:21: note: cast discards const qualifier",
});
ctx.objErrStage1("@Type() union payload is undefined",
@@ -874,6 +877,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{
"tmp.zig:6:5: error: declarations are not allowed between container fields",
+ "tmp.zig:5:5: note: field before declarations here",
+ "tmp.zig:9:5: note: field after declarations here",
});
ctx.objErrStage1("non-extern function with var args",
@@ -1540,7 +1545,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ std.debug.assert(bad_float < 1.0);
\\}
, &[_][]const u8{
- "tmp.zig:5:29: error: invalid token: '.'",
+ "tmp.zig:5:29: error: expected expression, found '.'",
});
ctx.objErrStage1("invalid exponent in float literal - 1",
@@ -1549,7 +1554,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:28: note: invalid byte: 'a'",
});
@@ -1559,7 +1564,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:29: note: invalid byte: 'F'",
});
@@ -1569,7 +1574,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:23: note: invalid byte: '_'",
});
@@ -1579,7 +1584,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:23: note: invalid byte: '.'",
});
@@ -1589,7 +1594,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:25: note: invalid byte: ';'",
});
@@ -1599,7 +1604,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:25: note: invalid byte: '_'",
});
@@ -1609,7 +1614,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:26: note: invalid byte: '_'",
});
@@ -1619,7 +1624,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:26: note: invalid byte: '_'",
});
@@ -1629,7 +1634,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:28: note: invalid byte: ';'",
});
@@ -1639,7 +1644,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:23: note: invalid byte: '_'",
});
@@ -1649,7 +1654,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:25: note: invalid byte: '_'",
});
@@ -1659,7 +1664,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:28: note: invalid byte: '_'",
});
@@ -1669,7 +1674,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:23: note: invalid byte: 'x'",
});
@@ -1679,7 +1684,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:23: note: invalid byte: '_'",
});
@@ -1689,7 +1694,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:27: note: invalid byte: 'p'",
});
@@ -1699,7 +1704,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:26: note: invalid byte: ';'",
});
@@ -1709,7 +1714,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:28: note: invalid byte: ';'",
});
@@ -1719,7 +1724,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:28: note: invalid byte: ';'",
});
@@ -1729,7 +1734,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = bad;
\\}
, &[_][]const u8{
- "tmp.zig:2:21: error: expected expression, found 'invalid'",
+ "tmp.zig:2:21: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:28: note: invalid byte: ';'",
});
@@ -1962,7 +1967,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = geo_data;
\\}
, &[_][]const u8{
- "tmp.zig:4:30: error: array literal requires address-of operator to coerce to slice type '[][2]f32'",
+ "tmp.zig:4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'",
});
ctx.objErrStage1("slicing of global undefined pointer",
@@ -2171,7 +2176,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x;
\\}
, &[_][]const u8{
- "tmp.zig:3:6: error: expected ',' after field",
+ "tmp.zig:3:7: error: expected ',' after field",
});
ctx.objErrStage1("bad alignment type",
@@ -2537,7 +2542,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x;
\\}
, &[_][]const u8{
- "tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'",
+ "tmp.zig:2:15: error: array literal requires address-of operator (&) to coerce to slice type '[]u8'",
});
ctx.objErrStage1("slice passed as array init type",
@@ -2546,7 +2551,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = x;
\\}
, &[_][]const u8{
- "tmp.zig:2:15: error: array literal requires address-of operator to coerce to slice type '[]u8'",
+ "tmp.zig:2:15: error: array literal requires address-of operator (&) to coerce to slice type '[]u8'",
});
ctx.objErrStage1("inferred array size invalid here",
@@ -3493,7 +3498,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = sliceA;
\\}
, &[_][]const u8{
- "tmp.zig:3:27: error: expected type '[]u8', found '*const [1]u8'",
+ "tmp.zig:3:27: error: cannot cast pointer to array literal to slice type '[]u8'",
+ "tmp.zig:3:27: note: cast discards const qualifier",
});
ctx.objErrStage1("deref slice and get len field",
@@ -4865,11 +4871,11 @@ pub fn addCases(ctx: *TestContext) !void {
\\export fn entry() void {
\\ while(true) {}
\\ var good = {};
- \\ while(true) ({})
+ \\ while(true) 1
\\ var bad = {};
\\}
, &[_][]const u8{
- "tmp.zig:4:21: error: expected ';' or 'else' after statement",
+ "tmp.zig:4:18: error: expected ';' or 'else' after statement",
});
ctx.objErrStage1("implicit semicolon - while expression",
@@ -5733,7 +5739,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\const foo = "a
\\b";
, &[_][]const u8{
- "tmp.zig:1:13: error: expected expression, found 'invalid'",
+ "tmp.zig:1:13: error: expected expression, found 'invalid bytes'",
"tmp.zig:1:15: note: invalid byte: '\\n'",
});
@@ -7638,7 +7644,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ const a = '\U1234';
\\}
, &[_][]const u8{
- "tmp.zig:2:15: error: expected expression, found 'invalid'",
+ "tmp.zig:2:15: error: expected expression, found 'invalid bytes'",
"tmp.zig:2:18: note: invalid byte: '1'",
});
@@ -7654,7 +7660,7 @@ pub fn addCases(ctx: *TestContext) !void {
"fn foo() bool {\r\n" ++
" return true;\r\n" ++
"}\r\n", &[_][]const u8{
- "tmp.zig:1:1: error: expected test, comptime, var decl, or container field, found 'invalid'",
+ "tmp.zig:1:1: error: expected test, comptime, var decl, or container field, found 'invalid bytes'",
"tmp.zig:1:1: note: invalid byte: '\\xff'",
});
@@ -8717,7 +8723,8 @@ pub fn addCases(ctx: *TestContext) !void {
\\ comptime ignore(@typeInfo(MyStruct).Struct.fields[0]);
\\}
, &[_][]const u8{
- ":5:28: error: expected type '[]u8', found '*const [3:0]u8'",
+ ":5:28: error: cannot cast pointer to array literal to slice type '[]u8'",
+ ":5:28: note: cast discards const qualifier",
});
ctx.objErrStage1("integer underflow error",
diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig
@@ -693,7 +693,7 @@ pub fn addCases(ctx: *TestContext) !void {
\\ _ = E1.a;
\\}
, &.{
- ":3:6: error: expected ',' after field",
+ ":3:7: error: expected ',' after field",
});
// Redundant non-exhaustive enum mark.