| 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 | 10405 | <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section. |
| 10406 | 10406 | This is why it is an error to pass a string literal to a mutable slice, like this: |
| 10407 | 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 | 10409 | fn foo(s: []u8) void { |
| 10410 | 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 | 66 | |
| 67 | 67 | /// Returns an extra offset for column and byte offset of errors that |
| 68 | 68 | /// should point after the token in the error message. |
| 69 | pub fn errorOffset(tree: Ast, error_tag: Error.Tag, token: TokenIndex) u32 { | |
| 70 | return switch (error_tag) { | |
| 71 | .expected_semi_after_decl, | |
| 72 | .expected_semi_after_stmt, | |
| 73 | .expected_comma_after_field, | |
| 74 | .expected_comma_after_arg, | |
| 75 | .expected_comma_after_param, | |
| 76 | .expected_comma_after_initializer, | |
| 77 | .expected_comma_after_switch_prong, | |
| 78 | .expected_semi_or_else, | |
| 79 | .expected_semi_or_lbrace, | |
| 80 | => @intCast(u32, tree.tokenSlice(token).len), | |
| 81 | else => 0, | |
| 82 | }; | |
| 69 | pub fn errorOffset(tree: Ast, parse_error: Error) u32 { | |
| 70 | return if (parse_error.token_is_prev) | |
| 71 | @intCast(u32, tree.tokenSlice(parse_error.token).len) | |
| 72 | else | |
| 73 | 0; | |
| 83 | 74 | } |
| 84 | 75 | |
| 85 | 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 | 153 | }, |
| 163 | 154 | .expected_block => { |
| 164 | 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 | 159 | .expected_block_or_assignment => { |
| 169 | 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 | 164 | .expected_block_or_expr => { |
| 174 | 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 | 169 | .expected_block_or_field => { |
| 179 | 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 | 174 | .expected_container_members => { |
| ... | ... | @@ -187,42 +178,42 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 187 | 178 | }, |
| 188 | 179 | .expected_expr => { |
| 189 | 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 | 184 | .expected_expr_or_assignment => { |
| 194 | 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 | 189 | .expected_fn => { |
| 199 | 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 | 194 | .expected_inlinable => { |
| 204 | 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 | 199 | .expected_labelable => { |
| 209 | 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 | 204 | .expected_param_list => { |
| 214 | 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 | 209 | .expected_prefix_expr => { |
| 219 | 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 | 214 | .expected_primary_type_expr => { |
| 224 | 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 | 219 | .expected_pub_item => { |
| ... | ... | @@ -230,7 +221,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 230 | 221 | }, |
| 231 | 222 | .expected_return_type => { |
| 232 | 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 | 227 | .expected_semi_or_else => { |
| ... | ... | @@ -244,39 +235,34 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 244 | 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 | 238 | .expected_suffix_op => { |
| 253 | 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 | 243 | .expected_type_expr => { |
| 258 | 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 | 248 | .expected_var_decl => { |
| 263 | 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 | 253 | .expected_var_decl_or_fn => { |
| 268 | 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 | 258 | .expected_loop_payload => { |
| 273 | 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 | 263 | .expected_container => { |
| 278 | 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 | 268 | .extern_fn_body => { |
| ... | ... | @@ -305,11 +291,6 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 305 | 291 | .invalid_bit_range => { |
| 306 | 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 | 294 | .same_line_doc_comment => { |
| 314 | 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 | 300 | .varargs_nonfinal => { |
| 320 | 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 | 307 | .expected_semi_after_decl => { |
| 324 | 308 | return stream.writeAll("expected ';' after declaration"); |
| ... | ... | @@ -341,9 +325,19 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 341 | 325 | .expected_comma_after_switch_prong => { |
| 342 | 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 | 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 | 341 | const expected_symbol = parse_error.extra.expected_tag.symbol(); |
| 348 | 342 | switch (found_tag) { |
| 349 | 343 | .invalid => return stream.print("expected '{s}', found invalid bytes", .{ |
| ... | ... | @@ -2483,6 +2477,9 @@ pub const full = struct { |
| 2483 | 2477 | |
| 2484 | 2478 | pub const Error = struct { |
| 2485 | 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 | 2483 | token: TokenIndex, |
| 2487 | 2484 | extra: union { |
| 2488 | 2485 | none: void, |
| ... | ... | @@ -2511,7 +2508,6 @@ pub const Error = struct { |
| 2511 | 2508 | expected_semi_or_else, |
| 2512 | 2509 | expected_semi_or_lbrace, |
| 2513 | 2510 | expected_statement, |
| 2514 | expected_string_literal, | |
| 2515 | 2511 | expected_suffix_op, |
| 2516 | 2512 | expected_type_expr, |
| 2517 | 2513 | expected_var_decl, |
| ... | ... | @@ -2526,12 +2522,10 @@ pub const Error = struct { |
| 2526 | 2522 | extra_volatile_qualifier, |
| 2527 | 2523 | ptr_mod_on_array_child_type, |
| 2528 | 2524 | invalid_bit_range, |
| 2529 | invalid_token, | |
| 2530 | 2525 | same_line_doc_comment, |
| 2531 | 2526 | unattached_doc_comment, |
| 2532 | 2527 | varargs_nonfinal, |
| 2533 | ||
| 2534 | // these have `token` set to token after which a semicolon was expected | |
| 2528 | expected_continue_expr, | |
| 2535 | 2529 | expected_semi_after_decl, |
| 2536 | 2530 | expected_semi_after_stmt, |
| 2537 | 2531 | expected_comma_after_field, |
| ... | ... | @@ -2539,6 +2533,10 @@ pub const Error = struct { |
| 2539 | 2533 | expected_comma_after_param, |
| 2540 | 2534 | expected_comma_after_initializer, |
| 2541 | 2535 | expected_comma_after_switch_prong, |
| 2536 | expected_initializer, | |
| 2537 | ||
| 2538 | previous_field, | |
| 2539 | next_field, | |
| 2542 | 2540 | |
| 2543 | 2541 | /// `expected_tag` is populated. |
| 2544 | 2542 | expected_token, |
lib/std/zig/parse.zig+106-99| ... | ... | @@ -91,6 +91,9 @@ const Parser = struct { |
| 91 | 91 | extra_data: std.ArrayListUnmanaged(Node.Index), |
| 92 | 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 | 97 | const SmallSpan = union(enum) { |
| 95 | 98 | zero_or_one: Node.Index, |
| 96 | 99 | multi: Node.SubRange, |
| ... | ... | @@ -147,11 +150,6 @@ const Parser = struct { |
| 147 | 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 | 153 | fn warnExpected(p: *Parser, expected_token: Token.Tag) error{OutOfMemory}!void { |
| 156 | 154 | @setCold(true); |
| 157 | 155 | try p.warnMsg(.{ |
| ... | ... | @@ -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 | 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 | 167 | fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void { |
| 170 | 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 | 209 | try p.errors.append(p.gpa, msg); |
| 172 | 210 | } |
| 173 | 211 | |
| ... | ... | @@ -235,6 +273,8 @@ const Parser = struct { |
| 235 | 273 | .keyword_comptime => switch (p.token_tags[p.tok_i + 1]) { |
| 236 | 274 | .identifier => { |
| 237 | 275 | p.tok_i += 1; |
| 276 | const identifier = p.tok_i; | |
| 277 | defer p.last_field = identifier; | |
| 238 | 278 | const container_field = try p.expectContainerFieldRecoverable(); |
| 239 | 279 | if (container_field != 0) { |
| 240 | 280 | switch (field_state) { |
| ... | ... | @@ -245,6 +285,16 @@ const Parser = struct { |
| 245 | 285 | .tag = .decl_between_fields, |
| 246 | 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 | 298 | // Continue parsing; error will be reported later. |
| 249 | 299 | field_state = .err; |
| 250 | 300 | }, |
| ... | ... | @@ -264,7 +314,7 @@ const Parser = struct { |
| 264 | 314 | } |
| 265 | 315 | // There is not allowed to be a decl after a field with no comma. |
| 266 | 316 | // Report error but recover parser. |
| 267 | try p.warnExpectedAfter(.expected_comma_after_field); | |
| 317 | try p.warn(.expected_comma_after_field); | |
| 268 | 318 | p.findNextContainerMember(); |
| 269 | 319 | } |
| 270 | 320 | }, |
| ... | ... | @@ -338,6 +388,8 @@ const Parser = struct { |
| 338 | 388 | trailing = p.token_tags[p.tok_i - 1] == .semicolon; |
| 339 | 389 | }, |
| 340 | 390 | .identifier => { |
| 391 | const identifier = p.tok_i; | |
| 392 | defer p.last_field = identifier; | |
| 341 | 393 | const container_field = try p.expectContainerFieldRecoverable(); |
| 342 | 394 | if (container_field != 0) { |
| 343 | 395 | switch (field_state) { |
| ... | ... | @@ -348,6 +400,14 @@ const Parser = struct { |
| 348 | 400 | .tag = .decl_between_fields, |
| 349 | 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 | 411 | // Continue parsing; error will be reported later. |
| 352 | 412 | field_state = .err; |
| 353 | 413 | }, |
| ... | ... | @@ -367,7 +427,7 @@ const Parser = struct { |
| 367 | 427 | } |
| 368 | 428 | // There is not allowed to be a decl after a field with no comma. |
| 369 | 429 | // Report error but recover parser. |
| 370 | try p.warnExpectedAfter(.expected_comma_after_field); | |
| 430 | try p.warn(.expected_comma_after_field); | |
| 371 | 431 | p.findNextContainerMember(); |
| 372 | 432 | } |
| 373 | 433 | }, |
| ... | ... | @@ -585,7 +645,7 @@ const Parser = struct { |
| 585 | 645 | // Since parseBlock only return error.ParseError on |
| 586 | 646 | // a missing '}' we can assume this function was |
| 587 | 647 | // supposed to end here. |
| 588 | try p.warnExpectedAfter(.expected_semi_or_lbrace); | |
| 648 | try p.warn(.expected_semi_or_lbrace); | |
| 589 | 649 | return null_node; |
| 590 | 650 | }, |
| 591 | 651 | } |
| ... | ... | @@ -996,7 +1056,7 @@ const Parser = struct { |
| 996 | 1056 | }; |
| 997 | 1057 | _ = p.eatToken(.keyword_else) orelse { |
| 998 | 1058 | if (else_required) { |
| 999 | try p.warnExpectedAfter(.expected_semi_or_else); | |
| 1059 | try p.warn(.expected_semi_or_else); | |
| 1000 | 1060 | } |
| 1001 | 1061 | return p.addNode(.{ |
| 1002 | 1062 | .tag = .if_simple, |
| ... | ... | @@ -1091,7 +1151,7 @@ const Parser = struct { |
| 1091 | 1151 | }; |
| 1092 | 1152 | _ = p.eatToken(.keyword_else) orelse { |
| 1093 | 1153 | if (else_required) { |
| 1094 | try p.warnExpectedAfter(.expected_semi_or_else); | |
| 1154 | try p.warn(.expected_semi_or_else); | |
| 1095 | 1155 | } |
| 1096 | 1156 | return p.addNode(.{ |
| 1097 | 1157 | .tag = .for_simple, |
| ... | ... | @@ -1166,7 +1226,7 @@ const Parser = struct { |
| 1166 | 1226 | }; |
| 1167 | 1227 | _ = p.eatToken(.keyword_else) orelse { |
| 1168 | 1228 | if (else_required) { |
| 1169 | try p.warnExpectedAfter(.expected_semi_or_else); | |
| 1229 | try p.warn(.expected_semi_or_else); | |
| 1170 | 1230 | } |
| 1171 | 1231 | if (cont_expr == 0) { |
| 1172 | 1232 | return p.addNode(.{ |
| ... | ... | @@ -1402,7 +1462,8 @@ const Parser = struct { |
| 1402 | 1462 | } |
| 1403 | 1463 | const rhs = try p.parseExprPrecedence(info.prec + 1); |
| 1404 | 1464 | if (rhs == 0) { |
| 1405 | return p.fail(.invalid_token); | |
| 1465 | try p.warn(.expected_expr); | |
| 1466 | return node; | |
| 1406 | 1467 | } |
| 1407 | 1468 | |
| 1408 | 1469 | node = try p.addNode(.{ |
| ... | ... | @@ -1881,7 +1942,7 @@ const Parser = struct { |
| 1881 | 1942 | |
| 1882 | 1943 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? |
| 1883 | 1944 | fn parseIfExpr(p: *Parser) !Node.Index { |
| 1884 | return p.parseIf(parseExpr); | |
| 1945 | return p.parseIf(expectExpr); | |
| 1885 | 1946 | } |
| 1886 | 1947 | |
| 1887 | 1948 | /// Block <- LBRACE Statement* RBRACE |
| ... | ... | @@ -2050,7 +2111,7 @@ const Parser = struct { |
| 2050 | 2111 | }, |
| 2051 | 2112 | .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), |
| 2052 | 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 | 2116 | if (p.eatToken(.r_brace)) |_| break; |
| 2056 | 2117 | const next = try p.expectFieldInit(); |
| ... | ... | @@ -2091,7 +2152,7 @@ const Parser = struct { |
| 2091 | 2152 | }, |
| 2092 | 2153 | .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), |
| 2093 | 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 | 2158 | const comma = (p.token_tags[p.tok_i - 2] == .comma); |
| ... | ... | @@ -2170,7 +2231,7 @@ const Parser = struct { |
| 2170 | 2231 | }, |
| 2171 | 2232 | .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), |
| 2172 | 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 | 2237 | const comma = (p.token_tags[p.tok_i - 2] == .comma); |
| ... | ... | @@ -2226,7 +2287,7 @@ const Parser = struct { |
| 2226 | 2287 | }, |
| 2227 | 2288 | .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), |
| 2228 | 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 | 2293 | const comma = (p.token_tags[p.tok_i - 2] == .comma); |
| ... | ... | @@ -2349,7 +2410,7 @@ const Parser = struct { |
| 2349 | 2410 | |
| 2350 | 2411 | .builtin => return p.parseBuiltinCall(), |
| 2351 | 2412 | .keyword_fn => return p.parseFnProto(), |
| 2352 | .keyword_if => return p.parseIf(parseTypeExpr), | |
| 2413 | .keyword_if => return p.parseIf(expectTypeExpr), | |
| 2353 | 2414 | .keyword_switch => return p.expectSwitchExpr(), |
| 2354 | 2415 | |
| 2355 | 2416 | .keyword_extern, |
| ... | ... | @@ -2467,7 +2528,7 @@ const Parser = struct { |
| 2467 | 2528 | }, |
| 2468 | 2529 | .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), |
| 2469 | 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 | 2533 | if (p.eatToken(.r_brace)) |_| break; |
| 2473 | 2534 | const next = try p.expectFieldInit(); |
| ... | ... | @@ -2519,7 +2580,7 @@ const Parser = struct { |
| 2519 | 2580 | }, |
| 2520 | 2581 | .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), |
| 2521 | 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 | 2586 | const comma = (p.token_tags[p.tok_i - 2] == .comma); |
| ... | ... | @@ -2580,7 +2641,7 @@ const Parser = struct { |
| 2580 | 2641 | }, |
| 2581 | 2642 | .colon, .r_paren, .r_bracket => return p.failExpected(.r_brace), |
| 2582 | 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 | 2647 | return p.addNode(.{ |
| ... | ... | @@ -2879,7 +2940,7 @@ const Parser = struct { |
| 2879 | 2940 | p.tok_i += 2; |
| 2880 | 2941 | return identifier; |
| 2881 | 2942 | } |
| 2882 | return 0; | |
| 2943 | return null_node; | |
| 2883 | 2944 | } |
| 2884 | 2945 | |
| 2885 | 2946 | /// FieldInit <- DOT IDENTIFIER EQUAL Expr |
| ... | ... | @@ -2896,15 +2957,23 @@ const Parser = struct { |
| 2896 | 2957 | } |
| 2897 | 2958 | |
| 2898 | 2959 | fn expectFieldInit(p: *Parser) !Node.Index { |
| 2899 | _ = try p.expectToken(.period); | |
| 2900 | _ = try p.expectToken(.identifier); | |
| 2901 | _ = try p.expectToken(.equal); | |
| 2960 | if (p.token_tags[p.tok_i] != .period or | |
| 2961 | p.token_tags[p.tok_i + 1] != .identifier or | |
| 2962 | p.token_tags[p.tok_i + 2] != .equal) | |
| 2963 | return p.fail(.expected_initializer); | |
| 2964 | ||
| 2965 | p.tok_i += 3; | |
| 2902 | 2966 | return p.expectExpr(); |
| 2903 | 2967 | } |
| 2904 | 2968 | |
| 2905 | 2969 | /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN |
| 2906 | 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 | 2977 | _ = try p.expectToken(.l_paren); |
| 2909 | 2978 | const node = try p.parseAssignExpr(); |
| 2910 | 2979 | if (node == 0) return p.fail(.expected_expr_or_assignment); |
| ... | ... | @@ -3413,7 +3482,7 @@ const Parser = struct { |
| 3413 | 3482 | // All possible delimiters. |
| 3414 | 3483 | .colon, .r_paren, .r_brace, .r_bracket => break, |
| 3415 | 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 | 3488 | return p.listToSpan(p.scratch.items[scratch_top..]); |
| ... | ... | @@ -3442,7 +3511,7 @@ const Parser = struct { |
| 3442 | 3511 | }, |
| 3443 | 3512 | .colon, .r_brace, .r_bracket => return p.failExpected(.r_paren), |
| 3444 | 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 | 3517 | if (varargs == .nonfinal) { |
| ... | ... | @@ -3486,7 +3555,7 @@ const Parser = struct { |
| 3486 | 3555 | break; |
| 3487 | 3556 | }, |
| 3488 | 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 | 3561 | const comma = (p.token_tags[p.tok_i - 2] == .comma); |
| ... | ... | @@ -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 | 3602 | /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)? |
| 3585 | 3603 | fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index { |
| 3586 | 3604 | const if_token = p.eatToken(.keyword_if) orelse return null_node; |
| ... | ... | @@ -3590,7 +3608,7 @@ const Parser = struct { |
| 3590 | 3608 | _ = try p.parsePtrPayload(); |
| 3591 | 3609 | |
| 3592 | 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 | 3613 | _ = p.eatToken(.keyword_else) orelse return p.addNode(.{ |
| 3596 | 3614 | .tag = .if_simple, |
| ... | ... | @@ -3602,7 +3620,7 @@ const Parser = struct { |
| 3602 | 3620 | }); |
| 3603 | 3621 | _ = try p.parsePayload(); |
| 3604 | 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 | 3625 | return p.addNode(.{ |
| 3608 | 3626 | .tag = .@"if", |
| ... | ... | @@ -3649,25 +3667,14 @@ const Parser = struct { |
| 3649 | 3667 | } |
| 3650 | 3668 | |
| 3651 | 3669 | fn expectToken(p: *Parser, tag: Token.Tag) Error!TokenIndex { |
| 3652 | const token = p.nextToken(); | |
| 3653 | if (p.token_tags[token] != tag) { | |
| 3654 | p.tok_i -= 1; // Go back so that we can recover properly. | |
| 3670 | if (p.token_tags[p.tok_i] != tag) { | |
| 3655 | 3671 | return p.failMsg(.{ |
| 3656 | 3672 | .tag = .expected_token, |
| 3657 | .token = token, | |
| 3673 | .token = p.tok_i, | |
| 3658 | 3674 | .extra = .{ .expected_tag = tag }, |
| 3659 | 3675 | }); |
| 3660 | 3676 | } |
| 3661 | return token; | |
| 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 | } | |
| 3677 | return p.nextToken(); | |
| 3671 | 3678 | } |
| 3672 | 3679 | |
| 3673 | 3680 | fn expectSemicolon(p: *Parser, error_tag: AstError.Tag, recoverable: bool) Error!void { |
| ... | ... | @@ -3675,7 +3682,7 @@ const Parser = struct { |
| 3675 | 3682 | _ = p.nextToken(); |
| 3676 | 3683 | return; |
| 3677 | 3684 | } |
| 3678 | try p.warnExpectedAfter(error_tag); | |
| 3685 | try p.warn(error_tag); | |
| 3679 | 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 | 226 | \\}; |
| 227 | 227 | , &[_]Error{ |
| 228 | 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 | 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 | 5042 | test "zig fmt: error for invalid bit range" { |
| 5022 | 5043 | try testError( |
| 5023 | 5044 | \\var x: []align(0:0:0)u8 = bar; |
| ... | ... | @@ -5057,7 +5078,9 @@ test "recovery: block statements" { |
| 5057 | 5078 | \\ inline; |
| 5058 | 5079 | \\} |
| 5059 | 5080 | , &[_]Error{ |
| 5060 | .invalid_token, | |
| 5081 | .expected_expr, | |
| 5082 | .expected_semi_after_stmt, | |
| 5083 | .expected_statement, | |
| 5061 | 5084 | .expected_inlinable, |
| 5062 | 5085 | }); |
| 5063 | 5086 | } |
| ... | ... | @@ -5076,7 +5099,7 @@ test "recovery: missing comma" { |
| 5076 | 5099 | , &[_]Error{ |
| 5077 | 5100 | .expected_comma_after_switch_prong, |
| 5078 | 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 | 322 | } |
| 323 | 323 | |
| 324 | 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 | 2995 | const token_starts = file.tree.tokens.items(.start); |
| 2996 | 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 | 2999 | try file.tree.renderError(parse_err, msg.writer()); |
| 3000 | 3000 | const err_msg = try gpa.create(ErrorMsg); |
| 3001 | 3001 | err_msg.* = .{ |
| ... | ... | @@ -3006,14 +3006,25 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 3006 | 3006 | }, |
| 3007 | 3007 | .msg = msg.toOwnedSlice(), |
| 3008 | 3008 | }; |
| 3009 | if (token_tags[parse_err.token] == .invalid) { | |
| 3010 | const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token).len); | |
| 3011 | const byte_abs = token_starts[parse_err.token] + bad_off; | |
| 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 + @boolToInt(parse_err.token_is_prev)).len); | |
| 3011 | const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off; | |
| 3012 | 3012 | try mod.errNoteNonLazy(.{ |
| 3013 | 3013 | .file_scope = file, |
| 3014 | 3014 | .parent_decl_node = 0, |
| 3015 | 3015 | .lazy = .{ .byte_abs = byte_abs }, |
| 3016 | 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 | 3799 | }; |
| 3800 | 3800 | defer tree.deinit(gpa); |
| 3801 | 3801 | |
| 3802 | for (tree.errors) |parse_error| { | |
| 3803 | try printErrMsgToStdErr(gpa, arena, parse_error, tree, "<stdin>", color); | |
| 3804 | } | |
| 3802 | try printErrsMsgToStdErr(gpa, arena, tree.errors, tree, "<stdin>", color); | |
| 3805 | 3803 | var has_ast_error = false; |
| 3806 | 3804 | if (check_ast_flag) { |
| 3807 | 3805 | const Module = @import("Module.zig"); |
| ... | ... | @@ -3989,9 +3987,7 @@ fn fmtPathFile( |
| 3989 | 3987 | var tree = try std.zig.parse(fmt.gpa, source_code); |
| 3990 | 3988 | defer tree.deinit(fmt.gpa); |
| 3991 | 3989 | |
| 3992 | for (tree.errors) |parse_error| { | |
| 3993 | try printErrMsgToStdErr(fmt.gpa, fmt.arena, parse_error, tree, file_path, fmt.color); | |
| 3994 | } | |
| 3990 | try printErrsMsgToStdErr(fmt.gpa, fmt.arena, tree.errors, tree, file_path, fmt.color); | |
| 3995 | 3991 | if (tree.errors.len != 0) { |
| 3996 | 3992 | fmt.any_error = true; |
| 3997 | 3993 | return; |
| ... | ... | @@ -4071,66 +4067,95 @@ fn fmtPathFile( |
| 4071 | 4067 | } |
| 4072 | 4068 | } |
| 4073 | 4069 | |
| 4074 | fn printErrMsgToStdErr( | |
| 4070 | fn printErrsMsgToStdErr( | |
| 4075 | 4071 | gpa: mem.Allocator, |
| 4076 | 4072 | arena: mem.Allocator, |
| 4077 | parse_error: Ast.Error, | |
| 4073 | parse_errors: []const Ast.Error, | |
| 4078 | 4074 | tree: Ast, |
| 4079 | 4075 | path: []const u8, |
| 4080 | 4076 | color: Color, |
| 4081 | 4077 | ) !void { |
| 4082 | const lok_token = parse_error.token; | |
| 4083 | const token_tags = tree.tokens.items(.tag); | |
| 4084 | const start_loc = tree.tokenLocation(0, lok_token); | |
| 4085 | const source_line = tree.source[start_loc.line_start..start_loc.line_end]; | |
| 4086 | ||
| 4087 | var text_buf = std.ArrayList(u8).init(gpa); | |
| 4088 | defer text_buf.deinit(); | |
| 4089 | const writer = text_buf.writer(); | |
| 4090 | try tree.renderError(parse_error, writer); | |
| 4091 | const text = text_buf.items; | |
| 4092 | ||
| 4093 | var notes_buffer: [1]Compilation.AllErrors.Message = undefined; | |
| 4094 | var notes_len: usize = 0; | |
| 4095 | ||
| 4096 | if (token_tags[parse_error.token] == .invalid) { | |
| 4097 | const bad_off = @intCast(u32, tree.tokenSlice(parse_error.token).len); | |
| 4098 | const byte_offset = @intCast(u32, start_loc.line_start) + bad_off; | |
| 4099 | notes_buffer[notes_len] = .{ | |
| 4078 | var i: usize = 0; | |
| 4079 | while (i < parse_errors.len) : (i += 1) { | |
| 4080 | const parse_error = parse_errors[i]; | |
| 4081 | const lok_token = parse_error.token; | |
| 4082 | const token_tags = tree.tokens.items(.tag); | |
| 4083 | const start_loc = tree.tokenLocation(0, lok_token); | |
| 4084 | const source_line = tree.source[start_loc.line_start..start_loc.line_end]; | |
| 4085 | ||
| 4086 | var text_buf = std.ArrayList(u8).init(gpa); | |
| 4087 | defer text_buf.deinit(); | |
| 4088 | const writer = text_buf.writer(); | |
| 4089 | try tree.renderError(parse_error, writer); | |
| 4090 | const text = text_buf.items; | |
| 4091 | ||
| 4092 | var notes_buffer: [2]Compilation.AllErrors.Message = undefined; | |
| 4093 | var notes_len: usize = 0; | |
| 4094 | ||
| 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 | 4140 | .src = .{ |
| 4101 | 4141 | .src_path = path, |
| 4102 | .msg = try std.fmt.allocPrint(arena, "invalid byte: '{'}'", .{ | |
| 4103 | std.zig.fmtEscapes(tree.source[byte_offset..][0..1]), | |
| 4104 | }), | |
| 4105 | .byte_offset = byte_offset, | |
| 4142 | .msg = text, | |
| 4143 | .byte_offset = @intCast(u32, start_loc.line_start) + extra_offset, | |
| 4106 | 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 | 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); | |
| 4115 | const message: Compilation.AllErrors.Message = .{ | |
| 4116 | .src = .{ | |
| 4117 | .src_path = path, | |
| 4118 | .msg = text, | |
| 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 | }; | |
| 4151 | const ttyconf: std.debug.TTY.Config = switch (color) { | |
| 4152 | .auto => std.debug.detectTTYConfig(), | |
| 4153 | .on => .escape_codes, | |
| 4154 | .off => .no_color, | |
| 4155 | }; | |
| 4132 | 4156 | |
| 4133 | message.renderToStdErr(ttyconf); | |
| 4157 | message.renderToStdErr(ttyconf); | |
| 4158 | } | |
| 4134 | 4159 | } |
| 4135 | 4160 | |
| 4136 | 4161 | pub const info_zen = |
| ... | ... | @@ -4688,9 +4713,7 @@ pub fn cmdAstCheck( |
| 4688 | 4713 | file.tree_loaded = true; |
| 4689 | 4714 | defer file.tree.deinit(gpa); |
| 4690 | 4715 | |
| 4691 | for (file.tree.errors) |parse_error| { | |
| 4692 | try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, file.sub_file_path, color); | |
| 4693 | } | |
| 4716 | try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, file.sub_file_path, color); | |
| 4694 | 4717 | if (file.tree.errors.len != 0) { |
| 4695 | 4718 | process.exit(1); |
| 4696 | 4719 | } |
| ... | ... | @@ -4816,9 +4839,7 @@ pub fn cmdChangelist( |
| 4816 | 4839 | file.tree_loaded = true; |
| 4817 | 4840 | defer file.tree.deinit(gpa); |
| 4818 | 4841 | |
| 4819 | for (file.tree.errors) |parse_error| { | |
| 4820 | try printErrMsgToStdErr(gpa, arena, parse_error, file.tree, old_source_file, .auto); | |
| 4821 | } | |
| 4842 | try printErrsMsgToStdErr(gpa, arena, file.tree.errors, file.tree, old_source_file, .auto); | |
| 4822 | 4843 | if (file.tree.errors.len != 0) { |
| 4823 | 4844 | process.exit(1); |
| 4824 | 4845 | } |
| ... | ... | @@ -4855,9 +4876,7 @@ pub fn cmdChangelist( |
| 4855 | 4876 | var new_tree = try std.zig.parse(gpa, new_source); |
| 4856 | 4877 | defer new_tree.deinit(gpa); |
| 4857 | 4878 | |
| 4858 | for (new_tree.errors) |parse_error| { | |
| 4859 | try printErrMsgToStdErr(gpa, arena, parse_error, new_tree, new_source_file, .auto); | |
| 4860 | } | |
| 4879 | try printErrsMsgToStdErr(gpa, arena, new_tree.errors, new_tree, new_source_file, .auto); | |
| 4861 | 4880 | if (new_tree.errors.len != 0) { |
| 4862 | 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 | 7843 | bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 |
| 7844 | 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 | 7847 | array_type->data.array.child_type, source_node, |
| 7848 | 7848 | !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk && |
| 7849 | 7849 | (slice_ptr_type->data.pointer.sentinel == nullptr || |
| ... | ... | @@ -7851,6 +7851,14 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou |
| 7851 | 7851 | const_values_equal(ira->codegen, array_type->data.array.sentinel, |
| 7852 | 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 | 7862 | // If the pointers both have ABI align, it works. |
| 7855 | 7863 | // Or if the array length is 0, alignment doesn't matter. |
| 7856 | 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 | 8216 | ZigType *wanted_child = wanted_type->data.pointer.child_type; |
| 8209 | 8217 | bool const_ok = (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const); |
| 8210 | 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 | 8229 | Stage1AirInst *res = ir_analyze_struct_literal_to_array(ira, scope, source_node, value, anon_type, wanted_child); |
| 8214 | 8230 | if (res->value->type->id == ZigTypeIdPointer) |
| 8215 | 8231 | return res; |
| ... | ... | @@ -8241,6 +8257,13 @@ static Stage1AirInst *ir_analyze_cast(IrAnalyze *ira, Scope *scope, AstNode *sou |
| 8241 | 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 | 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 | 15091 | return ira->codegen->invalid_inst_gen; |
| 15069 | 15092 | if (actual_array_type->id != ZigTypeIdArray) { |
| 15070 | 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 | 15095 | buf_ptr(&actual_array_type->name))); |
| 15073 | 15096 | return ira->codegen->invalid_inst_gen; |
| 15074 | 15097 | } |
| ... | ... | @@ -17473,7 +17496,7 @@ static Stage1AirInst *ir_analyze_instruction_container_init_list(IrAnalyze *ira, |
| 17473 | 17496 | |
| 17474 | 17497 | if (is_slice(container_type)) { |
| 17475 | 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 | 17500 | buf_ptr(&container_type->name))); |
| 17478 | 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 | 86 | \\ _ = c; |
| 87 | 87 | \\} |
| 88 | 88 | , &[_][]const u8{ |
| 89 | "tmp.zig:2:31: error: expected type '[][]const u8', found '*const struct:2:31'", | |
| 90 | "tmp.zig:6:33: error: expected type '*[2][]const u8', found '*const struct:6:33'", | |
| 89 | "tmp.zig:2:31: error: cannot cast pointer to array literal to slice type '[][]const u8'", | |
| 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 | 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 | 97 | ctx.objErrStage1("@Type() union payload is undefined", |
| ... | ... | @@ -874,6 +877,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 874 | 877 | \\} |
| 875 | 878 | , &[_][]const u8{ |
| 876 | 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 | 884 | ctx.objErrStage1("non-extern function with var args", |
| ... | ... | @@ -1540,7 +1545,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1540 | 1545 | \\ std.debug.assert(bad_float < 1.0); |
| 1541 | 1546 | \\} |
| 1542 | 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 | 1551 | ctx.objErrStage1("invalid exponent in float literal - 1", |
| ... | ... | @@ -1549,7 +1554,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1549 | 1554 | \\ _ = bad; |
| 1550 | 1555 | \\} |
| 1551 | 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 | 1558 | "tmp.zig:2:28: note: invalid byte: 'a'", |
| 1554 | 1559 | }); |
| 1555 | 1560 | |
| ... | ... | @@ -1559,7 +1564,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1559 | 1564 | \\ _ = bad; |
| 1560 | 1565 | \\} |
| 1561 | 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 | 1568 | "tmp.zig:2:29: note: invalid byte: 'F'", |
| 1564 | 1569 | }); |
| 1565 | 1570 | |
| ... | ... | @@ -1569,7 +1574,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1569 | 1574 | \\ _ = bad; |
| 1570 | 1575 | \\} |
| 1571 | 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 | 1578 | "tmp.zig:2:23: note: invalid byte: '_'", |
| 1574 | 1579 | }); |
| 1575 | 1580 | |
| ... | ... | @@ -1579,7 +1584,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1579 | 1584 | \\ _ = bad; |
| 1580 | 1585 | \\} |
| 1581 | 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 | 1588 | "tmp.zig:2:23: note: invalid byte: '.'", |
| 1584 | 1589 | }); |
| 1585 | 1590 | |
| ... | ... | @@ -1589,7 +1594,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1589 | 1594 | \\ _ = bad; |
| 1590 | 1595 | \\} |
| 1591 | 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 | 1598 | "tmp.zig:2:25: note: invalid byte: ';'", |
| 1594 | 1599 | }); |
| 1595 | 1600 | |
| ... | ... | @@ -1599,7 +1604,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1599 | 1604 | \\ _ = bad; |
| 1600 | 1605 | \\} |
| 1601 | 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 | 1608 | "tmp.zig:2:25: note: invalid byte: '_'", |
| 1604 | 1609 | }); |
| 1605 | 1610 | |
| ... | ... | @@ -1609,7 +1614,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1609 | 1614 | \\ _ = bad; |
| 1610 | 1615 | \\} |
| 1611 | 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 | 1618 | "tmp.zig:2:26: note: invalid byte: '_'", |
| 1614 | 1619 | }); |
| 1615 | 1620 | |
| ... | ... | @@ -1619,7 +1624,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1619 | 1624 | \\ _ = bad; |
| 1620 | 1625 | \\} |
| 1621 | 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 | 1628 | "tmp.zig:2:26: note: invalid byte: '_'", |
| 1624 | 1629 | }); |
| 1625 | 1630 | |
| ... | ... | @@ -1629,7 +1634,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1629 | 1634 | \\ _ = bad; |
| 1630 | 1635 | \\} |
| 1631 | 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 | 1638 | "tmp.zig:2:28: note: invalid byte: ';'", |
| 1634 | 1639 | }); |
| 1635 | 1640 | |
| ... | ... | @@ -1639,7 +1644,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1639 | 1644 | \\ _ = bad; |
| 1640 | 1645 | \\} |
| 1641 | 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 | 1648 | "tmp.zig:2:23: note: invalid byte: '_'", |
| 1644 | 1649 | }); |
| 1645 | 1650 | |
| ... | ... | @@ -1649,7 +1654,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1649 | 1654 | \\ _ = bad; |
| 1650 | 1655 | \\} |
| 1651 | 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 | 1658 | "tmp.zig:2:25: note: invalid byte: '_'", |
| 1654 | 1659 | }); |
| 1655 | 1660 | |
| ... | ... | @@ -1659,7 +1664,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1659 | 1664 | \\ _ = bad; |
| 1660 | 1665 | \\} |
| 1661 | 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 | 1668 | "tmp.zig:2:28: note: invalid byte: '_'", |
| 1664 | 1669 | }); |
| 1665 | 1670 | |
| ... | ... | @@ -1669,7 +1674,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1669 | 1674 | \\ _ = bad; |
| 1670 | 1675 | \\} |
| 1671 | 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 | 1678 | "tmp.zig:2:23: note: invalid byte: 'x'", |
| 1674 | 1679 | }); |
| 1675 | 1680 | |
| ... | ... | @@ -1679,7 +1684,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1679 | 1684 | \\ _ = bad; |
| 1680 | 1685 | \\} |
| 1681 | 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 | 1688 | "tmp.zig:2:23: note: invalid byte: '_'", |
| 1684 | 1689 | }); |
| 1685 | 1690 | |
| ... | ... | @@ -1689,7 +1694,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1689 | 1694 | \\ _ = bad; |
| 1690 | 1695 | \\} |
| 1691 | 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 | 1698 | "tmp.zig:2:27: note: invalid byte: 'p'", |
| 1694 | 1699 | }); |
| 1695 | 1700 | |
| ... | ... | @@ -1699,7 +1704,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1699 | 1704 | \\ _ = bad; |
| 1700 | 1705 | \\} |
| 1701 | 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 | 1708 | "tmp.zig:2:26: note: invalid byte: ';'", |
| 1704 | 1709 | }); |
| 1705 | 1710 | |
| ... | ... | @@ -1709,7 +1714,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1709 | 1714 | \\ _ = bad; |
| 1710 | 1715 | \\} |
| 1711 | 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 | 1718 | "tmp.zig:2:28: note: invalid byte: ';'", |
| 1714 | 1719 | }); |
| 1715 | 1720 | |
| ... | ... | @@ -1719,7 +1724,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1719 | 1724 | \\ _ = bad; |
| 1720 | 1725 | \\} |
| 1721 | 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 | 1728 | "tmp.zig:2:28: note: invalid byte: ';'", |
| 1724 | 1729 | }); |
| 1725 | 1730 | |
| ... | ... | @@ -1729,7 +1734,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1729 | 1734 | \\ _ = bad; |
| 1730 | 1735 | \\} |
| 1731 | 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 | 1738 | "tmp.zig:2:28: note: invalid byte: ';'", |
| 1734 | 1739 | }); |
| 1735 | 1740 | |
| ... | ... | @@ -1962,7 +1967,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1962 | 1967 | \\ _ = geo_data; |
| 1963 | 1968 | \\} |
| 1964 | 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 | 1973 | ctx.objErrStage1("slicing of global undefined pointer", |
| ... | ... | @@ -2171,7 +2176,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 2171 | 2176 | \\ _ = x; |
| 2172 | 2177 | \\} |
| 2173 | 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 | 2182 | ctx.objErrStage1("bad alignment type", |
| ... | ... | @@ -2537,7 +2542,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 2537 | 2542 | \\ _ = x; |
| 2538 | 2543 | \\} |
| 2539 | 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 | 2548 | ctx.objErrStage1("slice passed as array init type", |
| ... | ... | @@ -2546,7 +2551,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 2546 | 2551 | \\ _ = x; |
| 2547 | 2552 | \\} |
| 2548 | 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 | 2557 | ctx.objErrStage1("inferred array size invalid here", |
| ... | ... | @@ -3493,7 +3498,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 3493 | 3498 | \\ _ = sliceA; |
| 3494 | 3499 | \\} |
| 3495 | 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 | 3505 | ctx.objErrStage1("deref slice and get len field", |
| ... | ... | @@ -4865,11 +4871,11 @@ pub fn addCases(ctx: *TestContext) !void { |
| 4865 | 4871 | \\export fn entry() void { |
| 4866 | 4872 | \\ while(true) {} |
| 4867 | 4873 | \\ var good = {}; |
| 4868 | \\ while(true) ({}) | |
| 4874 | \\ while(true) 1 | |
| 4869 | 4875 | \\ var bad = {}; |
| 4870 | 4876 | \\} |
| 4871 | 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 | 4881 | ctx.objErrStage1("implicit semicolon - while expression", |
| ... | ... | @@ -5733,7 +5739,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 5733 | 5739 | \\const foo = "a |
| 5734 | 5740 | \\b"; |
| 5735 | 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 | 5743 | "tmp.zig:1:15: note: invalid byte: '\\n'", |
| 5738 | 5744 | }); |
| 5739 | 5745 | |
| ... | ... | @@ -7638,7 +7644,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 7638 | 7644 | \\ const a = '\U1234'; |
| 7639 | 7645 | \\} |
| 7640 | 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 | 7648 | "tmp.zig:2:18: note: invalid byte: '1'", |
| 7643 | 7649 | }); |
| 7644 | 7650 | |
| ... | ... | @@ -7654,7 +7660,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 7654 | 7660 | "fn foo() bool {\r\n" ++ |
| 7655 | 7661 | " return true;\r\n" ++ |
| 7656 | 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 | 7664 | "tmp.zig:1:1: note: invalid byte: '\\xff'", |
| 7659 | 7665 | }); |
| 7660 | 7666 | |
| ... | ... | @@ -8717,7 +8723,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 8717 | 8723 | \\ comptime ignore(@typeInfo(MyStruct).Struct.fields[0]); |
| 8718 | 8724 | \\} |
| 8719 | 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 | 8730 | ctx.objErrStage1("integer underflow error", |
test/stage2/cbe.zig+1-1| ... | ... | @@ -693,7 +693,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 693 | 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 | 699 | // Redundant non-exhaustive enum mark. |