| ... | @@ -442,6 +442,49 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block | ... | @@ -442,6 +442,49 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block |
| 442 | try blockExprStmts(mod, parent_scope, &block_node.base, block_node.statements()); | 442 | try blockExprStmts(mod, parent_scope, &block_node.base, block_node.statements()); |
| 443 | } | 443 | } |
| 444 | | 444 | |
| | 445 | fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIndex) !void { |
| | 446 | // Look for the label in the scope. |
| | 447 | var scope = parent_scope; |
| | 448 | while (true) { |
| | 449 | switch (scope.tag) { |
| | 450 | .gen_zir => { |
| | 451 | const gen_zir = scope.cast(Scope.GenZIR).?; |
| | 452 | if (gen_zir.label) |prev_label| { |
| | 453 | if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) { |
| | 454 | const tree = parent_scope.tree(); |
| | 455 | const label_src = tree.token_locs[label].start; |
| | 456 | const prev_label_src = tree.token_locs[prev_label.token].start; |
| | 457 | |
| | 458 | const label_name = try mod.identifierTokenString(parent_scope, label); |
| | 459 | const msg = msg: { |
| | 460 | const msg = try mod.errMsg( |
| | 461 | parent_scope, |
| | 462 | label_src, |
| | 463 | "redefinition of label '{s}'", |
| | 464 | .{label_name}, |
| | 465 | ); |
| | 466 | errdefer msg.destroy(mod.gpa); |
| | 467 | try mod.errNote( |
| | 468 | parent_scope, |
| | 469 | prev_label_src, |
| | 470 | msg, |
| | 471 | "previous definition is here", |
| | 472 | .{}, |
| | 473 | ); |
| | 474 | break :msg msg; |
| | 475 | }; |
| | 476 | return mod.failWithOwnedErrorMsg(parent_scope, msg); |
| | 477 | } |
| | 478 | } |
| | 479 | scope = gen_zir.parent; |
| | 480 | }, |
| | 481 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| | 482 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| | 483 | else => return, |
| | 484 | } |
| | 485 | } |
| | 486 | } |
| | 487 | |
| 445 | fn labeledBlockExpr( | 488 | fn labeledBlockExpr( |
| 446 | mod: *Module, | 489 | mod: *Module, |
| 447 | parent_scope: *Scope, | 490 | parent_scope: *Scope, |
| ... | @@ -457,6 +500,8 @@ fn labeledBlockExpr( | ... | @@ -457,6 +500,8 @@ fn labeledBlockExpr( |
| 457 | const tree = parent_scope.tree(); | 500 | const tree = parent_scope.tree(); |
| 458 | const src = tree.token_locs[block_node.lbrace].start; | 501 | const src = tree.token_locs[block_node.lbrace].start; |
| 459 | | 502 | |
| | 503 | try checkLabelRedefinition(mod, parent_scope, block_node.label); |
| | 504 | |
| 460 | // Create the Block ZIR instruction so that we can put it into the GenZIR struct | 505 | // Create the Block ZIR instruction so that we can put it into the GenZIR struct |
| 461 | // so that break statements can reference it. | 506 | // so that break statements can reference it. |
| 462 | const gen_zir = parent_scope.getGenZIR(); | 507 | const gen_zir = parent_scope.getGenZIR(); |
| ... | @@ -560,14 +605,30 @@ fn varDecl( | ... | @@ -560,14 +605,30 @@ fn varDecl( |
| 560 | .local_val => { | 605 | .local_val => { |
| 561 | const local_val = s.cast(Scope.LocalVal).?; | 606 | const local_val = s.cast(Scope.LocalVal).?; |
| 562 | if (mem.eql(u8, local_val.name, ident_name)) { | 607 | if (mem.eql(u8, local_val.name, ident_name)) { |
| 563 | return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); | 608 | const msg = msg: { |
| | 609 | const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{ |
| | 610 | ident_name, |
| | 611 | }); |
| | 612 | errdefer msg.destroy(mod.gpa); |
| | 613 | try mod.errNote(scope, local_val.inst.src, msg, "previous definition is here", .{}); |
| | 614 | break :msg msg; |
| | 615 | }; |
| | 616 | return mod.failWithOwnedErrorMsg(scope, msg); |
| 564 | } | 617 | } |
| 565 | s = local_val.parent; | 618 | s = local_val.parent; |
| 566 | }, | 619 | }, |
| 567 | .local_ptr => { | 620 | .local_ptr => { |
| 568 | const local_ptr = s.cast(Scope.LocalPtr).?; | 621 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 569 | if (mem.eql(u8, local_ptr.name, ident_name)) { | 622 | if (mem.eql(u8, local_ptr.name, ident_name)) { |
| 570 | return mod.fail(scope, name_src, "redefinition of '{s}'", .{ident_name}); | 623 | const msg = msg: { |
| | 624 | const msg = try mod.errMsg(scope, name_src, "redefinition of '{s}'", .{ |
| | 625 | ident_name, |
| | 626 | }); |
| | 627 | errdefer msg.destroy(mod.gpa); |
| | 628 | try mod.errNote(scope, local_ptr.ptr.src, msg, "previous definition is here", .{}); |
| | 629 | break :msg msg; |
| | 630 | }; |
| | 631 | return mod.failWithOwnedErrorMsg(scope, msg); |
| 571 | } | 632 | } |
| 572 | s = local_ptr.parent; | 633 | s = local_ptr.parent; |
| 573 | }, | 634 | }, |
| ... | @@ -1166,8 +1227,10 @@ fn orelseCatchExpr( | ... | @@ -1166,8 +1227,10 @@ fn orelseCatchExpr( |
| 1166 | return rlWrapPtr(mod, scope, rl, &block.base); | 1227 | return rlWrapPtr(mod, scope, rl, &block.base); |
| 1167 | } | 1228 | } |
| 1168 | | 1229 | |
| 1169 | /// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating. | 1230 | /// Return whether the identifier names of two tokens are equal. Resolves @"" |
| 1170 | /// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used. | 1231 | /// tokens without allocating. |
| | 1232 | /// OK in theory it could do it without allocating. This implementation |
| | 1233 | /// allocates when the @"" form is used. |
| 1171 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { | 1234 | fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { |
| 1172 | const ident_name_1 = try mod.identifierTokenString(scope, token1); | 1235 | const ident_name_1 = try mod.identifierTokenString(scope, token1); |
| 1173 | const ident_name_2 = try mod.identifierTokenString(scope, token2); | 1236 | const ident_name_2 = try mod.identifierTokenString(scope, token2); |
| ... | @@ -1514,6 +1577,10 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1514,6 +1577,10 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1514 | } | 1577 | } |
| 1515 | } | 1578 | } |
| 1516 | | 1579 | |
| | 1580 | if (while_node.label) |label| { |
| | 1581 | try checkLabelRedefinition(mod, scope, label); |
| | 1582 | } |
| | 1583 | |
| 1517 | if (while_node.inline_token) |tok| | 1584 | if (while_node.inline_token) |tok| |
| 1518 | return mod.failTok(scope, tok, "TODO inline while", .{}); | 1585 | return mod.failTok(scope, tok, "TODO inline while", .{}); |
| 1519 | | 1586 | |
| ... | @@ -1649,7 +1716,16 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1649,7 +1716,16 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1649 | return &while_block.base; | 1716 | return &while_block.base; |
| 1650 | } | 1717 | } |
| 1651 | | 1718 | |
| 1652 | fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) InnerError!*zir.Inst { | 1719 | fn forExpr( |
| | 1720 | mod: *Module, |
| | 1721 | scope: *Scope, |
| | 1722 | rl: ResultLoc, |
| | 1723 | for_node: *ast.Node.For, |
| | 1724 | ) InnerError!*zir.Inst { |
| | 1725 | if (for_node.label) |label| { |
| | 1726 | try checkLabelRedefinition(mod, scope, label); |
| | 1727 | } |
| | 1728 | |
| 1653 | if (for_node.inline_token) |tok| | 1729 | if (for_node.inline_token) |tok| |
| 1654 | return mod.failTok(scope, tok, "TODO inline for", .{}); | 1730 | return mod.failTok(scope, tok, "TODO inline for", .{}); |
| 1655 | | 1731 | |
| ... | @@ -1928,14 +2004,17 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1928,14 +2004,17 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1928 | // Check for else/_ prong, those are handled last. | 2004 | // Check for else/_ prong, those are handled last. |
| 1929 | if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { | 2005 | if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { |
| 1930 | if (else_src) |src| { | 2006 | if (else_src) |src| { |
| 1931 | const msg = try mod.errMsg( | 2007 | const msg = msg: { |
| 1932 | scope, | 2008 | const msg = try mod.errMsg( |
| 1933 | case_src, | 2009 | scope, |
| 1934 | "multiple else prongs in switch expression", | 2010 | case_src, |
| 1935 | .{}, | 2011 | "multiple else prongs in switch expression", |
| 1936 | ); | 2012 | .{}, |
| 1937 | errdefer msg.destroy(mod.gpa); | 2013 | ); |
| 1938 | try mod.errNote(scope, src, msg, "previous else prong is here", .{}); | 2014 | errdefer msg.destroy(mod.gpa); |
| | 2015 | try mod.errNote(scope, src, msg, "previous else prong is here", .{}); |
| | 2016 | break :msg msg; |
| | 2017 | }; |
| 1939 | return mod.failWithOwnedErrorMsg(scope, msg); | 2018 | return mod.failWithOwnedErrorMsg(scope, msg); |
| 1940 | } | 2019 | } |
| 1941 | else_src = case_src; | 2020 | else_src = case_src; |
| ... | @@ -1945,14 +2024,17 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1945,14 +2024,17 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1945 | mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) | 2024 | mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) |
| 1946 | { | 2025 | { |
| 1947 | if (underscore_src) |src| { | 2026 | if (underscore_src) |src| { |
| 1948 | const msg = try mod.errMsg( | 2027 | const msg = msg: { |
| 1949 | scope, | 2028 | const msg = try mod.errMsg( |
| 1950 | case_src, | 2029 | scope, |
| 1951 | "multiple '_' prongs in switch expression", | 2030 | case_src, |
| 1952 | .{}, | 2031 | "multiple '_' prongs in switch expression", |
| 1953 | ); | 2032 | .{}, |
| 1954 | errdefer msg.destroy(mod.gpa); | 2033 | ); |
| 1955 | try mod.errNote(scope, src, msg, "previous '_' prong is here", .{}); | 2034 | errdefer msg.destroy(mod.gpa); |
| | 2035 | try mod.errNote(scope, src, msg, "previous '_' prong is here", .{}); |
| | 2036 | break :msg msg; |
| | 2037 | }; |
| 1956 | return mod.failWithOwnedErrorMsg(scope, msg); | 2038 | return mod.failWithOwnedErrorMsg(scope, msg); |
| 1957 | } | 2039 | } |
| 1958 | underscore_src = case_src; | 2040 | underscore_src = case_src; |
| ... | @@ -1962,15 +2044,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node | ... | @@ -1962,15 +2044,18 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1962 | | 2044 | |
| 1963 | if (else_src) |some_else| { | 2045 | if (else_src) |some_else| { |
| 1964 | if (underscore_src) |some_underscore| { | 2046 | if (underscore_src) |some_underscore| { |
| 1965 | const msg = try mod.errMsg( | 2047 | const msg = msg: { |
| 1966 | scope, | 2048 | const msg = try mod.errMsg( |
| 1967 | switch_src, | 2049 | scope, |
| 1968 | "else and '_' prong in switch expression", | 2050 | switch_src, |
| 1969 | .{}, | 2051 | "else and '_' prong in switch expression", |
| 1970 | ); | 2052 | .{}, |
| 1971 | errdefer msg.destroy(mod.gpa); | 2053 | ); |
| 1972 | try mod.errNote(scope, some_else, msg, "else prong is here", .{}); | 2054 | errdefer msg.destroy(mod.gpa); |
| 1973 | try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{}); | 2055 | try mod.errNote(scope, some_else, msg, "else prong is here", .{}); |
| | 2056 | try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{}); |
| | 2057 | break :msg msg; |
| | 2058 | }; |
| 1974 | return mod.failWithOwnedErrorMsg(scope, msg); | 2059 | return mod.failWithOwnedErrorMsg(scope, msg); |
| 1975 | } | 2060 | } |
| 1976 | } | 2061 | } |