| author | |
| committer | |
| log | 53241f288e40a9e97a5425cb0e1ac7dbbc9de852 |
| tree | d63dda15c2615440408100e213e8c97dfd7c4d52 |
| parent | 56e9575e827208b3df5c90472826f52bfc8342c0 |
| parent | 6b65590715d0871c11635fc49cb1fc471a60ea59 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
further parser error improvements10 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'#} |
| 10409 | fn foo(s: []u8) void { | 10409 | fn 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 |
| 66 | 66 | ||
| 67 | /// Returns an extra offset for column and byte offset of errors that | 67 | /// 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. |
| 69 | pub fn errorOffset(tree: Ast, error_tag: Error.Tag, token: TokenIndex) u32 { | 69 | pub 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 | } |
| 84 | 75 | ||
| 85 | pub fn tokenLocation(self: Ast, start_offset: ByteOffset, token_index: TokenIndex) Location { | 76 | 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 { | ... | @@ -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 | }, | ||
| 322 | 306 | ||
| 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 | }, | ||
| 344 | 338 | ||
| 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 { |
| 2483 | 2477 | ||
| 2484 | pub const Error = struct { | 2478 | pub 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, |
| 2533 | 2528 | 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, | ||
| 2542 | 2540 | ||
| 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), |
| 93 | 93 | ||
| 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 | } |
| 149 | 152 | ||
| 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 | } |
| 163 | 161 | ||
| 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 | } |
| 168 | 166 | ||
| 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 | } |
| 173 | 211 | ||
| ... | @@ -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 on | 645 | // Since parseBlock only return error.ParseError on |
| 586 | // a missing '}' we can assume this function was | 646 | // 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 | } |
| 1407 | 1468 | ||
| 1408 | node = try p.addNode(.{ | 1469 | node = try p.addNode(.{ |
| ... | @@ -1881,7 +1942,7 @@ const Parser = struct { | ... | @@ -1881,7 +1942,7 @@ const Parser = struct { |
| 1881 | 1942 | ||
| 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 | } |
| 1886 | 1947 | ||
| 1887 | /// Block <- LBRACE Statement* RBRACE | 1948 | /// 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 { |
| 2349 | 2410 | ||
| 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(), |
| 2354 | 2415 | ||
| 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 | } |
| 2884 | 2945 | ||
| 2885 | /// FieldInit <- DOT IDENTIFIER EQUAL Expr | 2946 | /// FieldInit <- DOT IDENTIFIER EQUAL Expr |
| ... | @@ -2896,15 +2957,23 @@ const Parser = struct { | ... | @@ -2896,15 +2957,23 @@ const Parser = struct { |
| 2896 | } | 2957 | } |
| 2897 | 2958 | ||
| 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 | } |
| 2904 | 2968 | ||
| 2905 | /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN | 2969 | /// 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 | } |
| 3532 | 3601 | ||
| 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(); |
| 3591 | 3609 | ||
| 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); |
| 3594 | 3612 | ||
| 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); |
| 3606 | 3624 | ||
| 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 | } |
| 3650 | 3668 | ||
| 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 | } |
| 3672 | 3679 | ||
| 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 | } |
| 3681 | 3688 |
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 | } |
| 231 | 233 | ||
| ... | @@ -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 | } |
| 5020 | 5022 | ||
| 5023 | test "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 | |||
| 5021 | test "zig fmt: error for invalid bit range" { | 5042 | test "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 | } |
| 5082 | 5105 |
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 | } |
| 323 | 323 | ||
| 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); |
| 2997 | 2997 | ||
| 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 | } |
| 3018 | 3029 | ||
| 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); |
| 3801 | 3801 | ||
| 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); |
| 3991 | 3989 | ||
| 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 | } |
| 4073 | 4069 | ||
| 4074 | fn printErrMsgToStdErr( | 4070 | fn 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; |
| 4086 | 4082 | 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(); |
| 4092 | 4088 | 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; |
| 4095 | 4091 | ||
| 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 | } | ||
| 4113 | 4150 | ||
| 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 | }; | ||
| 4132 | 4156 | ||
| 4133 | message.renderToStdErr(ttyconf); | 4157 | message.renderToStdErr(ttyconf); |
| 4158 | } | ||
| 4134 | } | 4159 | } |
| 4135 | 4160 | ||
| 4136 | pub const info_zen = | 4161 | pub 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); |
| 4690 | 4715 | ||
| 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); |
| 4818 | 4841 | ||
| 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); |
| 4857 | 4878 | ||
| 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 == 0 | 7843 | 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); |
| 7845 | 7845 | ||
| 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); |
| 8242 | 8258 | ||
| 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, |
| 17473 | 17496 | ||
| 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 | }); |
| 93 | 96 | ||
| 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 | }); |
| 878 | 883 | ||
| 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 | }); |
| 1545 | 1550 | ||
| 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 | }); |
| 1555 | 1560 | ||
| ... | @@ -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 | }); |
| 1565 | 1570 | ||
| ... | @@ -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 | }); |
| 1575 | 1580 | ||
| ... | @@ -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 | }); |
| 1585 | 1590 | ||
| ... | @@ -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 | }); |
| 1595 | 1600 | ||
| ... | @@ -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 | }); |
| 1605 | 1610 | ||
| ... | @@ -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 | }); |
| 1615 | 1620 | ||
| ... | @@ -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 | }); |
| 1625 | 1630 | ||
| ... | @@ -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 | }); |
| 1635 | 1640 | ||
| ... | @@ -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 | }); |
| 1645 | 1650 | ||
| ... | @@ -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 | }); |
| 1655 | 1660 | ||
| ... | @@ -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 | }); |
| 1665 | 1670 | ||
| ... | @@ -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 | }); |
| 1675 | 1680 | ||
| ... | @@ -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 | }); |
| 1685 | 1690 | ||
| ... | @@ -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 | }); |
| 1695 | 1700 | ||
| ... | @@ -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 | }); |
| 1705 | 1710 | ||
| ... | @@ -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 | }); |
| 1715 | 1720 | ||
| ... | @@ -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 | }); |
| 1725 | 1730 | ||
| ... | @@ -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 | }); |
| 1735 | 1740 | ||
| ... | @@ -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 | }); |
| 1967 | 1972 | ||
| 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 | }); |
| 2176 | 2181 | ||
| 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 | }); |
| 2542 | 2547 | ||
| 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 | }); |
| 2551 | 2556 | ||
| 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 | }); |
| 3498 | 3504 | ||
| 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 | }); |
| 4874 | 4880 | ||
| 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 = "a | 5739 | \\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 | }); |
| 5739 | 5745 | ||
| ... | @@ -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 | }); |
| 7644 | 7650 | ||
| ... | @@ -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 | }); |
| 7660 | 7666 | ||
| ... | @@ -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 | }); |
| 8722 | 8729 | ||
| 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 | }); |
| 698 | 698 | ||
| 699 | // Redundant non-exhaustive enum mark. | 699 | // Redundant non-exhaustive enum mark. |