| ... | @@ -60,6 +60,7 @@ const InnerError = Module.InnerError; | ... | @@ -60,6 +60,7 @@ const InnerError = Module.InnerError; |
| 60 | const Decl = Module.Decl; | 60 | const Decl = Module.Decl; |
| 61 | const LazySrcLoc = Module.LazySrcLoc; | 61 | const LazySrcLoc = Module.LazySrcLoc; |
| 62 | const RangeSet = @import("RangeSet.zig"); | 62 | const RangeSet = @import("RangeSet.zig"); |
| | 63 | const AstGen = @import("AstGen.zig"); |
| 63 | | 64 | |
| 64 | const ValueSrcMap = std.HashMap(Value, LazySrcLoc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage); | 65 | const ValueSrcMap = std.HashMap(Value, LazySrcLoc, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage); |
| 65 | | 66 | |
| ... | @@ -419,19 +420,27 @@ fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.I | ... | @@ -419,19 +420,27 @@ fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.I |
| 419 | | 420 | |
| 420 | fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !Value { | 421 | fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !Value { |
| 421 | return (try sema.resolveDefinedValue(block, src, base)) orelse | 422 | return (try sema.resolveDefinedValue(block, src, base)) orelse |
| 422 | return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{}); | 423 | return sema.failWithNeededComptime(block, src); |
| 423 | } | 424 | } |
| 424 | | 425 | |
| 425 | fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value { | 426 | fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value { |
| 426 | if (base.value()) |val| { | 427 | if (base.value()) |val| { |
| 427 | if (val.isUndef()) { | 428 | if (val.isUndef()) { |
| 428 | return sema.mod.fail(&block.base, src, "use of undefined value here causes undefined behavior", .{}); | 429 | return sema.failWithUseOfUndef(block, src); |
| 429 | } | 430 | } |
| 430 | return val; | 431 | return val; |
| 431 | } | 432 | } |
| 432 | return null; | 433 | return null; |
| 433 | } | 434 | } |
| 434 | | 435 | |
| | 436 | fn failWithNeededComptime(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError { |
| | 437 | return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{}); |
| | 438 | } |
| | 439 | |
| | 440 | fn failWithUseOfUndef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) InnerError { |
| | 441 | return sema.mod.fail(&block.base, src, "use of undefined value here causes undefined behavior", .{}); |
| | 442 | } |
| | 443 | |
| 435 | /// Appropriate to call when the coercion has already been done by result | 444 | /// Appropriate to call when the coercion has already been done by result |
| 436 | /// location semantics. Asserts the value fits in the provided `Int` type. | 445 | /// location semantics. Asserts the value fits in the provided `Int` type. |
| 437 | /// Only supports `Int` types 64 bits or less. | 446 | /// Only supports `Int` types 64 bits or less. |
| ... | @@ -2368,7 +2377,7 @@ fn analyzeSwitch( | ... | @@ -2368,7 +2377,7 @@ fn analyzeSwitch( |
| 2368 | | 2377 | |
| 2369 | var extra_index: usize = special.end; | 2378 | var extra_index: usize = special.end; |
| 2370 | { | 2379 | { |
| 2371 | var scalar_i: usize = 0; | 2380 | var scalar_i: u32 = 0; |
| 2372 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 2381 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 2373 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 2382 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2374 | extra_index += 1; | 2383 | extra_index += 1; |
| ... | @@ -2382,11 +2391,12 @@ fn analyzeSwitch( | ... | @@ -2382,11 +2391,12 @@ fn analyzeSwitch( |
| 2382 | &range_set, | 2391 | &range_set, |
| 2383 | item_ref, | 2392 | item_ref, |
| 2384 | src_node_offset, | 2393 | src_node_offset, |
| | 2394 | .{ .scalar = scalar_i }, |
| 2385 | ); | 2395 | ); |
| 2386 | } | 2396 | } |
| 2387 | } | 2397 | } |
| 2388 | { | 2398 | { |
| 2389 | var multi_i: usize = 0; | 2399 | var multi_i: u32 = 0; |
| 2390 | while (multi_i < multi_cases_len) : (multi_i += 1) { | 2400 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| 2391 | const items_len = sema.code.extra[extra_index]; | 2401 | const items_len = sema.code.extra[extra_index]; |
| 2392 | extra_index += 1; | 2402 | extra_index += 1; |
| ... | @@ -2397,16 +2407,17 @@ fn analyzeSwitch( | ... | @@ -2397,16 +2407,17 @@ fn analyzeSwitch( |
| 2397 | const items = sema.code.refSlice(extra_index, items_len); | 2407 | const items = sema.code.refSlice(extra_index, items_len); |
| 2398 | extra_index += items_len; | 2408 | extra_index += items_len; |
| 2399 | | 2409 | |
| 2400 | for (items) |item_ref| { | 2410 | for (items) |item_ref, item_i| { |
| 2401 | try sema.validateSwitchItem( | 2411 | try sema.validateSwitchItem( |
| 2402 | block, | 2412 | block, |
| 2403 | &range_set, | 2413 | &range_set, |
| 2404 | item_ref, | 2414 | item_ref, |
| 2405 | src_node_offset, | 2415 | src_node_offset, |
| | 2416 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 2406 | ); | 2417 | ); |
| 2407 | } | 2418 | } |
| 2408 | | 2419 | |
| 2409 | var range_i: usize = 0; | 2420 | var range_i: u32 = 0; |
| 2410 | while (range_i < ranges_len) : (range_i += 1) { | 2421 | while (range_i < ranges_len) : (range_i += 1) { |
| 2411 | const item_first = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); | 2422 | const item_first = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2412 | extra_index += 1; | 2423 | extra_index += 1; |
| ... | @@ -2419,6 +2430,7 @@ fn analyzeSwitch( | ... | @@ -2419,6 +2430,7 @@ fn analyzeSwitch( |
| 2419 | item_first, | 2430 | item_first, |
| 2420 | item_last, | 2431 | item_last, |
| 2421 | src_node_offset, | 2432 | src_node_offset, |
| | 2433 | .{ .range = .{ .prong = multi_i, .item = range_i } }, |
| 2422 | ); | 2434 | ); |
| 2423 | } | 2435 | } |
| 2424 | | 2436 | |
| ... | @@ -2723,8 +2735,9 @@ fn analyzeSwitch( | ... | @@ -2723,8 +2735,9 @@ fn analyzeSwitch( |
| 2723 | extra_index += body_len; | 2735 | extra_index += body_len; |
| 2724 | | 2736 | |
| 2725 | case_block.instructions.shrinkRetainingCapacity(0); | 2737 | case_block.instructions.shrinkRetainingCapacity(0); |
| 2726 | const item = try sema.resolveInst(item_ref); | 2738 | // We validate these above; these two calls are guaranteed to succeed. |
| 2727 | const item_val = try sema.resolveConstValue(&case_block, item.src, item); | 2739 | const item = sema.resolveInst(item_ref) catch unreachable; |
| | 2740 | const item_val = sema.resolveConstValue(&case_block, .unneeded, item) catch unreachable; |
| 2728 | | 2741 | |
| 2729 | _ = try sema.analyzeBody(&case_block, body); | 2742 | _ = try sema.analyzeBody(&case_block, body); |
| 2730 | | 2743 | |
| ... | @@ -2836,48 +2849,133 @@ fn analyzeSwitch( | ... | @@ -2836,48 +2849,133 @@ fn analyzeSwitch( |
| 2836 | prev_condbr = new_condbr; | 2849 | prev_condbr = new_condbr; |
| 2837 | } | 2850 | } |
| 2838 | | 2851 | |
| 2839 | case_block.instructions.shrinkRetainingCapacity(0); | 2852 | const final_else_body: Body = blk: { |
| 2840 | _ = try sema.analyzeBody(&case_block, special.body); | 2853 | if (special.body.len != 0) { |
| 2841 | const else_body: Body = .{ | 2854 | case_block.instructions.shrinkRetainingCapacity(0); |
| 2842 | .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items), | 2855 | _ = try sema.analyzeBody(&case_block, special.body); |
| 2843 | }; | 2856 | const else_body: Body = .{ |
| 2844 | first_condbr.else_body = else_body; | 2857 | .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items), |
| 2845 | | 2858 | }; |
| 2846 | const final_else_body: Body = .{ | 2859 | if (prev_condbr != null) { |
| 2847 | .instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&first_condbr.base}), | 2860 | first_condbr.else_body = else_body; |
| | 2861 | break :blk .{ |
| | 2862 | .instructions = try sema.arena.dupe(*Inst, &[1]*Inst{&first_condbr.base}), |
| | 2863 | }; |
| | 2864 | } else { |
| | 2865 | break :blk else_body; |
| | 2866 | } |
| | 2867 | } else { |
| | 2868 | break :blk .{ .instructions = &.{} }; |
| | 2869 | } |
| 2848 | }; | 2870 | }; |
| 2849 | | 2871 | |
| 2850 | _ = try child_block.addSwitchBr(src, operand, cases, final_else_body); | 2872 | _ = try child_block.addSwitchBr(src, operand, cases, final_else_body); |
| 2851 | return sema.analyzeBlockBody(block, &child_block, merges); | 2873 | return sema.analyzeBlockBody(block, &child_block, merges); |
| 2852 | } | 2874 | } |
| 2853 | | 2875 | |
| | 2876 | fn validateSwitchRange( |
| | 2877 | sema: *Sema, |
| | 2878 | block: *Scope.Block, |
| | 2879 | range_set: *RangeSet, |
| | 2880 | first_ref: zir.Inst.Ref, |
| | 2881 | last_ref: zir.Inst.Ref, |
| | 2882 | src_node_offset: i32, |
| | 2883 | switch_prong_src: AstGen.SwitchProngSrc, |
| | 2884 | ) InnerError!void { |
| | 2885 | const first = try sema.resolveInst(first_ref); |
| | 2886 | const last = try sema.resolveInst(last_ref); |
| | 2887 | // We have to avoid the helper functions here because we cannot construct a LazySrcLoc |
| | 2888 | // because we only have the switch AST node. Only if we know for sure we need to report |
| | 2889 | // a compile error do we resolve the full source locations. |
| | 2890 | const first_val = val: { |
| | 2891 | if (last.value()) |val| { |
| | 2892 | if (val.isUndef()) { |
| | 2893 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .first); |
| | 2894 | return sema.failWithUseOfUndef(block, src); |
| | 2895 | } |
| | 2896 | break :val val; |
| | 2897 | } |
| | 2898 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .first); |
| | 2899 | return sema.failWithNeededComptime(block, src); |
| | 2900 | }; |
| | 2901 | const last_val = val: { |
| | 2902 | if (first.value()) |val| { |
| | 2903 | if (val.isUndef()) { |
| | 2904 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .last); |
| | 2905 | return sema.failWithUseOfUndef(block, src); |
| | 2906 | } |
| | 2907 | break :val val; |
| | 2908 | } |
| | 2909 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .last); |
| | 2910 | return sema.failWithNeededComptime(block, src); |
| | 2911 | }; |
| | 2912 | const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src); |
| | 2913 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| | 2914 | } |
| | 2915 | |
| 2854 | fn validateSwitchItem( | 2916 | fn validateSwitchItem( |
| 2855 | sema: *Sema, | 2917 | sema: *Sema, |
| 2856 | block: *Scope.Block, | 2918 | block: *Scope.Block, |
| 2857 | range_set: *RangeSet, | 2919 | range_set: *RangeSet, |
| 2858 | item_ref: zir.Inst.Ref, | 2920 | item_ref: zir.Inst.Ref, |
| 2859 | src_node_offset: i32, | 2921 | src_node_offset: i32, |
| | 2922 | switch_prong_src: AstGen.SwitchProngSrc, |
| 2860 | ) InnerError!void { | 2923 | ) InnerError!void { |
| 2861 | @panic("TODO"); | 2924 | const item = try sema.resolveInst(item_ref); |
| | 2925 | // We have to avoid the helper functions here because we cannot construct a LazySrcLoc |
| | 2926 | // because we only have the switch AST node. Only if we know for sure we need to report |
| | 2927 | // a compile error do we resolve the full source locations. |
| | 2928 | const value = val: { |
| | 2929 | if (item.value()) |val| { |
| | 2930 | if (val.isUndef()) { |
| | 2931 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| | 2932 | return sema.failWithUseOfUndef(block, src); |
| | 2933 | } |
| | 2934 | break :val val; |
| | 2935 | } |
| | 2936 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| | 2937 | return sema.failWithNeededComptime(block, src); |
| | 2938 | }; |
| | 2939 | const maybe_prev_src = try range_set.add(value, value, switch_prong_src); |
| | 2940 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 2862 | } | 2941 | } |
| 2863 | | 2942 | |
| 2864 | fn validateSwitchItemBool( | 2943 | fn validateSwitchDupe( |
| 2865 | sema: *Sema, | 2944 | sema: *Sema, |
| 2866 | block: *Scope.Block, | 2945 | block: *Scope.Block, |
| 2867 | true_count: *u8, | 2946 | maybe_prev_src: ?AstGen.SwitchProngSrc, |
| 2868 | false_count: *u8, | 2947 | switch_prong_src: AstGen.SwitchProngSrc, |
| 2869 | item_ref: zir.Inst.Ref, | | |
| 2870 | src_node_offset: i32, | 2948 | src_node_offset: i32, |
| 2871 | ) InnerError!void { | 2949 | ) InnerError!void { |
| 2872 | @panic("TODO"); | 2950 | const prev_prong_src = maybe_prev_src orelse return; |
| | 2951 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| | 2952 | const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| | 2953 | const msg = msg: { |
| | 2954 | const msg = try sema.mod.errMsg( |
| | 2955 | &block.base, |
| | 2956 | src, |
| | 2957 | "duplicate switch value", |
| | 2958 | .{}, |
| | 2959 | ); |
| | 2960 | errdefer msg.destroy(sema.gpa); |
| | 2961 | try sema.mod.errNote( |
| | 2962 | &block.base, |
| | 2963 | prev_src, |
| | 2964 | msg, |
| | 2965 | "previous value here", |
| | 2966 | .{}, |
| | 2967 | ); |
| | 2968 | break :msg msg; |
| | 2969 | }; |
| | 2970 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); |
| 2873 | } | 2971 | } |
| 2874 | | 2972 | |
| 2875 | fn validateSwitchRange( | 2973 | fn validateSwitchItemBool( |
| 2876 | sema: *Sema, | 2974 | sema: *Sema, |
| 2877 | block: *Scope.Block, | 2975 | block: *Scope.Block, |
| 2878 | range_set: *RangeSet, | 2976 | true_count: *u8, |
| 2879 | item_first: zir.Inst.Ref, | 2977 | false_count: *u8, |
| 2880 | item_last: zir.Inst.Ref, | 2978 | item_ref: zir.Inst.Ref, |
| 2881 | src_node_offset: i32, | 2979 | src_node_offset: i32, |
| 2882 | ) InnerError!void { | 2980 | ) InnerError!void { |
| 2883 | @panic("TODO"); | 2981 | @panic("TODO"); |