authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-31 16:28:08-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-12-31 16:28:08-08:00
log93bb1d93cd18e739410009e7c77048d151a93b10
tree67b36291211919b9751785eecf8858195bce42d6
parent6c2e0c2046a4c1d01587cc15ea2f59af32743eb4
parent982acc22fd8674a9efbe1e65e037c464ba610882
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7616 from ziglang/stage2-inferred-vars

stage2: inferred local variables

12 files changed, 347 insertions(+), 71 deletions(-)

src/Module.zig+14-1
......@@ -3189,7 +3189,14 @@ pub fn floatSub(
31893189 }
31903190}
31913191
3192pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {
3192pub 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 {
31933200 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
31943201 return Type.initTag(.const_slice_u8);
31953202 }
......@@ -3414,3 +3421,9 @@ pub fn getTarget(self: Module) Target {
34143421pub fn optimizeMode(self: Module) std.builtin.Mode {
34153422 return self.comp.bin_file.options.optimize_mode;
34163423}
3424
3425pub 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(
585585
586586 switch (tree.token_ids[node.mut_token]) {
587587 .Keyword_const => {
588 var resolve_inferred_alloc: ?*zir.Inst = null;
588589 // Depending on the type of AST the initialization expression is, we may need an lvalue
589590 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
590591 // the variable, no memory location needed.
......@@ -595,6 +596,7 @@ fn varDecl(
595596 break :r ResultLoc{ .ptr = alloc };
596597 } else {
597598 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred);
599 resolve_inferred_alloc = &alloc.base;
598600 break :r ResultLoc{ .inferred_ptr = alloc };
599601 }
600602 } else r: {
......@@ -604,6 +606,9 @@ fn varDecl(
604606 break :r .none;
605607 };
606608 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 }
607612 const sub_scope = try block_arena.create(Scope.LocalVal);
608613 sub_scope.* = .{
609614 .parent = scope,
......@@ -614,15 +619,20 @@ fn varDecl(
614619 return &sub_scope.base;
615620 },
616621 .Keyword_var => {
622 var resolve_inferred_alloc: ?*zir.Inst = null;
617623 const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: {
618624 const type_inst = try typeExpr(mod, scope, type_node);
619625 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst);
620626 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
621627 } 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 } };
624631 };
625632 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 }
626636 const sub_scope = try block_arena.create(Scope.LocalPtr);
627637 sub_scope.* = .{
628638 .parent = scope,
......@@ -2717,7 +2727,8 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
27172727 return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{});
27182728 },
27192729 .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;
27212732 },
27222733 .block_ptr => |block_ptr| {
27232734 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 {
285285 .arg => try genArg(&ctx),
286286 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
287287 .block => try genBlock(&ctx, file, inst.castTag(.block).?),
288 .bitcast => try genBitcast(&ctx, file, inst.castTag(.bitcast).?),
288289 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
289290 .call => try genCall(&ctx, file, inst.castTag(.call).?),
290291 .cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="),
......@@ -295,6 +296,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
295296 .cmp_neq => try genBinOp(&ctx, file, inst.castTag(.cmp_neq).?, "!="),
296297 .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),
297298 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),
299 .load => try genLoad(&ctx, file, inst.castTag(.load).?),
298300 .ret => try genRet(&ctx, file, inst.castTag(.ret).?),
299301 .retvoid => try genRetVoid(file),
300302 .store => try genStore(&ctx, file, inst.castTag(.store).?),
......@@ -429,6 +431,16 @@ fn genRetVoid(file: *C) !?[]u8 {
429431 return null;
430432}
431433
434fn 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
432444fn genRet(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
433445 try indent(file);
434446 const writer = file.main.writer();
......@@ -440,7 +452,6 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
440452 if (inst.base.isUnused())
441453 return null;
442454 try indent(file);
443 const op = inst.operand;
444455 const writer = file.main.writer();
445456 const name = try ctx.name();
446457 const from = try ctx.resolveInst(inst.operand);
......@@ -537,6 +548,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {
537548 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});
538549}
539550
551fn 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
540569fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {
541570 try indent(file);
542571 try file.main.writer().writeAll("zig_breakpoint();\n");
src/ir.zig+1-1
......@@ -196,7 +196,7 @@ pub const Inst = struct {
196196 pub fn value(base: *Inst) ?Value {
197197 if (base.ty.onePossibleValue()) |opv| return opv;
198198
199 const inst = base.cast(Constant) orelse return null;
199 const inst = base.castTag(.constant) orelse return null;
200200 return inst.val;
201201 }
202202
src/link/cbe.h+1-1
......@@ -41,4 +41,4 @@
4141#include <stdint.h>
4242#define int128_t __int128
4343#define uint128_t unsigned __int128
44
44#include <string.h>
src/test.zig+1
......@@ -782,6 +782,7 @@ pub const TestContext = struct {
782782 "-std=c89",
783783 "-pedantic",
784784 "-Werror",
785 "-Wno-declaration-after-statement",
785786 "--",
786787 "-lc",
787788 exe_path,
src/type.zig+125-54
......@@ -78,6 +78,8 @@ pub const Type = extern union {
7878 .const_slice,
7979 .mut_slice,
8080 .pointer,
81 .inferred_alloc_const,
82 .inferred_alloc_mut,
8183 => return .Pointer,
8284
8385 .optional,
......@@ -158,6 +160,9 @@ pub const Type = extern union {
158160 .optional_single_mut_pointer,
159161 => self.cast(Payload.ElemType),
160162
163 .inferred_alloc_const => unreachable,
164 .inferred_alloc_mut => unreachable,
165
161166 else => null,
162167 };
163168 }
......@@ -384,6 +389,8 @@ pub const Type = extern union {
384389 .enum_literal,
385390 .anyerror_void_error_union,
386391 .@"anyframe",
392 .inferred_alloc_const,
393 .inferred_alloc_mut,
387394 => unreachable,
388395
389396 .array_u8,
......@@ -686,6 +693,8 @@ pub const Type = extern union {
686693 const name = ty.castTag(.error_set_single).?.data;
687694 return out_stream.print("error{{{s}}}", .{name});
688695 },
696 .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),
697 .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),
689698 }
690699 unreachable;
691700 }
......@@ -733,6 +742,8 @@ pub const Type = extern union {
733742 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
734743 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
735744 .enum_literal => return Value.initTag(.enum_literal_type),
745 .inferred_alloc_const => unreachable,
746 .inferred_alloc_mut => unreachable,
736747 else => return Value.Tag.ty.create(allocator, self),
737748 }
738749 }
......@@ -803,6 +814,9 @@ pub const Type = extern union {
803814 .enum_literal,
804815 .empty_struct,
805816 => false,
817
818 .inferred_alloc_const => unreachable,
819 .inferred_alloc_mut => unreachable,
806820 };
807821 }
808822
......@@ -920,6 +934,8 @@ pub const Type = extern union {
920934 .@"undefined",
921935 .enum_literal,
922936 .empty_struct,
937 .inferred_alloc_const,
938 .inferred_alloc_mut,
923939 => unreachable,
924940 };
925941 }
......@@ -943,6 +959,8 @@ pub const Type = extern union {
943959 .enum_literal => unreachable,
944960 .single_const_pointer_to_comptime_int => unreachable,
945961 .empty_struct => unreachable,
962 .inferred_alloc_const => unreachable,
963 .inferred_alloc_mut => unreachable,
946964
947965 .u8,
948966 .i8,
......@@ -1121,6 +1139,8 @@ pub const Type = extern union {
11211139 .single_const_pointer,
11221140 .single_mut_pointer,
11231141 .single_const_pointer_to_comptime_int,
1142 .inferred_alloc_const,
1143 .inferred_alloc_mut,
11241144 => true,
11251145
11261146 .pointer => self.castTag(.pointer).?.data.size == .One,
......@@ -1203,6 +1223,8 @@ pub const Type = extern union {
12031223 .single_const_pointer,
12041224 .single_mut_pointer,
12051225 .single_const_pointer_to_comptime_int,
1226 .inferred_alloc_const,
1227 .inferred_alloc_mut,
12061228 => .One,
12071229
12081230 .pointer => self.castTag(.pointer).?.data.size,
......@@ -1273,6 +1295,8 @@ pub const Type = extern union {
12731295 .error_set,
12741296 .error_set_single,
12751297 .empty_struct,
1298 .inferred_alloc_const,
1299 .inferred_alloc_mut,
12761300 => false,
12771301
12781302 .const_slice,
......@@ -1345,6 +1369,8 @@ pub const Type = extern union {
13451369 .error_set,
13461370 .error_set_single,
13471371 .empty_struct,
1372 .inferred_alloc_const,
1373 .inferred_alloc_mut,
13481374 => false,
13491375
13501376 .single_const_pointer,
......@@ -1426,6 +1452,8 @@ pub const Type = extern union {
14261452 .error_set,
14271453 .error_set_single,
14281454 .empty_struct,
1455 .inferred_alloc_const,
1456 .inferred_alloc_mut,
14291457 => false,
14301458
14311459 .pointer => {
......@@ -1502,6 +1530,8 @@ pub const Type = extern union {
15021530 .error_set,
15031531 .error_set_single,
15041532 .empty_struct,
1533 .inferred_alloc_const,
1534 .inferred_alloc_mut,
15051535 => false,
15061536
15071537 .pointer => {
......@@ -1569,58 +1599,59 @@ pub const Type = extern union {
15691599 /// Asserts the type is a pointer or array type.
15701600 pub fn elemType(self: Type) Type {
15711601 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,
16241655
16251656 .array => self.castTag(.array).?.data.elem_type,
16261657 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
......@@ -1742,6 +1773,8 @@ pub const Type = extern union {
17421773 .error_set,
17431774 .error_set_single,
17441775 .empty_struct,
1776 .inferred_alloc_const,
1777 .inferred_alloc_mut,
17451778 => unreachable,
17461779
17471780 .array => self.castTag(.array).?.data.len,
......@@ -1808,6 +1841,8 @@ pub const Type = extern union {
18081841 .error_set,
18091842 .error_set_single,
18101843 .empty_struct,
1844 .inferred_alloc_const,
1845 .inferred_alloc_mut,
18111846 => unreachable,
18121847
18131848 .single_const_pointer,
......@@ -1891,6 +1926,8 @@ pub const Type = extern union {
18911926 .error_set,
18921927 .error_set_single,
18931928 .empty_struct,
1929 .inferred_alloc_const,
1930 .inferred_alloc_mut,
18941931 => false,
18951932
18961933 .int_signed,
......@@ -1966,6 +2003,8 @@ pub const Type = extern union {
19662003 .error_set,
19672004 .error_set_single,
19682005 .empty_struct,
2006 .inferred_alloc_const,
2007 .inferred_alloc_mut,
19692008 => false,
19702009
19712010 .int_unsigned,
......@@ -2031,6 +2070,8 @@ pub const Type = extern union {
20312070 .error_set,
20322071 .error_set_single,
20332072 .empty_struct,
2073 .inferred_alloc_const,
2074 .inferred_alloc_mut,
20342075 => unreachable,
20352076
20362077 .int_unsigned => .{
......@@ -2120,6 +2161,8 @@ pub const Type = extern union {
21202161 .error_set,
21212162 .error_set_single,
21222163 .empty_struct,
2164 .inferred_alloc_const,
2165 .inferred_alloc_mut,
21232166 => false,
21242167
21252168 .usize,
......@@ -2232,6 +2275,8 @@ pub const Type = extern union {
22322275 .error_set,
22332276 .error_set_single,
22342277 .empty_struct,
2278 .inferred_alloc_const,
2279 .inferred_alloc_mut,
22352280 => unreachable,
22362281 };
22372282 }
......@@ -2310,6 +2355,8 @@ pub const Type = extern union {
23102355 .error_set,
23112356 .error_set_single,
23122357 .empty_struct,
2358 .inferred_alloc_const,
2359 .inferred_alloc_mut,
23132360 => unreachable,
23142361 }
23152362 }
......@@ -2387,6 +2434,8 @@ pub const Type = extern union {
23872434 .error_set,
23882435 .error_set_single,
23892436 .empty_struct,
2437 .inferred_alloc_const,
2438 .inferred_alloc_mut,
23902439 => unreachable,
23912440 }
23922441 }
......@@ -2464,6 +2513,8 @@ pub const Type = extern union {
24642513 .error_set,
24652514 .error_set_single,
24662515 .empty_struct,
2516 .inferred_alloc_const,
2517 .inferred_alloc_mut,
24672518 => unreachable,
24682519 };
24692520 }
......@@ -2538,6 +2589,8 @@ pub const Type = extern union {
25382589 .error_set,
25392590 .error_set_single,
25402591 .empty_struct,
2592 .inferred_alloc_const,
2593 .inferred_alloc_mut,
25412594 => unreachable,
25422595 };
25432596 }
......@@ -2612,6 +2665,8 @@ pub const Type = extern union {
26122665 .error_set,
26132666 .error_set_single,
26142667 .empty_struct,
2668 .inferred_alloc_const,
2669 .inferred_alloc_mut,
26152670 => unreachable,
26162671 };
26172672 }
......@@ -2686,6 +2741,8 @@ pub const Type = extern union {
26862741 .error_set,
26872742 .error_set_single,
26882743 .empty_struct,
2744 .inferred_alloc_const,
2745 .inferred_alloc_mut,
26892746 => false,
26902747 };
26912748 }
......@@ -2778,6 +2835,8 @@ pub const Type = extern union {
27782835 ty = ty.castTag(.pointer).?.data.pointee_type;
27792836 continue;
27802837 },
2838 .inferred_alloc_const => unreachable,
2839 .inferred_alloc_mut => unreachable,
27812840 };
27822841 }
27832842
......@@ -2846,6 +2905,8 @@ pub const Type = extern union {
28462905 .error_set,
28472906 .error_set_single,
28482907 .empty_struct,
2908 .inferred_alloc_const,
2909 .inferred_alloc_mut,
28492910 => return false,
28502911
28512912 .c_const_pointer,
......@@ -2931,6 +2992,8 @@ pub const Type = extern union {
29312992 .c_const_pointer,
29322993 .c_mut_pointer,
29332994 .pointer,
2995 .inferred_alloc_const,
2996 .inferred_alloc_mut,
29342997 => unreachable,
29352998
29362999 .empty_struct => self.castTag(.empty_struct).?.data,
......@@ -3041,7 +3104,13 @@ pub const Type = extern union {
30413104 single_const_pointer_to_comptime_int,
30423105 anyerror_void_error_union,
30433106 @"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.
30453114 // After this, the tag requires a payload.
30463115
30473116 array_u8,
......@@ -3069,7 +3138,7 @@ pub const Type = extern union {
30693138 error_set_single,
30703139 empty_struct,
30713140
3072 pub const last_no_payload_tag = Tag.const_slice_u8;
3141 pub const last_no_payload_tag = Tag.inferred_alloc_const;
30733142 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
30743143
30753144 pub fn Type(comptime t: Tag) type {
......@@ -3116,6 +3185,8 @@ pub const Type = extern union {
31163185 .anyerror_void_error_union,
31173186 .@"anyframe",
31183187 .const_slice_u8,
3188 .inferred_alloc_const,
3189 .inferred_alloc_mut,
31193190 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
31203191
31213192 .array_u8,
src/value.zig+36
......@@ -7,6 +7,7 @@ const BigIntMutable = std.math.big.int.Mutable;
77const Target = std.Target;
88const Allocator = std.mem.Allocator;
99const Module = @import("Module.zig");
10const ir = @import("ir.zig");
1011
1112/// This is the raw data, with no bookkeeping, no memory awareness,
1213/// no de-duplication, and no type system awareness.
......@@ -101,6 +102,9 @@ pub const Value = extern union {
101102 enum_literal,
102103 error_set,
103104 @"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,
104108
105109 pub const last_no_payload_tag = Tag.bool_false;
106110 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -189,6 +193,7 @@ pub const Value = extern union {
189193 .float_128 => Payload.Float_128,
190194 .error_set => Payload.ErrorSet,
191195 .@"error" => Payload.Error,
196 .inferred_alloc => Payload.InferredAlloc,
192197 };
193198 }
194199
......@@ -383,6 +388,8 @@ pub const Value = extern union {
383388
384389 // memory is managed by the declaration
385390 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
391
392 .inferred_alloc => unreachable,
386393 }
387394 }
388395
......@@ -501,6 +508,7 @@ pub const Value = extern union {
501508 return out_stream.writeAll("}");
502509 },
503510 .@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}),
511 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
504512 };
505513 }
506514
......@@ -613,6 +621,7 @@ pub const Value = extern union {
613621 .enum_literal,
614622 .@"error",
615623 .empty_struct_value,
624 .inferred_alloc,
616625 => unreachable,
617626 };
618627 }
......@@ -683,6 +692,7 @@ pub const Value = extern union {
683692 .error_set,
684693 .@"error",
685694 .empty_struct_value,
695 .inferred_alloc,
686696 => unreachable,
687697
688698 .undef => unreachable,
......@@ -768,6 +778,7 @@ pub const Value = extern union {
768778 .error_set,
769779 .@"error",
770780 .empty_struct_value,
781 .inferred_alloc,
771782 => unreachable,
772783
773784 .undef => unreachable,
......@@ -853,6 +864,7 @@ pub const Value = extern union {
853864 .error_set,
854865 .@"error",
855866 .empty_struct_value,
867 .inferred_alloc,
856868 => unreachable,
857869
858870 .undef => unreachable,
......@@ -966,6 +978,7 @@ pub const Value = extern union {
966978 .error_set,
967979 .@"error",
968980 .empty_struct_value,
981 .inferred_alloc,
969982 => unreachable,
970983
971984 .zero,
......@@ -1055,6 +1068,7 @@ pub const Value = extern union {
10551068 .error_set,
10561069 .@"error",
10571070 .empty_struct_value,
1071 .inferred_alloc,
10581072 => unreachable,
10591073
10601074 .zero,
......@@ -1213,6 +1227,7 @@ pub const Value = extern union {
12131227 .error_set,
12141228 .@"error",
12151229 .empty_struct_value,
1230 .inferred_alloc,
12161231 => unreachable,
12171232
12181233 .zero,
......@@ -1289,6 +1304,7 @@ pub const Value = extern union {
12891304 .error_set,
12901305 .@"error",
12911306 .empty_struct_value,
1307 .inferred_alloc,
12921308 => unreachable,
12931309
12941310 .zero,
......@@ -1525,6 +1541,8 @@ pub const Value = extern union {
15251541 hasher.update(payload.name);
15261542 std.hash.autoHash(&hasher, payload.value);
15271543 },
1544
1545 .inferred_alloc => unreachable,
15281546 }
15291547 return hasher.final();
15301548 }
......@@ -1602,6 +1620,7 @@ pub const Value = extern union {
16021620 .error_set,
16031621 .@"error",
16041622 .empty_struct_value,
1623 .inferred_alloc,
16051624 => unreachable,
16061625
16071626 .ref_val => self.castTag(.ref_val).?.data,
......@@ -1687,6 +1706,7 @@ pub const Value = extern union {
16871706 .error_set,
16881707 .@"error",
16891708 .empty_struct_value,
1709 .inferred_alloc,
16901710 => unreachable,
16911711
16921712 .empty_array => unreachable, // out of bounds array index
......@@ -1793,6 +1813,7 @@ pub const Value = extern union {
17931813
17941814 .undef => unreachable,
17951815 .unreachable_value => unreachable,
1816 .inferred_alloc => unreachable,
17961817 .null_value => true,
17971818 };
17981819 }
......@@ -1801,6 +1822,7 @@ pub const Value = extern union {
18011822 pub fn isFloat(self: Value) bool {
18021823 return switch (self.tag()) {
18031824 .undef => unreachable,
1825 .inferred_alloc => unreachable,
18041826
18051827 .float_16,
18061828 .float_32,
......@@ -1890,6 +1912,7 @@ pub const Value = extern union {
18901912
18911913 .undef => unreachable,
18921914 .unreachable_value => unreachable,
1915 .inferred_alloc => unreachable,
18931916 };
18941917 }
18951918
......@@ -2020,6 +2043,19 @@ pub const Value = extern union {
20202043 value: u16,
20212044 },
20222045 };
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 };
20232059 };
20242060
20252061 /// Big enough to fit any non-BigInt value
src/zir.zig+12
......@@ -241,12 +241,20 @@ pub const Inst = struct {
241241 const_slice_type,
242242 /// Create a pointer type with attributes
243243 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,
244249 /// Slice operation `array_ptr[start..end:sentinel]`
245250 slice,
246251 /// Slice operation with just start `lhs[rhs..]`
247252 slice_start,
248253 /// Write a value to a pointer. For loading, see `deref`.
249254 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,
250258 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
251259 str,
252260 /// Arithmetic subtraction. Asserts no integer overflow.
......@@ -319,6 +327,7 @@ pub const Inst = struct {
319327 .ref,
320328 .bitcast_ref,
321329 .typeof,
330 .resolve_inferred_alloc,
322331 .single_const_ptr_type,
323332 .single_mut_ptr_type,
324333 .many_const_ptr_type,
......@@ -355,6 +364,7 @@ pub const Inst = struct {
355364 .shl,
356365 .shr,
357366 .store,
367 .store_to_inferred_ptr,
358368 .sub,
359369 .subwrap,
360370 .cmp_lt,
......@@ -498,6 +508,7 @@ pub const Inst = struct {
498508 .mut_slice_type,
499509 .const_slice_type,
500510 .store,
511 .store_to_inferred_ptr,
501512 .str,
502513 .sub,
503514 .subwrap,
......@@ -522,6 +533,7 @@ pub const Inst = struct {
522533 .import,
523534 .switch_range,
524535 .typeof_peer,
536 .resolve_inferred_alloc,
525537 => false,
526538
527539 .@"break",
src/zir_sema.zig+87-10
......@@ -10,10 +10,12 @@
1010const std = @import("std");
1111const mem = std.mem;
1212const Allocator = std.mem.Allocator;
13const assert = std.debug.assert;
14const log = std.log.scoped(.sema);
15
1316const Value = @import("value.zig").Value;
1417const Type = @import("type.zig").Type;
1518const TypedValue = @import("TypedValue.zig");
16const assert = std.debug.assert;
1719const ir = @import("ir.zig");
1820const zir = @import("zir.zig");
1921const Module = @import("Module.zig");
......@@ -28,8 +30,18 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
2830 switch (old_inst.tag) {
2931 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),
3032 .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 ),
3345 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
3446 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
3547 .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!
5567 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
5668 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
5769 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
70 .resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?),
5871 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
5972 .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).?),
6074 .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One),
6175 .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One),
6276 .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
419433
420434fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
421435 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);
425437 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);
426438 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
427439 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
428440}
429441
430fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
431 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferred", .{});
442fn 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
469fn 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);
432494}
433495
434fn analyzeInstAllocInferredMut(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
435 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferredMut", .{});
496fn 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);
436513}
437514
438515fn 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 {
5151 , "");
5252 }
5353
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
5471 ctx.c("empty start function", linux_x64,
5572 \\export fn _start() noreturn {
5673 \\ unreachable;
test/stage2/test.zig+9
......@@ -1322,4 +1322,13 @@ pub fn addCases(ctx: *TestContext) !void {
13221322 \\}
13231323 , &[_][]const u8{":2:5: error: unused for label"});
13241324 }
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 }
13251334}