mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 09:44:52 +01:00
This commit aims to simplify and de-duplicate the logic required for semantically analyzing `switch` expressions. The core logic has been moved to `analyzeSwitchBlock`, `resolveSwitchBlock` and `finishSwitchBlock` and has been rewritten around the new iterator-based API exposed by `Zir.UnwrappedSwitchBlock`. All validation logic and switch prong item resolution have been moved to `validateSwitchBlock`, which produces a `ValidatedSwitchBlock` containing all the necessary information for further analysis. `Zir.UnwrappedSwitchBlock`, `ValidatedSwitchBlock` and `SwitchOperand` replace `SwitchProngAnalysis` while adding more flexibility, mainly for better integration with `switch_block_err_union`. `analyzeSwitchBlock` has an explicit code path for OPV types which lowers them to either a `block`-`br` or a `loop`-`repeat` construct instead of a switch. Backends expect `switch` to actually have an operand that exists at runtime, so this is a bug fix and avoids further special cases in the rest of the switch logic. `resolveSwitchBlock` and `finishSwitchBr` exclusively deal with operands which can have more than one value, at comptime and at runtime respectively. This commit also reworks `RangeSet` to be an unmanaged container and adds `Air.SwitchBr.BranchHints` to offload some complexity from Sema to there and save a few bytes of memory in the process. Additionally, some new features have been implemented: - decl literals and everything else requiring a result type (`@enumFromInt`!) may now be used as switch prong items - union tag captures are now allowed for all prongs, not just `inline` ones - switch prongs may contain errors which are not in the error set being switched on, if these prongs contain `=> comptime unreachable` and some bugs have been fixed: - lots of issues with switching on OPV types are now fixed - the rules around unreachable `else` prongs when switching on errors now apply to *any* switch on an error, not just to `switch_block_err_union`, and are applied properly based on the AST - switching on `void` no longer requires an `else` prong unconditionally - lazy values are properly resolved before any comparisons with prong items - evaluation order between all kinds of switch statements is now the same, with or without label
46 lines
878 B
Zig
46 lines
878 B
Zig
const E = enum { a, b, c };
|
|
var my_e: E = .a;
|
|
|
|
export fn f0() void {
|
|
switch (my_e) {
|
|
.a => {},
|
|
.b => {},
|
|
.x => {},
|
|
.c => {},
|
|
}
|
|
}
|
|
|
|
export fn f1() void {
|
|
switch (my_e) {
|
|
else => {},
|
|
.x, .y => {},
|
|
}
|
|
}
|
|
|
|
export fn f2() void {
|
|
switch (my_e) {
|
|
else => {},
|
|
.a => {},
|
|
.x, .y => {},
|
|
.b => {},
|
|
}
|
|
}
|
|
|
|
export fn f3() void {
|
|
switch (my_e) {
|
|
.a, .b => {},
|
|
.x, .y => {},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
// error
|
|
//
|
|
// :8:10: error: enum 'tmp.E' has no member named 'x'
|
|
// :1:11: note: enum declared here
|
|
// :16:10: error: enum 'tmp.E' has no member named 'x'
|
|
// :1:11: note: enum declared here
|
|
// :24:10: error: enum 'tmp.E' has no member named 'x'
|
|
// :1:11: note: enum declared here
|
|
// :32:10: error: enum 'tmp.E' has no member named 'x'
|
|
// :1:11: note: enum declared here
|