| author | |
| committer | |
| log | 93bb1d93cd18e739410009e7c77048d151a93b10 |
| tree | 67b36291211919b9751785eecf8858195bce42d6 |
| parent | 6c2e0c2046a4c1d01587cc15ea2f59af32743eb4 |
| parent | 982acc22fd8674a9efbe1e65e037c464ba610882 |
| signature |
stage2: inferred local variables12 files changed, 347 insertions(+), 71 deletions(-)
src/Module.zig+14-1| ... | ... | @@ -3189,7 +3189,14 @@ pub fn floatSub( |
| 3189 | 3189 | } |
| 3190 | 3190 | } |
| 3191 | 3191 | |
| 3192 | pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { | |
| 3192 | pub fn simplePtrType( | |
| 3193 | self: *Module, | |
| 3194 | scope: *Scope, | |
| 3195 | src: usize, | |
| 3196 | elem_ty: Type, | |
| 3197 | mutable: bool, | |
| 3198 | size: std.builtin.TypeInfo.Pointer.Size, | |
| 3199 | ) Allocator.Error!Type { | |
| 3193 | 3200 | if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { |
| 3194 | 3201 | return Type.initTag(.const_slice_u8); |
| 3195 | 3202 | } |
| ... | ... | @@ -3414,3 +3421,9 @@ pub fn getTarget(self: Module) Target { |
| 3414 | 3421 | pub fn optimizeMode(self: Module) std.builtin.Mode { |
| 3415 | 3422 | return self.comp.bin_file.options.optimize_mode; |
| 3416 | 3423 | } |
| 3424 | ||
| 3425 | pub fn validateVarType(mod: *Module, scope: *Scope, src: usize, ty: Type) !void { | |
| 3426 | if (!ty.isValidVarType(false)) { | |
| 3427 | return mod.fail(scope, src, "variable of type '{}' must be const or comptime", .{ty}); | |
| 3428 | } | |
| 3429 | } |
src/astgen.zig+14-3| ... | ... | @@ -585,6 +585,7 @@ fn varDecl( |
| 585 | 585 | |
| 586 | 586 | switch (tree.token_ids[node.mut_token]) { |
| 587 | 587 | .Keyword_const => { |
| 588 | var resolve_inferred_alloc: ?*zir.Inst = null; | |
| 588 | 589 | // Depending on the type of AST the initialization expression is, we may need an lvalue |
| 589 | 590 | // or an rvalue as a result location. If it is an rvalue, we can use the instruction as |
| 590 | 591 | // the variable, no memory location needed. |
| ... | ... | @@ -595,6 +596,7 @@ fn varDecl( |
| 595 | 596 | break :r ResultLoc{ .ptr = alloc }; |
| 596 | 597 | } else { |
| 597 | 598 | const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred); |
| 599 | resolve_inferred_alloc = &alloc.base; | |
| 598 | 600 | break :r ResultLoc{ .inferred_ptr = alloc }; |
| 599 | 601 | } |
| 600 | 602 | } else r: { |
| ... | ... | @@ -604,6 +606,9 @@ fn varDecl( |
| 604 | 606 | break :r .none; |
| 605 | 607 | }; |
| 606 | 608 | const init_inst = try expr(mod, scope, result_loc, init_node); |
| 609 | if (resolve_inferred_alloc) |inst| { | |
| 610 | _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); | |
| 611 | } | |
| 607 | 612 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 608 | 613 | sub_scope.* = .{ |
| 609 | 614 | .parent = scope, |
| ... | ... | @@ -614,15 +619,20 @@ fn varDecl( |
| 614 | 619 | return &sub_scope.base; |
| 615 | 620 | }, |
| 616 | 621 | .Keyword_var => { |
| 622 | var resolve_inferred_alloc: ?*zir.Inst = null; | |
| 617 | 623 | const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: { |
| 618 | 624 | const type_inst = try typeExpr(mod, scope, type_node); |
| 619 | 625 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst); |
| 620 | 626 | break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; |
| 621 | 627 | } else a: { |
| 622 | const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred_mut); | |
| 623 | break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred_mut).? } }; | |
| 628 | const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred_mut); | |
| 629 | resolve_inferred_alloc = &alloc.base; | |
| 630 | break :a .{ .alloc = &alloc.base, .result_loc = .{ .inferred_ptr = alloc } }; | |
| 624 | 631 | }; |
| 625 | 632 | const init_inst = try expr(mod, scope, var_data.result_loc, init_node); |
| 633 | if (resolve_inferred_alloc) |inst| { | |
| 634 | _ = try addZIRUnOp(mod, scope, name_src, .resolve_inferred_alloc, inst); | |
| 635 | } | |
| 626 | 636 | const sub_scope = try block_arena.create(Scope.LocalPtr); |
| 627 | 637 | sub_scope.* = .{ |
| 628 | 638 | .parent = scope, |
| ... | ... | @@ -2717,7 +2727,8 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr |
| 2717 | 2727 | return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{}); |
| 2718 | 2728 | }, |
| 2719 | 2729 | .inferred_ptr => |alloc| { |
| 2720 | return addZIRBinOp(mod, scope, result.src, .store, &alloc.base, result); | |
| 2730 | _ = try addZIRBinOp(mod, scope, result.src, .store_to_inferred_ptr, &alloc.base, result); | |
| 2731 | return result; | |
| 2721 | 2732 | }, |
| 2722 | 2733 | .block_ptr => |block_ptr| { |
| 2723 | 2734 | return mod.fail(scope, result.src, "TODO implement rlWrap .block_ptr", .{}); |
src/codegen/c.zig+30-1| ... | ... | @@ -285,6 +285,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void { |
| 285 | 285 | .arg => try genArg(&ctx), |
| 286 | 286 | .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?), |
| 287 | 287 | .block => try genBlock(&ctx, file, inst.castTag(.block).?), |
| 288 | .bitcast => try genBitcast(&ctx, file, inst.castTag(.bitcast).?), | |
| 288 | 289 | .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?), |
| 289 | 290 | .call => try genCall(&ctx, file, inst.castTag(.call).?), |
| 290 | 291 | .cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="), |
| ... | ... | @@ -295,6 +296,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void { |
| 295 | 296 | .cmp_neq => try genBinOp(&ctx, file, inst.castTag(.cmp_neq).?, "!="), |
| 296 | 297 | .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?), |
| 297 | 298 | .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?), |
| 299 | .load => try genLoad(&ctx, file, inst.castTag(.load).?), | |
| 298 | 300 | .ret => try genRet(&ctx, file, inst.castTag(.ret).?), |
| 299 | 301 | .retvoid => try genRetVoid(file), |
| 300 | 302 | .store => try genStore(&ctx, file, inst.castTag(.store).?), |
| ... | ... | @@ -429,6 +431,16 @@ fn genRetVoid(file: *C) !?[]u8 { |
| 429 | 431 | return null; |
| 430 | 432 | } |
| 431 | 433 | |
| 434 | fn genLoad(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 { | |
| 435 | const operand = try ctx.resolveInst(inst.operand); | |
| 436 | const writer = file.main.writer(); | |
| 437 | try indent(file); | |
| 438 | const local_name = try ctx.name(); | |
| 439 | try renderTypeAndName(ctx, writer, inst.base.ty, local_name, .Const); | |
| 440 | try writer.print(" = *{s};\n", .{operand}); | |
| 441 | return local_name; | |
| 442 | } | |
| 443 | ||
| 432 | 444 | fn genRet(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 { |
| 433 | 445 | try indent(file); |
| 434 | 446 | const writer = file.main.writer(); |
| ... | ... | @@ -440,7 +452,6 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 { |
| 440 | 452 | if (inst.base.isUnused()) |
| 441 | 453 | return null; |
| 442 | 454 | try indent(file); |
| 443 | const op = inst.operand; | |
| 444 | 455 | const writer = file.main.writer(); |
| 445 | 456 | const name = try ctx.name(); |
| 446 | 457 | const from = try ctx.resolveInst(inst.operand); |
| ... | ... | @@ -537,6 +548,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 { |
| 537 | 548 | return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{}); |
| 538 | 549 | } |
| 539 | 550 | |
| 551 | fn genBitcast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 { | |
| 552 | const writer = file.main.writer(); | |
| 553 | try indent(file); | |
| 554 | const local_name = try ctx.name(); | |
| 555 | const operand = try ctx.resolveInst(inst.operand); | |
| 556 | try renderTypeAndName(ctx, writer, inst.base.ty, local_name, .Const); | |
| 557 | if (inst.base.ty.zigTypeTag() == .Pointer and inst.operand.ty.zigTypeTag() == .Pointer) { | |
| 558 | try writer.writeAll(" = ("); | |
| 559 | try renderType(ctx, writer, inst.base.ty); | |
| 560 | try writer.print("){s};\n", .{operand}); | |
| 561 | } else { | |
| 562 | try writer.writeAll(";\n"); | |
| 563 | try indent(file); | |
| 564 | try writer.print("memcpy(&{s}, &{s}, sizeof {s});\n", .{ local_name, operand, local_name }); | |
| 565 | } | |
| 566 | return local_name; | |
| 567 | } | |
| 568 | ||
| 540 | 569 | fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 { |
| 541 | 570 | try indent(file); |
| 542 | 571 | try file.main.writer().writeAll("zig_breakpoint();\n"); |
src/ir.zig+1-1| ... | ... | @@ -196,7 +196,7 @@ pub const Inst = struct { |
| 196 | 196 | pub fn value(base: *Inst) ?Value { |
| 197 | 197 | if (base.ty.onePossibleValue()) |opv| return opv; |
| 198 | 198 | |
| 199 | const inst = base.cast(Constant) orelse return null; | |
| 199 | const inst = base.castTag(.constant) orelse return null; | |
| 200 | 200 | return inst.val; |
| 201 | 201 | } |
| 202 | 202 |
src/link/cbe.h+1-1| ... | ... | @@ -41,4 +41,4 @@ |
| 41 | 41 | #include <stdint.h> |
| 42 | 42 | #define int128_t __int128 |
| 43 | 43 | #define uint128_t unsigned __int128 |
| 44 | ||
| 44 | #include <string.h> |
src/test.zig+1| ... | ... | @@ -782,6 +782,7 @@ pub const TestContext = struct { |
| 782 | 782 | "-std=c89", |
| 783 | 783 | "-pedantic", |
| 784 | 784 | "-Werror", |
| 785 | "-Wno-declaration-after-statement", | |
| 785 | 786 | "--", |
| 786 | 787 | "-lc", |
| 787 | 788 | exe_path, |
src/type.zig+125-54| ... | ... | @@ -78,6 +78,8 @@ pub const Type = extern union { |
| 78 | 78 | .const_slice, |
| 79 | 79 | .mut_slice, |
| 80 | 80 | .pointer, |
| 81 | .inferred_alloc_const, | |
| 82 | .inferred_alloc_mut, | |
| 81 | 83 | => return .Pointer, |
| 82 | 84 | |
| 83 | 85 | .optional, |
| ... | ... | @@ -158,6 +160,9 @@ pub const Type = extern union { |
| 158 | 160 | .optional_single_mut_pointer, |
| 159 | 161 | => self.cast(Payload.ElemType), |
| 160 | 162 | |
| 163 | .inferred_alloc_const => unreachable, | |
| 164 | .inferred_alloc_mut => unreachable, | |
| 165 | ||
| 161 | 166 | else => null, |
| 162 | 167 | }; |
| 163 | 168 | } |
| ... | ... | @@ -384,6 +389,8 @@ pub const Type = extern union { |
| 384 | 389 | .enum_literal, |
| 385 | 390 | .anyerror_void_error_union, |
| 386 | 391 | .@"anyframe", |
| 392 | .inferred_alloc_const, | |
| 393 | .inferred_alloc_mut, | |
| 387 | 394 | => unreachable, |
| 388 | 395 | |
| 389 | 396 | .array_u8, |
| ... | ... | @@ -686,6 +693,8 @@ pub const Type = extern union { |
| 686 | 693 | const name = ty.castTag(.error_set_single).?.data; |
| 687 | 694 | return out_stream.print("error{{{s}}}", .{name}); |
| 688 | 695 | }, |
| 696 | .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"), | |
| 697 | .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"), | |
| 689 | 698 | } |
| 690 | 699 | unreachable; |
| 691 | 700 | } |
| ... | ... | @@ -733,6 +742,8 @@ pub const Type = extern union { |
| 733 | 742 | .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), |
| 734 | 743 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), |
| 735 | 744 | .enum_literal => return Value.initTag(.enum_literal_type), |
| 745 | .inferred_alloc_const => unreachable, | |
| 746 | .inferred_alloc_mut => unreachable, | |
| 736 | 747 | else => return Value.Tag.ty.create(allocator, self), |
| 737 | 748 | } |
| 738 | 749 | } |
| ... | ... | @@ -803,6 +814,9 @@ pub const Type = extern union { |
| 803 | 814 | .enum_literal, |
| 804 | 815 | .empty_struct, |
| 805 | 816 | => false, |
| 817 | ||
| 818 | .inferred_alloc_const => unreachable, | |
| 819 | .inferred_alloc_mut => unreachable, | |
| 806 | 820 | }; |
| 807 | 821 | } |
| 808 | 822 | |
| ... | ... | @@ -920,6 +934,8 @@ pub const Type = extern union { |
| 920 | 934 | .@"undefined", |
| 921 | 935 | .enum_literal, |
| 922 | 936 | .empty_struct, |
| 937 | .inferred_alloc_const, | |
| 938 | .inferred_alloc_mut, | |
| 923 | 939 | => unreachable, |
| 924 | 940 | }; |
| 925 | 941 | } |
| ... | ... | @@ -943,6 +959,8 @@ pub const Type = extern union { |
| 943 | 959 | .enum_literal => unreachable, |
| 944 | 960 | .single_const_pointer_to_comptime_int => unreachable, |
| 945 | 961 | .empty_struct => unreachable, |
| 962 | .inferred_alloc_const => unreachable, | |
| 963 | .inferred_alloc_mut => unreachable, | |
| 946 | 964 | |
| 947 | 965 | .u8, |
| 948 | 966 | .i8, |
| ... | ... | @@ -1121,6 +1139,8 @@ pub const Type = extern union { |
| 1121 | 1139 | .single_const_pointer, |
| 1122 | 1140 | .single_mut_pointer, |
| 1123 | 1141 | .single_const_pointer_to_comptime_int, |
| 1142 | .inferred_alloc_const, | |
| 1143 | .inferred_alloc_mut, | |
| 1124 | 1144 | => true, |
| 1125 | 1145 | |
| 1126 | 1146 | .pointer => self.castTag(.pointer).?.data.size == .One, |
| ... | ... | @@ -1203,6 +1223,8 @@ pub const Type = extern union { |
| 1203 | 1223 | .single_const_pointer, |
| 1204 | 1224 | .single_mut_pointer, |
| 1205 | 1225 | .single_const_pointer_to_comptime_int, |
| 1226 | .inferred_alloc_const, | |
| 1227 | .inferred_alloc_mut, | |
| 1206 | 1228 | => .One, |
| 1207 | 1229 | |
| 1208 | 1230 | .pointer => self.castTag(.pointer).?.data.size, |
| ... | ... | @@ -1273,6 +1295,8 @@ pub const Type = extern union { |
| 1273 | 1295 | .error_set, |
| 1274 | 1296 | .error_set_single, |
| 1275 | 1297 | .empty_struct, |
| 1298 | .inferred_alloc_const, | |
| 1299 | .inferred_alloc_mut, | |
| 1276 | 1300 | => false, |
| 1277 | 1301 | |
| 1278 | 1302 | .const_slice, |
| ... | ... | @@ -1345,6 +1369,8 @@ pub const Type = extern union { |
| 1345 | 1369 | .error_set, |
| 1346 | 1370 | .error_set_single, |
| 1347 | 1371 | .empty_struct, |
| 1372 | .inferred_alloc_const, | |
| 1373 | .inferred_alloc_mut, | |
| 1348 | 1374 | => false, |
| 1349 | 1375 | |
| 1350 | 1376 | .single_const_pointer, |
| ... | ... | @@ -1426,6 +1452,8 @@ pub const Type = extern union { |
| 1426 | 1452 | .error_set, |
| 1427 | 1453 | .error_set_single, |
| 1428 | 1454 | .empty_struct, |
| 1455 | .inferred_alloc_const, | |
| 1456 | .inferred_alloc_mut, | |
| 1429 | 1457 | => false, |
| 1430 | 1458 | |
| 1431 | 1459 | .pointer => { |
| ... | ... | @@ -1502,6 +1530,8 @@ pub const Type = extern union { |
| 1502 | 1530 | .error_set, |
| 1503 | 1531 | .error_set_single, |
| 1504 | 1532 | .empty_struct, |
| 1533 | .inferred_alloc_const, | |
| 1534 | .inferred_alloc_mut, | |
| 1505 | 1535 | => false, |
| 1506 | 1536 | |
| 1507 | 1537 | .pointer => { |
| ... | ... | @@ -1569,58 +1599,59 @@ pub const Type = extern union { |
| 1569 | 1599 | /// Asserts the type is a pointer or array type. |
| 1570 | 1600 | pub fn elemType(self: Type) Type { |
| 1571 | 1601 | return switch (self.tag()) { |
| 1572 | .u8, | |
| 1573 | .i8, | |
| 1574 | .u16, | |
| 1575 | .i16, | |
| 1576 | .u32, | |
| 1577 | .i32, | |
| 1578 | .u64, | |
| 1579 | .i64, | |
| 1580 | .usize, | |
| 1581 | .isize, | |
| 1582 | .c_short, | |
| 1583 | .c_ushort, | |
| 1584 | .c_int, | |
| 1585 | .c_uint, | |
| 1586 | .c_long, | |
| 1587 | .c_ulong, | |
| 1588 | .c_longlong, | |
| 1589 | .c_ulonglong, | |
| 1590 | .c_longdouble, | |
| 1591 | .f16, | |
| 1592 | .f32, | |
| 1593 | .f64, | |
| 1594 | .f128, | |
| 1595 | .c_void, | |
| 1596 | .bool, | |
| 1597 | .void, | |
| 1598 | .type, | |
| 1599 | .anyerror, | |
| 1600 | .comptime_int, | |
| 1601 | .comptime_float, | |
| 1602 | .noreturn, | |
| 1603 | .@"null", | |
| 1604 | .@"undefined", | |
| 1605 | .fn_noreturn_no_args, | |
| 1606 | .fn_void_no_args, | |
| 1607 | .fn_naked_noreturn_no_args, | |
| 1608 | .fn_ccc_void_no_args, | |
| 1609 | .function, | |
| 1610 | .int_unsigned, | |
| 1611 | .int_signed, | |
| 1612 | .optional, | |
| 1613 | .optional_single_const_pointer, | |
| 1614 | .optional_single_mut_pointer, | |
| 1615 | .enum_literal, | |
| 1616 | .error_union, | |
| 1617 | .@"anyframe", | |
| 1618 | .anyframe_T, | |
| 1619 | .anyerror_void_error_union, | |
| 1620 | .error_set, | |
| 1621 | .error_set_single, | |
| 1622 | .empty_struct, | |
| 1623 | => unreachable, | |
| 1602 | .u8 => unreachable, | |
| 1603 | .i8 => unreachable, | |
| 1604 | .u16 => unreachable, | |
| 1605 | .i16 => unreachable, | |
| 1606 | .u32 => unreachable, | |
| 1607 | .i32 => unreachable, | |
| 1608 | .u64 => unreachable, | |
| 1609 | .i64 => unreachable, | |
| 1610 | .usize => unreachable, | |
| 1611 | .isize => unreachable, | |
| 1612 | .c_short => unreachable, | |
| 1613 | .c_ushort => unreachable, | |
| 1614 | .c_int => unreachable, | |
| 1615 | .c_uint => unreachable, | |
| 1616 | .c_long => unreachable, | |
| 1617 | .c_ulong => unreachable, | |
| 1618 | .c_longlong => unreachable, | |
| 1619 | .c_ulonglong => unreachable, | |
| 1620 | .c_longdouble => unreachable, | |
| 1621 | .f16 => unreachable, | |
| 1622 | .f32 => unreachable, | |
| 1623 | .f64 => unreachable, | |
| 1624 | .f128 => unreachable, | |
| 1625 | .c_void => unreachable, | |
| 1626 | .bool => unreachable, | |
| 1627 | .void => unreachable, | |
| 1628 | .type => unreachable, | |
| 1629 | .anyerror => unreachable, | |
| 1630 | .comptime_int => unreachable, | |
| 1631 | .comptime_float => unreachable, | |
| 1632 | .noreturn => unreachable, | |
| 1633 | .@"null" => unreachable, | |
| 1634 | .@"undefined" => unreachable, | |
| 1635 | .fn_noreturn_no_args => unreachable, | |
| 1636 | .fn_void_no_args => unreachable, | |
| 1637 | .fn_naked_noreturn_no_args => unreachable, | |
| 1638 | .fn_ccc_void_no_args => unreachable, | |
| 1639 | .function => unreachable, | |
| 1640 | .int_unsigned => unreachable, | |
| 1641 | .int_signed => unreachable, | |
| 1642 | .optional => unreachable, | |
| 1643 | .optional_single_const_pointer => unreachable, | |
| 1644 | .optional_single_mut_pointer => unreachable, | |
| 1645 | .enum_literal => unreachable, | |
| 1646 | .error_union => unreachable, | |
| 1647 | .@"anyframe" => unreachable, | |
| 1648 | .anyframe_T => unreachable, | |
| 1649 | .anyerror_void_error_union => unreachable, | |
| 1650 | .error_set => unreachable, | |
| 1651 | .error_set_single => unreachable, | |
| 1652 | .empty_struct => unreachable, | |
| 1653 | .inferred_alloc_const => unreachable, | |
| 1654 | .inferred_alloc_mut => unreachable, | |
| 1624 | 1655 | |
| 1625 | 1656 | .array => self.castTag(.array).?.data.elem_type, |
| 1626 | 1657 | .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type, |
| ... | ... | @@ -1742,6 +1773,8 @@ pub const Type = extern union { |
| 1742 | 1773 | .error_set, |
| 1743 | 1774 | .error_set_single, |
| 1744 | 1775 | .empty_struct, |
| 1776 | .inferred_alloc_const, | |
| 1777 | .inferred_alloc_mut, | |
| 1745 | 1778 | => unreachable, |
| 1746 | 1779 | |
| 1747 | 1780 | .array => self.castTag(.array).?.data.len, |
| ... | ... | @@ -1808,6 +1841,8 @@ pub const Type = extern union { |
| 1808 | 1841 | .error_set, |
| 1809 | 1842 | .error_set_single, |
| 1810 | 1843 | .empty_struct, |
| 1844 | .inferred_alloc_const, | |
| 1845 | .inferred_alloc_mut, | |
| 1811 | 1846 | => unreachable, |
| 1812 | 1847 | |
| 1813 | 1848 | .single_const_pointer, |
| ... | ... | @@ -1891,6 +1926,8 @@ pub const Type = extern union { |
| 1891 | 1926 | .error_set, |
| 1892 | 1927 | .error_set_single, |
| 1893 | 1928 | .empty_struct, |
| 1929 | .inferred_alloc_const, | |
| 1930 | .inferred_alloc_mut, | |
| 1894 | 1931 | => false, |
| 1895 | 1932 | |
| 1896 | 1933 | .int_signed, |
| ... | ... | @@ -1966,6 +2003,8 @@ pub const Type = extern union { |
| 1966 | 2003 | .error_set, |
| 1967 | 2004 | .error_set_single, |
| 1968 | 2005 | .empty_struct, |
| 2006 | .inferred_alloc_const, | |
| 2007 | .inferred_alloc_mut, | |
| 1969 | 2008 | => false, |
| 1970 | 2009 | |
| 1971 | 2010 | .int_unsigned, |
| ... | ... | @@ -2031,6 +2070,8 @@ pub const Type = extern union { |
| 2031 | 2070 | .error_set, |
| 2032 | 2071 | .error_set_single, |
| 2033 | 2072 | .empty_struct, |
| 2073 | .inferred_alloc_const, | |
| 2074 | .inferred_alloc_mut, | |
| 2034 | 2075 | => unreachable, |
| 2035 | 2076 | |
| 2036 | 2077 | .int_unsigned => .{ |
| ... | ... | @@ -2120,6 +2161,8 @@ pub const Type = extern union { |
| 2120 | 2161 | .error_set, |
| 2121 | 2162 | .error_set_single, |
| 2122 | 2163 | .empty_struct, |
| 2164 | .inferred_alloc_const, | |
| 2165 | .inferred_alloc_mut, | |
| 2123 | 2166 | => false, |
| 2124 | 2167 | |
| 2125 | 2168 | .usize, |
| ... | ... | @@ -2232,6 +2275,8 @@ pub const Type = extern union { |
| 2232 | 2275 | .error_set, |
| 2233 | 2276 | .error_set_single, |
| 2234 | 2277 | .empty_struct, |
| 2278 | .inferred_alloc_const, | |
| 2279 | .inferred_alloc_mut, | |
| 2235 | 2280 | => unreachable, |
| 2236 | 2281 | }; |
| 2237 | 2282 | } |
| ... | ... | @@ -2310,6 +2355,8 @@ pub const Type = extern union { |
| 2310 | 2355 | .error_set, |
| 2311 | 2356 | .error_set_single, |
| 2312 | 2357 | .empty_struct, |
| 2358 | .inferred_alloc_const, | |
| 2359 | .inferred_alloc_mut, | |
| 2313 | 2360 | => unreachable, |
| 2314 | 2361 | } |
| 2315 | 2362 | } |
| ... | ... | @@ -2387,6 +2434,8 @@ pub const Type = extern union { |
| 2387 | 2434 | .error_set, |
| 2388 | 2435 | .error_set_single, |
| 2389 | 2436 | .empty_struct, |
| 2437 | .inferred_alloc_const, | |
| 2438 | .inferred_alloc_mut, | |
| 2390 | 2439 | => unreachable, |
| 2391 | 2440 | } |
| 2392 | 2441 | } |
| ... | ... | @@ -2464,6 +2513,8 @@ pub const Type = extern union { |
| 2464 | 2513 | .error_set, |
| 2465 | 2514 | .error_set_single, |
| 2466 | 2515 | .empty_struct, |
| 2516 | .inferred_alloc_const, | |
| 2517 | .inferred_alloc_mut, | |
| 2467 | 2518 | => unreachable, |
| 2468 | 2519 | }; |
| 2469 | 2520 | } |
| ... | ... | @@ -2538,6 +2589,8 @@ pub const Type = extern union { |
| 2538 | 2589 | .error_set, |
| 2539 | 2590 | .error_set_single, |
| 2540 | 2591 | .empty_struct, |
| 2592 | .inferred_alloc_const, | |
| 2593 | .inferred_alloc_mut, | |
| 2541 | 2594 | => unreachable, |
| 2542 | 2595 | }; |
| 2543 | 2596 | } |
| ... | ... | @@ -2612,6 +2665,8 @@ pub const Type = extern union { |
| 2612 | 2665 | .error_set, |
| 2613 | 2666 | .error_set_single, |
| 2614 | 2667 | .empty_struct, |
| 2668 | .inferred_alloc_const, | |
| 2669 | .inferred_alloc_mut, | |
| 2615 | 2670 | => unreachable, |
| 2616 | 2671 | }; |
| 2617 | 2672 | } |
| ... | ... | @@ -2686,6 +2741,8 @@ pub const Type = extern union { |
| 2686 | 2741 | .error_set, |
| 2687 | 2742 | .error_set_single, |
| 2688 | 2743 | .empty_struct, |
| 2744 | .inferred_alloc_const, | |
| 2745 | .inferred_alloc_mut, | |
| 2689 | 2746 | => false, |
| 2690 | 2747 | }; |
| 2691 | 2748 | } |
| ... | ... | @@ -2778,6 +2835,8 @@ pub const Type = extern union { |
| 2778 | 2835 | ty = ty.castTag(.pointer).?.data.pointee_type; |
| 2779 | 2836 | continue; |
| 2780 | 2837 | }, |
| 2838 | .inferred_alloc_const => unreachable, | |
| 2839 | .inferred_alloc_mut => unreachable, | |
| 2781 | 2840 | }; |
| 2782 | 2841 | } |
| 2783 | 2842 | |
| ... | ... | @@ -2846,6 +2905,8 @@ pub const Type = extern union { |
| 2846 | 2905 | .error_set, |
| 2847 | 2906 | .error_set_single, |
| 2848 | 2907 | .empty_struct, |
| 2908 | .inferred_alloc_const, | |
| 2909 | .inferred_alloc_mut, | |
| 2849 | 2910 | => return false, |
| 2850 | 2911 | |
| 2851 | 2912 | .c_const_pointer, |
| ... | ... | @@ -2931,6 +2992,8 @@ pub const Type = extern union { |
| 2931 | 2992 | .c_const_pointer, |
| 2932 | 2993 | .c_mut_pointer, |
| 2933 | 2994 | .pointer, |
| 2995 | .inferred_alloc_const, | |
| 2996 | .inferred_alloc_mut, | |
| 2934 | 2997 | => unreachable, |
| 2935 | 2998 | |
| 2936 | 2999 | .empty_struct => self.castTag(.empty_struct).?.data, |
| ... | ... | @@ -3041,7 +3104,13 @@ pub const Type = extern union { |
| 3041 | 3104 | single_const_pointer_to_comptime_int, |
| 3042 | 3105 | anyerror_void_error_union, |
| 3043 | 3106 | @"anyframe", |
| 3044 | const_slice_u8, // See last_no_payload_tag below. | |
| 3107 | const_slice_u8, | |
| 3108 | /// This is a special value that tracks a set of types that have been stored | |
| 3109 | /// to an inferred allocation. It does not support most of the normal type queries. | |
| 3110 | /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. | |
| 3111 | inferred_alloc_mut, | |
| 3112 | /// Same as `inferred_alloc_mut` but the local is `var` not `const`. | |
| 3113 | inferred_alloc_const, // See last_no_payload_tag below. | |
| 3045 | 3114 | // After this, the tag requires a payload. |
| 3046 | 3115 | |
| 3047 | 3116 | array_u8, |
| ... | ... | @@ -3069,7 +3138,7 @@ pub const Type = extern union { |
| 3069 | 3138 | error_set_single, |
| 3070 | 3139 | empty_struct, |
| 3071 | 3140 | |
| 3072 | pub const last_no_payload_tag = Tag.const_slice_u8; | |
| 3141 | pub const last_no_payload_tag = Tag.inferred_alloc_const; | |
| 3073 | 3142 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| 3074 | 3143 | |
| 3075 | 3144 | pub fn Type(comptime t: Tag) type { |
| ... | ... | @@ -3116,6 +3185,8 @@ pub const Type = extern union { |
| 3116 | 3185 | .anyerror_void_error_union, |
| 3117 | 3186 | .@"anyframe", |
| 3118 | 3187 | .const_slice_u8, |
| 3188 | .inferred_alloc_const, | |
| 3189 | .inferred_alloc_mut, | |
| 3119 | 3190 | => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), |
| 3120 | 3191 | |
| 3121 | 3192 | .array_u8, |
src/value.zig+36| ... | ... | @@ -7,6 +7,7 @@ const BigIntMutable = std.math.big.int.Mutable; |
| 7 | 7 | const Target = std.Target; |
| 8 | 8 | const Allocator = std.mem.Allocator; |
| 9 | 9 | const Module = @import("Module.zig"); |
| 10 | const ir = @import("ir.zig"); | |
| 10 | 11 | |
| 11 | 12 | /// This is the raw data, with no bookkeeping, no memory awareness, |
| 12 | 13 | /// no de-duplication, and no type system awareness. |
| ... | ... | @@ -101,6 +102,9 @@ pub const Value = extern union { |
| 101 | 102 | enum_literal, |
| 102 | 103 | error_set, |
| 103 | 104 | @"error", |
| 105 | /// This is a special value that tracks a set of types that have been stored | |
| 106 | /// to an inferred allocation. It does not support any of the normal value queries. | |
| 107 | inferred_alloc, | |
| 104 | 108 | |
| 105 | 109 | pub const last_no_payload_tag = Tag.bool_false; |
| 106 | 110 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; |
| ... | ... | @@ -189,6 +193,7 @@ pub const Value = extern union { |
| 189 | 193 | .float_128 => Payload.Float_128, |
| 190 | 194 | .error_set => Payload.ErrorSet, |
| 191 | 195 | .@"error" => Payload.Error, |
| 196 | .inferred_alloc => Payload.InferredAlloc, | |
| 192 | 197 | }; |
| 193 | 198 | } |
| 194 | 199 | |
| ... | ... | @@ -383,6 +388,8 @@ pub const Value = extern union { |
| 383 | 388 | |
| 384 | 389 | // memory is managed by the declaration |
| 385 | 390 | .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), |
| 391 | ||
| 392 | .inferred_alloc => unreachable, | |
| 386 | 393 | } |
| 387 | 394 | } |
| 388 | 395 | |
| ... | ... | @@ -501,6 +508,7 @@ pub const Value = extern union { |
| 501 | 508 | return out_stream.writeAll("}"); |
| 502 | 509 | }, |
| 503 | 510 | .@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}), |
| 511 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), | |
| 504 | 512 | }; |
| 505 | 513 | } |
| 506 | 514 | |
| ... | ... | @@ -613,6 +621,7 @@ pub const Value = extern union { |
| 613 | 621 | .enum_literal, |
| 614 | 622 | .@"error", |
| 615 | 623 | .empty_struct_value, |
| 624 | .inferred_alloc, | |
| 616 | 625 | => unreachable, |
| 617 | 626 | }; |
| 618 | 627 | } |
| ... | ... | @@ -683,6 +692,7 @@ pub const Value = extern union { |
| 683 | 692 | .error_set, |
| 684 | 693 | .@"error", |
| 685 | 694 | .empty_struct_value, |
| 695 | .inferred_alloc, | |
| 686 | 696 | => unreachable, |
| 687 | 697 | |
| 688 | 698 | .undef => unreachable, |
| ... | ... | @@ -768,6 +778,7 @@ pub const Value = extern union { |
| 768 | 778 | .error_set, |
| 769 | 779 | .@"error", |
| 770 | 780 | .empty_struct_value, |
| 781 | .inferred_alloc, | |
| 771 | 782 | => unreachable, |
| 772 | 783 | |
| 773 | 784 | .undef => unreachable, |
| ... | ... | @@ -853,6 +864,7 @@ pub const Value = extern union { |
| 853 | 864 | .error_set, |
| 854 | 865 | .@"error", |
| 855 | 866 | .empty_struct_value, |
| 867 | .inferred_alloc, | |
| 856 | 868 | => unreachable, |
| 857 | 869 | |
| 858 | 870 | .undef => unreachable, |
| ... | ... | @@ -966,6 +978,7 @@ pub const Value = extern union { |
| 966 | 978 | .error_set, |
| 967 | 979 | .@"error", |
| 968 | 980 | .empty_struct_value, |
| 981 | .inferred_alloc, | |
| 969 | 982 | => unreachable, |
| 970 | 983 | |
| 971 | 984 | .zero, |
| ... | ... | @@ -1055,6 +1068,7 @@ pub const Value = extern union { |
| 1055 | 1068 | .error_set, |
| 1056 | 1069 | .@"error", |
| 1057 | 1070 | .empty_struct_value, |
| 1071 | .inferred_alloc, | |
| 1058 | 1072 | => unreachable, |
| 1059 | 1073 | |
| 1060 | 1074 | .zero, |
| ... | ... | @@ -1213,6 +1227,7 @@ pub const Value = extern union { |
| 1213 | 1227 | .error_set, |
| 1214 | 1228 | .@"error", |
| 1215 | 1229 | .empty_struct_value, |
| 1230 | .inferred_alloc, | |
| 1216 | 1231 | => unreachable, |
| 1217 | 1232 | |
| 1218 | 1233 | .zero, |
| ... | ... | @@ -1289,6 +1304,7 @@ pub const Value = extern union { |
| 1289 | 1304 | .error_set, |
| 1290 | 1305 | .@"error", |
| 1291 | 1306 | .empty_struct_value, |
| 1307 | .inferred_alloc, | |
| 1292 | 1308 | => unreachable, |
| 1293 | 1309 | |
| 1294 | 1310 | .zero, |
| ... | ... | @@ -1525,6 +1541,8 @@ pub const Value = extern union { |
| 1525 | 1541 | hasher.update(payload.name); |
| 1526 | 1542 | std.hash.autoHash(&hasher, payload.value); |
| 1527 | 1543 | }, |
| 1544 | ||
| 1545 | .inferred_alloc => unreachable, | |
| 1528 | 1546 | } |
| 1529 | 1547 | return hasher.final(); |
| 1530 | 1548 | } |
| ... | ... | @@ -1602,6 +1620,7 @@ pub const Value = extern union { |
| 1602 | 1620 | .error_set, |
| 1603 | 1621 | .@"error", |
| 1604 | 1622 | .empty_struct_value, |
| 1623 | .inferred_alloc, | |
| 1605 | 1624 | => unreachable, |
| 1606 | 1625 | |
| 1607 | 1626 | .ref_val => self.castTag(.ref_val).?.data, |
| ... | ... | @@ -1687,6 +1706,7 @@ pub const Value = extern union { |
| 1687 | 1706 | .error_set, |
| 1688 | 1707 | .@"error", |
| 1689 | 1708 | .empty_struct_value, |
| 1709 | .inferred_alloc, | |
| 1690 | 1710 | => unreachable, |
| 1691 | 1711 | |
| 1692 | 1712 | .empty_array => unreachable, // out of bounds array index |
| ... | ... | @@ -1793,6 +1813,7 @@ pub const Value = extern union { |
| 1793 | 1813 | |
| 1794 | 1814 | .undef => unreachable, |
| 1795 | 1815 | .unreachable_value => unreachable, |
| 1816 | .inferred_alloc => unreachable, | |
| 1796 | 1817 | .null_value => true, |
| 1797 | 1818 | }; |
| 1798 | 1819 | } |
| ... | ... | @@ -1801,6 +1822,7 @@ pub const Value = extern union { |
| 1801 | 1822 | pub fn isFloat(self: Value) bool { |
| 1802 | 1823 | return switch (self.tag()) { |
| 1803 | 1824 | .undef => unreachable, |
| 1825 | .inferred_alloc => unreachable, | |
| 1804 | 1826 | |
| 1805 | 1827 | .float_16, |
| 1806 | 1828 | .float_32, |
| ... | ... | @@ -1890,6 +1912,7 @@ pub const Value = extern union { |
| 1890 | 1912 | |
| 1891 | 1913 | .undef => unreachable, |
| 1892 | 1914 | .unreachable_value => unreachable, |
| 1915 | .inferred_alloc => unreachable, | |
| 1893 | 1916 | }; |
| 1894 | 1917 | } |
| 1895 | 1918 | |
| ... | ... | @@ -2020,6 +2043,19 @@ pub const Value = extern union { |
| 2020 | 2043 | value: u16, |
| 2021 | 2044 | }, |
| 2022 | 2045 | }; |
| 2046 | ||
| 2047 | pub const InferredAlloc = struct { | |
| 2048 | pub const base_tag = Tag.inferred_alloc; | |
| 2049 | ||
| 2050 | base: Payload = .{ .tag = base_tag }, | |
| 2051 | data: struct { | |
| 2052 | /// The value stored in the inferred allocation. This will go into | |
| 2053 | /// peer type resolution. This is stored in a separate list so that | |
| 2054 | /// the items are contiguous in memory and thus can be passed to | |
| 2055 | /// `Module.resolvePeerTypes`. | |
| 2056 | stored_inst_list: std.ArrayListUnmanaged(*ir.Inst) = .{}, | |
| 2057 | }, | |
| 2058 | }; | |
| 2023 | 2059 | }; |
| 2024 | 2060 | |
| 2025 | 2061 | /// Big enough to fit any non-BigInt value |
src/zir.zig+12| ... | ... | @@ -241,12 +241,20 @@ pub const Inst = struct { |
| 241 | 241 | const_slice_type, |
| 242 | 242 | /// Create a pointer type with attributes |
| 243 | 243 | ptr_type, |
| 244 | /// Each `store_to_inferred_ptr` puts the type of the stored value into a set, | |
| 245 | /// and then `resolve_inferred_alloc` triggers peer type resolution on the set. | |
| 246 | /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which | |
| 247 | /// is the allocation that needs to have its type inferred. | |
| 248 | resolve_inferred_alloc, | |
| 244 | 249 | /// Slice operation `array_ptr[start..end:sentinel]` |
| 245 | 250 | slice, |
| 246 | 251 | /// Slice operation with just start `lhs[rhs..]` |
| 247 | 252 | slice_start, |
| 248 | 253 | /// Write a value to a pointer. For loading, see `deref`. |
| 249 | 254 | store, |
| 255 | /// Same as `store` but the type of the value being stored will be used to infer | |
| 256 | /// the pointer type. | |
| 257 | store_to_inferred_ptr, | |
| 250 | 258 | /// String Literal. Makes an anonymous Decl and then takes a pointer to it. |
| 251 | 259 | str, |
| 252 | 260 | /// Arithmetic subtraction. Asserts no integer overflow. |
| ... | ... | @@ -319,6 +327,7 @@ pub const Inst = struct { |
| 319 | 327 | .ref, |
| 320 | 328 | .bitcast_ref, |
| 321 | 329 | .typeof, |
| 330 | .resolve_inferred_alloc, | |
| 322 | 331 | .single_const_ptr_type, |
| 323 | 332 | .single_mut_ptr_type, |
| 324 | 333 | .many_const_ptr_type, |
| ... | ... | @@ -355,6 +364,7 @@ pub const Inst = struct { |
| 355 | 364 | .shl, |
| 356 | 365 | .shr, |
| 357 | 366 | .store, |
| 367 | .store_to_inferred_ptr, | |
| 358 | 368 | .sub, |
| 359 | 369 | .subwrap, |
| 360 | 370 | .cmp_lt, |
| ... | ... | @@ -498,6 +508,7 @@ pub const Inst = struct { |
| 498 | 508 | .mut_slice_type, |
| 499 | 509 | .const_slice_type, |
| 500 | 510 | .store, |
| 511 | .store_to_inferred_ptr, | |
| 501 | 512 | .str, |
| 502 | 513 | .sub, |
| 503 | 514 | .subwrap, |
| ... | ... | @@ -522,6 +533,7 @@ pub const Inst = struct { |
| 522 | 533 | .import, |
| 523 | 534 | .switch_range, |
| 524 | 535 | .typeof_peer, |
| 536 | .resolve_inferred_alloc, | |
| 525 | 537 | => false, |
| 526 | 538 | |
| 527 | 539 | .@"break", |
src/zir_sema.zig+87-10| ... | ... | @@ -10,10 +10,12 @@ |
| 10 | 10 | const std = @import("std"); |
| 11 | 11 | const mem = std.mem; |
| 12 | 12 | const Allocator = std.mem.Allocator; |
| 13 | const assert = std.debug.assert; | |
| 14 | const log = std.log.scoped(.sema); | |
| 15 | ||
| 13 | 16 | const Value = @import("value.zig").Value; |
| 14 | 17 | const Type = @import("type.zig").Type; |
| 15 | 18 | const TypedValue = @import("TypedValue.zig"); |
| 16 | const assert = std.debug.assert; | |
| 17 | 19 | const ir = @import("ir.zig"); |
| 18 | 20 | const zir = @import("zir.zig"); |
| 19 | 21 | const Module = @import("Module.zig"); |
| ... | ... | @@ -28,8 +30,18 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 28 | 30 | switch (old_inst.tag) { |
| 29 | 31 | .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?), |
| 30 | 32 | .alloc_mut => return analyzeInstAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?), |
| 31 | .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?), | |
| 32 | .alloc_inferred_mut => return analyzeInstAllocInferredMut(mod, scope, old_inst.castTag(.alloc_inferred_mut).?), | |
| 33 | .alloc_inferred => return analyzeInstAllocInferred( | |
| 34 | mod, | |
| 35 | scope, | |
| 36 | old_inst.castTag(.alloc_inferred).?, | |
| 37 | .inferred_alloc_const, | |
| 38 | ), | |
| 39 | .alloc_inferred_mut => return analyzeInstAllocInferred( | |
| 40 | mod, | |
| 41 | scope, | |
| 42 | old_inst.castTag(.alloc_inferred_mut).?, | |
| 43 | .inferred_alloc_mut, | |
| 44 | ), | |
| 33 | 45 | .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?), |
| 34 | 46 | .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?), |
| 35 | 47 | .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?), |
| ... | ... | @@ -55,8 +67,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 55 | 67 | .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?), |
| 56 | 68 | .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?), |
| 57 | 69 | .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), |
| 70 | .resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?), | |
| 58 | 71 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), |
| 59 | 72 | .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), |
| 73 | .store_to_inferred_ptr => return analyzeInstStoreToInferredPtr(mod, scope, old_inst.castTag(.store_to_inferred_ptr).?), | |
| 60 | 74 | .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), |
| 61 | 75 | .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), |
| 62 | 76 | .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), |
| ... | ... | @@ -419,20 +433,83 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro |
| 419 | 433 | |
| 420 | 434 | fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 421 | 435 | const var_type = try resolveType(mod, scope, inst.positionals.operand); |
| 422 | if (!var_type.isValidVarType(false)) { | |
| 423 | return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); | |
| 424 | } | |
| 436 | try mod.validateVarType(scope, inst.base.src, var_type); | |
| 425 | 437 | const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One); |
| 426 | 438 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 427 | 439 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 428 | 440 | } |
| 429 | 441 | |
| 430 | fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | |
| 431 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferred", .{}); | |
| 442 | fn analyzeInstAllocInferred( | |
| 443 | mod: *Module, | |
| 444 | scope: *Scope, | |
| 445 | inst: *zir.Inst.NoOp, | |
| 446 | mut_tag: Type.Tag, | |
| 447 | ) InnerError!*Inst { | |
| 448 | const val_payload = try scope.arena().create(Value.Payload.InferredAlloc); | |
| 449 | val_payload.* = .{ | |
| 450 | .data = .{}, | |
| 451 | }; | |
| 452 | // `Module.constInst` does not add the instruction to the block because it is | |
| 453 | // not needed in the case of constant values. However here, we plan to "downgrade" | |
| 454 | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append | |
| 455 | // to the block even though it is currently a `.constant`. | |
| 456 | const result = try mod.constInst(scope, inst.base.src, .{ | |
| 457 | .ty = switch (mut_tag) { | |
| 458 | .inferred_alloc_const => Type.initTag(.inferred_alloc_const), | |
| 459 | .inferred_alloc_mut => Type.initTag(.inferred_alloc_mut), | |
| 460 | else => unreachable, | |
| 461 | }, | |
| 462 | .val = Value.initPayload(&val_payload.base), | |
| 463 | }); | |
| 464 | const block = try mod.requireFunctionBlock(scope, inst.base.src); | |
| 465 | try block.instructions.append(mod.gpa, result); | |
| 466 | return result; | |
| 467 | } | |
| 468 | ||
| 469 | fn analyzeInstResolveInferredAlloc( | |
| 470 | mod: *Module, | |
| 471 | scope: *Scope, | |
| 472 | inst: *zir.Inst.UnOp, | |
| 473 | ) InnerError!*Inst { | |
| 474 | const ptr = try resolveInst(mod, scope, inst.positionals.operand); | |
| 475 | const ptr_val = ptr.castTag(.constant).?.val; | |
| 476 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | |
| 477 | const peer_inst_list = inferred_alloc.data.stored_inst_list.items; | |
| 478 | const final_elem_ty = try mod.resolvePeerTypes(scope, peer_inst_list); | |
| 479 | const var_is_mut = switch (ptr.ty.tag()) { | |
| 480 | .inferred_alloc_const => false, | |
| 481 | .inferred_alloc_mut => true, | |
| 482 | else => unreachable, | |
| 483 | }; | |
| 484 | if (var_is_mut) { | |
| 485 | try mod.validateVarType(scope, inst.base.src, final_elem_ty); | |
| 486 | } | |
| 487 | const final_ptr_ty = try mod.simplePtrType(scope, inst.base.src, final_elem_ty, true, .One); | |
| 488 | ||
| 489 | // Change it to a normal alloc. | |
| 490 | ptr.ty = final_ptr_ty; | |
| 491 | ptr.tag = .alloc; | |
| 492 | ||
| 493 | return mod.constVoid(scope, inst.base.src); | |
| 432 | 494 | } |
| 433 | 495 | |
| 434 | fn analyzeInstAllocInferredMut(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | |
| 435 | return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferredMut", .{}); | |
| 496 | fn analyzeInstStoreToInferredPtr( | |
| 497 | mod: *Module, | |
| 498 | scope: *Scope, | |
| 499 | inst: *zir.Inst.BinOp, | |
| 500 | ) InnerError!*Inst { | |
| 501 | const ptr = try resolveInst(mod, scope, inst.positionals.lhs); | |
| 502 | const value = try resolveInst(mod, scope, inst.positionals.rhs); | |
| 503 | const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?; | |
| 504 | // Add the stored instruction to the set we will use to resolve peer types | |
| 505 | // for the inferred allocation. | |
| 506 | try inferred_alloc.data.stored_inst_list.append(scope.arena(), value); | |
| 507 | // Create a new alloc with exactly the type the pointer wants. | |
| 508 | // Later it gets cleaned up by aliasing the alloc we are supposed to be storing to. | |
| 509 | const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One); | |
| 510 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); | |
| 511 | const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr); | |
| 512 | return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value); | |
| 436 | 513 | } |
| 437 | 514 | |
| 438 | 515 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { |
test/stage2/cbe.zig+17| ... | ... | @@ -51,6 +51,23 @@ pub fn addCases(ctx: *TestContext) !void { |
| 51 | 51 | , ""); |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | { | |
| 55 | var case = ctx.exeFromCompiledC("inferred local const and var", .{}); | |
| 56 | ||
| 57 | case.addCompareOutput( | |
| 58 | \\fn add(a: i32, b: i32) i32 { | |
| 59 | \\ return a + b; | |
| 60 | \\} | |
| 61 | \\ | |
| 62 | \\export fn main() c_int { | |
| 63 | \\ const x = add(1, 2); | |
| 64 | \\ var y = add(3, 0); | |
| 65 | \\ y -= x; | |
| 66 | \\ return y; | |
| 67 | \\} | |
| 68 | , ""); | |
| 69 | } | |
| 70 | ||
| 54 | 71 | ctx.c("empty start function", linux_x64, |
| 55 | 72 | \\export fn _start() noreturn { |
| 56 | 73 | \\ unreachable; |
test/stage2/test.zig+9| ... | ... | @@ -1322,4 +1322,13 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1322 | 1322 | \\} |
| 1323 | 1323 | , &[_][]const u8{":2:5: error: unused for label"}); |
| 1324 | 1324 | } |
| 1325 | ||
| 1326 | { | |
| 1327 | var case = ctx.exe("bad inferred variable type", linux_x64); | |
| 1328 | case.addError( | |
| 1329 | \\export fn foo() void { | |
| 1330 | \\ var x = null; | |
| 1331 | \\} | |
| 1332 | , &[_][]const u8{":2:9: error: variable of type '@Type(.Null)' must be const or comptime"}); | |
| 1333 | } | |
| 1325 | 1334 | } |