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(...@@ -3189,7 +3189,14 @@ pub fn floatSub(
3189 }3189 }
3190}3190}
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 {
3193 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {3200 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
3194 return Type.initTag(.const_slice_u8);3201 return Type.initTag(.const_slice_u8);
3195 }3202 }
...@@ -3414,3 +3421,9 @@ pub fn getTarget(self: Module) Target {...@@ -3414,3 +3421,9 @@ pub fn getTarget(self: Module) Target {
3414pub fn optimizeMode(self: Module) std.builtin.Mode {3421pub fn optimizeMode(self: Module) std.builtin.Mode {
3415 return self.comp.bin_file.options.optimize_mode;3422 return self.comp.bin_file.options.optimize_mode;
3416}3423}
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(...@@ -585,6 +585,7 @@ fn varDecl(
585585
586 switch (tree.token_ids[node.mut_token]) {586 switch (tree.token_ids[node.mut_token]) {
587 .Keyword_const => {587 .Keyword_const => {
588 var resolve_inferred_alloc: ?*zir.Inst = null;
588 // Depending on the type of AST the initialization expression is, we may need an lvalue589 // Depending on the type of AST the initialization expression is, we may need an lvalue
589 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as590 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
590 // the variable, no memory location needed.591 // the variable, no memory location needed.
...@@ -595,6 +596,7 @@ fn varDecl(...@@ -595,6 +596,7 @@ fn varDecl(
595 break :r ResultLoc{ .ptr = alloc };596 break :r ResultLoc{ .ptr = alloc };
596 } else {597 } else {
597 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred);598 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred);
599 resolve_inferred_alloc = &alloc.base;
598 break :r ResultLoc{ .inferred_ptr = alloc };600 break :r ResultLoc{ .inferred_ptr = alloc };
599 }601 }
600 } else r: {602 } else r: {
...@@ -604,6 +606,9 @@ fn varDecl(...@@ -604,6 +606,9 @@ fn varDecl(
604 break :r .none;606 break :r .none;
605 };607 };
606 const init_inst = try expr(mod, scope, result_loc, init_node);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 const sub_scope = try block_arena.create(Scope.LocalVal);612 const sub_scope = try block_arena.create(Scope.LocalVal);
608 sub_scope.* = .{613 sub_scope.* = .{
609 .parent = scope,614 .parent = scope,
...@@ -614,15 +619,20 @@ fn varDecl(...@@ -614,15 +619,20 @@ fn varDecl(
614 return &sub_scope.base;619 return &sub_scope.base;
615 },620 },
616 .Keyword_var => {621 .Keyword_var => {
622 var resolve_inferred_alloc: ?*zir.Inst = null;
617 const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: {623 const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: {
618 const type_inst = try typeExpr(mod, scope, type_node);624 const type_inst = try typeExpr(mod, scope, type_node);
619 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst);625 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc_mut, type_inst);
620 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };626 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
621 } else a: {627 } else a: {
622 const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred_mut);628 const alloc = try addZIRNoOpT(mod, scope, name_src, .alloc_inferred_mut);
623 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred_mut).? } };629 resolve_inferred_alloc = &alloc.base;
630 break :a .{ .alloc = &alloc.base, .result_loc = .{ .inferred_ptr = alloc } };
624 };631 };
625 const init_inst = try expr(mod, scope, var_data.result_loc, init_node);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 const sub_scope = try block_arena.create(Scope.LocalPtr);636 const sub_scope = try block_arena.create(Scope.LocalPtr);
627 sub_scope.* = .{637 sub_scope.* = .{
628 .parent = scope,638 .parent = scope,
...@@ -2717,7 +2727,8 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr...@@ -2717,7 +2727,8 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
2717 return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{});2727 return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{});
2718 },2728 },
2719 .inferred_ptr => |alloc| {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 .block_ptr => |block_ptr| {2733 .block_ptr => |block_ptr| {
2723 return mod.fail(scope, result.src, "TODO implement rlWrap .block_ptr", .{});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,6 +285,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
285 .arg => try genArg(&ctx),285 .arg => try genArg(&ctx),
286 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),286 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
287 .block => try genBlock(&ctx, file, inst.castTag(.block).?),287 .block => try genBlock(&ctx, file, inst.castTag(.block).?),
288 .bitcast => try genBitcast(&ctx, file, inst.castTag(.bitcast).?),
288 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),289 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
289 .call => try genCall(&ctx, file, inst.castTag(.call).?),290 .call => try genCall(&ctx, file, inst.castTag(.call).?),
290 .cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="),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,6 +296,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
295 .cmp_neq => try genBinOp(&ctx, file, inst.castTag(.cmp_neq).?, "!="),296 .cmp_neq => try genBinOp(&ctx, file, inst.castTag(.cmp_neq).?, "!="),
296 .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),297 .dbg_stmt => try genDbgStmt(&ctx, inst.castTag(.dbg_stmt).?),
297 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),298 .intcast => try genIntCast(&ctx, file, inst.castTag(.intcast).?),
299 .load => try genLoad(&ctx, file, inst.castTag(.load).?),
298 .ret => try genRet(&ctx, file, inst.castTag(.ret).?),300 .ret => try genRet(&ctx, file, inst.castTag(.ret).?),
299 .retvoid => try genRetVoid(file),301 .retvoid => try genRetVoid(file),
300 .store => try genStore(&ctx, file, inst.castTag(.store).?),302 .store => try genStore(&ctx, file, inst.castTag(.store).?),
...@@ -429,6 +431,16 @@ fn genRetVoid(file: *C) !?[]u8 {...@@ -429,6 +431,16 @@ fn genRetVoid(file: *C) !?[]u8 {
429 return null;431 return null;
430}432}
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
432fn genRet(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {444fn genRet(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
433 try indent(file);445 try indent(file);
434 const writer = file.main.writer();446 const writer = file.main.writer();
...@@ -440,7 +452,6 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {...@@ -440,7 +452,6 @@ fn genIntCast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
440 if (inst.base.isUnused())452 if (inst.base.isUnused())
441 return null;453 return null;
442 try indent(file);454 try indent(file);
443 const op = inst.operand;
444 const writer = file.main.writer();455 const writer = file.main.writer();
445 const name = try ctx.name();456 const name = try ctx.name();
446 const from = try ctx.resolveInst(inst.operand);457 const from = try ctx.resolveInst(inst.operand);
...@@ -537,6 +548,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {...@@ -537,6 +548,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {
537 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});548 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});
538}549}
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
540fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {569fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {
541 try indent(file);570 try indent(file);
542 try file.main.writer().writeAll("zig_breakpoint();\n");571 try file.main.writer().writeAll("zig_breakpoint();\n");
src/ir.zig+1-1
...@@ -196,7 +196,7 @@ pub const Inst = struct {...@@ -196,7 +196,7 @@ pub const Inst = struct {
196 pub fn value(base: *Inst) ?Value {196 pub fn value(base: *Inst) ?Value {
197 if (base.ty.onePossibleValue()) |opv| return opv;197 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;
200 return inst.val;200 return inst.val;
201 }201 }
202202
src/link/cbe.h+1-1
...@@ -41,4 +41,4 @@...@@ -41,4 +41,4 @@
41#include <stdint.h>41#include <stdint.h>
42#define int128_t __int12842#define int128_t __int128
43#define uint128_t unsigned __int12843#define uint128_t unsigned __int128
4444#include <string.h>
src/test.zig+1
...@@ -782,6 +782,7 @@ pub const TestContext = struct {...@@ -782,6 +782,7 @@ pub const TestContext = struct {
782 "-std=c89",782 "-std=c89",
783 "-pedantic",783 "-pedantic",
784 "-Werror",784 "-Werror",
785 "-Wno-declaration-after-statement",
785 "--",786 "--",
786 "-lc",787 "-lc",
787 exe_path,788 exe_path,
src/type.zig+125-54
...@@ -78,6 +78,8 @@ pub const Type = extern union {...@@ -78,6 +78,8 @@ pub const Type = extern union {
78 .const_slice,78 .const_slice,
79 .mut_slice,79 .mut_slice,
80 .pointer,80 .pointer,
81 .inferred_alloc_const,
82 .inferred_alloc_mut,
81 => return .Pointer,83 => return .Pointer,
8284
83 .optional,85 .optional,
...@@ -158,6 +160,9 @@ pub const Type = extern union {...@@ -158,6 +160,9 @@ pub const Type = extern union {
158 .optional_single_mut_pointer,160 .optional_single_mut_pointer,
159 => self.cast(Payload.ElemType),161 => self.cast(Payload.ElemType),
160162
163 .inferred_alloc_const => unreachable,
164 .inferred_alloc_mut => unreachable,
165
161 else => null,166 else => null,
162 };167 };
163 }168 }
...@@ -384,6 +389,8 @@ pub const Type = extern union {...@@ -384,6 +389,8 @@ pub const Type = extern union {
384 .enum_literal,389 .enum_literal,
385 .anyerror_void_error_union,390 .anyerror_void_error_union,
386 .@"anyframe",391 .@"anyframe",
392 .inferred_alloc_const,
393 .inferred_alloc_mut,
387 => unreachable,394 => unreachable,
388395
389 .array_u8,396 .array_u8,
...@@ -686,6 +693,8 @@ pub const Type = extern union {...@@ -686,6 +693,8 @@ pub const Type = extern union {
686 const name = ty.castTag(.error_set_single).?.data;693 const name = ty.castTag(.error_set_single).?.data;
687 return out_stream.print("error{{{s}}}", .{name});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 unreachable;699 unreachable;
691 }700 }
...@@ -733,6 +742,8 @@ pub const Type = extern union {...@@ -733,6 +742,8 @@ pub const Type = extern union {
733 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),742 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
734 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),743 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
735 .enum_literal => return Value.initTag(.enum_literal_type),744 .enum_literal => return Value.initTag(.enum_literal_type),
745 .inferred_alloc_const => unreachable,
746 .inferred_alloc_mut => unreachable,
736 else => return Value.Tag.ty.create(allocator, self),747 else => return Value.Tag.ty.create(allocator, self),
737 }748 }
738 }749 }
...@@ -803,6 +814,9 @@ pub const Type = extern union {...@@ -803,6 +814,9 @@ pub const Type = extern union {
803 .enum_literal,814 .enum_literal,
804 .empty_struct,815 .empty_struct,
805 => false,816 => false,
817
818 .inferred_alloc_const => unreachable,
819 .inferred_alloc_mut => unreachable,
806 };820 };
807 }821 }
808822
...@@ -920,6 +934,8 @@ pub const Type = extern union {...@@ -920,6 +934,8 @@ pub const Type = extern union {
920 .@"undefined",934 .@"undefined",
921 .enum_literal,935 .enum_literal,
922 .empty_struct,936 .empty_struct,
937 .inferred_alloc_const,
938 .inferred_alloc_mut,
923 => unreachable,939 => unreachable,
924 };940 };
925 }941 }
...@@ -943,6 +959,8 @@ pub const Type = extern union {...@@ -943,6 +959,8 @@ pub const Type = extern union {
943 .enum_literal => unreachable,959 .enum_literal => unreachable,
944 .single_const_pointer_to_comptime_int => unreachable,960 .single_const_pointer_to_comptime_int => unreachable,
945 .empty_struct => unreachable,961 .empty_struct => unreachable,
962 .inferred_alloc_const => unreachable,
963 .inferred_alloc_mut => unreachable,
946964
947 .u8,965 .u8,
948 .i8,966 .i8,
...@@ -1121,6 +1139,8 @@ pub const Type = extern union {...@@ -1121,6 +1139,8 @@ pub const Type = extern union {
1121 .single_const_pointer,1139 .single_const_pointer,
1122 .single_mut_pointer,1140 .single_mut_pointer,
1123 .single_const_pointer_to_comptime_int,1141 .single_const_pointer_to_comptime_int,
1142 .inferred_alloc_const,
1143 .inferred_alloc_mut,
1124 => true,1144 => true,
11251145
1126 .pointer => self.castTag(.pointer).?.data.size == .One,1146 .pointer => self.castTag(.pointer).?.data.size == .One,
...@@ -1203,6 +1223,8 @@ pub const Type = extern union {...@@ -1203,6 +1223,8 @@ pub const Type = extern union {
1203 .single_const_pointer,1223 .single_const_pointer,
1204 .single_mut_pointer,1224 .single_mut_pointer,
1205 .single_const_pointer_to_comptime_int,1225 .single_const_pointer_to_comptime_int,
1226 .inferred_alloc_const,
1227 .inferred_alloc_mut,
1206 => .One,1228 => .One,
12071229
1208 .pointer => self.castTag(.pointer).?.data.size,1230 .pointer => self.castTag(.pointer).?.data.size,
...@@ -1273,6 +1295,8 @@ pub const Type = extern union {...@@ -1273,6 +1295,8 @@ pub const Type = extern union {
1273 .error_set,1295 .error_set,
1274 .error_set_single,1296 .error_set_single,
1275 .empty_struct,1297 .empty_struct,
1298 .inferred_alloc_const,
1299 .inferred_alloc_mut,
1276 => false,1300 => false,
12771301
1278 .const_slice,1302 .const_slice,
...@@ -1345,6 +1369,8 @@ pub const Type = extern union {...@@ -1345,6 +1369,8 @@ pub const Type = extern union {
1345 .error_set,1369 .error_set,
1346 .error_set_single,1370 .error_set_single,
1347 .empty_struct,1371 .empty_struct,
1372 .inferred_alloc_const,
1373 .inferred_alloc_mut,
1348 => false,1374 => false,
13491375
1350 .single_const_pointer,1376 .single_const_pointer,
...@@ -1426,6 +1452,8 @@ pub const Type = extern union {...@@ -1426,6 +1452,8 @@ pub const Type = extern union {
1426 .error_set,1452 .error_set,
1427 .error_set_single,1453 .error_set_single,
1428 .empty_struct,1454 .empty_struct,
1455 .inferred_alloc_const,
1456 .inferred_alloc_mut,
1429 => false,1457 => false,
14301458
1431 .pointer => {1459 .pointer => {
...@@ -1502,6 +1530,8 @@ pub const Type = extern union {...@@ -1502,6 +1530,8 @@ pub const Type = extern union {
1502 .error_set,1530 .error_set,
1503 .error_set_single,1531 .error_set_single,
1504 .empty_struct,1532 .empty_struct,
1533 .inferred_alloc_const,
1534 .inferred_alloc_mut,
1505 => false,1535 => false,
15061536
1507 .pointer => {1537 .pointer => {
...@@ -1569,58 +1599,59 @@ pub const Type = extern union {...@@ -1569,58 +1599,59 @@ pub const Type = extern union {
1569 /// Asserts the type is a pointer or array type.1599 /// Asserts the type is a pointer or array type.
1570 pub fn elemType(self: Type) Type {1600 pub fn elemType(self: Type) Type {
1571 return switch (self.tag()) {1601 return switch (self.tag()) {
1572 .u8,1602 .u8 => unreachable,
1573 .i8,1603 .i8 => unreachable,
1574 .u16,1604 .u16 => unreachable,
1575 .i16,1605 .i16 => unreachable,
1576 .u32,1606 .u32 => unreachable,
1577 .i32,1607 .i32 => unreachable,
1578 .u64,1608 .u64 => unreachable,
1579 .i64,1609 .i64 => unreachable,
1580 .usize,1610 .usize => unreachable,
1581 .isize,1611 .isize => unreachable,
1582 .c_short,1612 .c_short => unreachable,
1583 .c_ushort,1613 .c_ushort => unreachable,
1584 .c_int,1614 .c_int => unreachable,
1585 .c_uint,1615 .c_uint => unreachable,
1586 .c_long,1616 .c_long => unreachable,
1587 .c_ulong,1617 .c_ulong => unreachable,
1588 .c_longlong,1618 .c_longlong => unreachable,
1589 .c_ulonglong,1619 .c_ulonglong => unreachable,
1590 .c_longdouble,1620 .c_longdouble => unreachable,
1591 .f16,1621 .f16 => unreachable,
1592 .f32,1622 .f32 => unreachable,
1593 .f64,1623 .f64 => unreachable,
1594 .f128,1624 .f128 => unreachable,
1595 .c_void,1625 .c_void => unreachable,
1596 .bool,1626 .bool => unreachable,
1597 .void,1627 .void => unreachable,
1598 .type,1628 .type => unreachable,
1599 .anyerror,1629 .anyerror => unreachable,
1600 .comptime_int,1630 .comptime_int => unreachable,
1601 .comptime_float,1631 .comptime_float => unreachable,
1602 .noreturn,1632 .noreturn => unreachable,
1603 .@"null",1633 .@"null" => unreachable,
1604 .@"undefined",1634 .@"undefined" => unreachable,
1605 .fn_noreturn_no_args,1635 .fn_noreturn_no_args => unreachable,
1606 .fn_void_no_args,1636 .fn_void_no_args => unreachable,
1607 .fn_naked_noreturn_no_args,1637 .fn_naked_noreturn_no_args => unreachable,
1608 .fn_ccc_void_no_args,1638 .fn_ccc_void_no_args => unreachable,
1609 .function,1639 .function => unreachable,
1610 .int_unsigned,1640 .int_unsigned => unreachable,
1611 .int_signed,1641 .int_signed => unreachable,
1612 .optional,1642 .optional => unreachable,
1613 .optional_single_const_pointer,1643 .optional_single_const_pointer => unreachable,
1614 .optional_single_mut_pointer,1644 .optional_single_mut_pointer => unreachable,
1615 .enum_literal,1645 .enum_literal => unreachable,
1616 .error_union,1646 .error_union => unreachable,
1617 .@"anyframe",1647 .@"anyframe" => unreachable,
1618 .anyframe_T,1648 .anyframe_T => unreachable,
1619 .anyerror_void_error_union,1649 .anyerror_void_error_union => unreachable,
1620 .error_set,1650 .error_set => unreachable,
1621 .error_set_single,1651 .error_set_single => unreachable,
1622 .empty_struct,1652 .empty_struct => unreachable,
1623 => unreachable,1653 .inferred_alloc_const => unreachable,
1654 .inferred_alloc_mut => unreachable,
16241655
1625 .array => self.castTag(.array).?.data.elem_type,1656 .array => self.castTag(.array).?.data.elem_type,
1626 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,1657 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
...@@ -1742,6 +1773,8 @@ pub const Type = extern union {...@@ -1742,6 +1773,8 @@ pub const Type = extern union {
1742 .error_set,1773 .error_set,
1743 .error_set_single,1774 .error_set_single,
1744 .empty_struct,1775 .empty_struct,
1776 .inferred_alloc_const,
1777 .inferred_alloc_mut,
1745 => unreachable,1778 => unreachable,
17461779
1747 .array => self.castTag(.array).?.data.len,1780 .array => self.castTag(.array).?.data.len,
...@@ -1808,6 +1841,8 @@ pub const Type = extern union {...@@ -1808,6 +1841,8 @@ pub const Type = extern union {
1808 .error_set,1841 .error_set,
1809 .error_set_single,1842 .error_set_single,
1810 .empty_struct,1843 .empty_struct,
1844 .inferred_alloc_const,
1845 .inferred_alloc_mut,
1811 => unreachable,1846 => unreachable,
18121847
1813 .single_const_pointer,1848 .single_const_pointer,
...@@ -1891,6 +1926,8 @@ pub const Type = extern union {...@@ -1891,6 +1926,8 @@ pub const Type = extern union {
1891 .error_set,1926 .error_set,
1892 .error_set_single,1927 .error_set_single,
1893 .empty_struct,1928 .empty_struct,
1929 .inferred_alloc_const,
1930 .inferred_alloc_mut,
1894 => false,1931 => false,
18951932
1896 .int_signed,1933 .int_signed,
...@@ -1966,6 +2003,8 @@ pub const Type = extern union {...@@ -1966,6 +2003,8 @@ pub const Type = extern union {
1966 .error_set,2003 .error_set,
1967 .error_set_single,2004 .error_set_single,
1968 .empty_struct,2005 .empty_struct,
2006 .inferred_alloc_const,
2007 .inferred_alloc_mut,
1969 => false,2008 => false,
19702009
1971 .int_unsigned,2010 .int_unsigned,
...@@ -2031,6 +2070,8 @@ pub const Type = extern union {...@@ -2031,6 +2070,8 @@ pub const Type = extern union {
2031 .error_set,2070 .error_set,
2032 .error_set_single,2071 .error_set_single,
2033 .empty_struct,2072 .empty_struct,
2073 .inferred_alloc_const,
2074 .inferred_alloc_mut,
2034 => unreachable,2075 => unreachable,
20352076
2036 .int_unsigned => .{2077 .int_unsigned => .{
...@@ -2120,6 +2161,8 @@ pub const Type = extern union {...@@ -2120,6 +2161,8 @@ pub const Type = extern union {
2120 .error_set,2161 .error_set,
2121 .error_set_single,2162 .error_set_single,
2122 .empty_struct,2163 .empty_struct,
2164 .inferred_alloc_const,
2165 .inferred_alloc_mut,
2123 => false,2166 => false,
21242167
2125 .usize,2168 .usize,
...@@ -2232,6 +2275,8 @@ pub const Type = extern union {...@@ -2232,6 +2275,8 @@ pub const Type = extern union {
2232 .error_set,2275 .error_set,
2233 .error_set_single,2276 .error_set_single,
2234 .empty_struct,2277 .empty_struct,
2278 .inferred_alloc_const,
2279 .inferred_alloc_mut,
2235 => unreachable,2280 => unreachable,
2236 };2281 };
2237 }2282 }
...@@ -2310,6 +2355,8 @@ pub const Type = extern union {...@@ -2310,6 +2355,8 @@ pub const Type = extern union {
2310 .error_set,2355 .error_set,
2311 .error_set_single,2356 .error_set_single,
2312 .empty_struct,2357 .empty_struct,
2358 .inferred_alloc_const,
2359 .inferred_alloc_mut,
2313 => unreachable,2360 => unreachable,
2314 }2361 }
2315 }2362 }
...@@ -2387,6 +2434,8 @@ pub const Type = extern union {...@@ -2387,6 +2434,8 @@ pub const Type = extern union {
2387 .error_set,2434 .error_set,
2388 .error_set_single,2435 .error_set_single,
2389 .empty_struct,2436 .empty_struct,
2437 .inferred_alloc_const,
2438 .inferred_alloc_mut,
2390 => unreachable,2439 => unreachable,
2391 }2440 }
2392 }2441 }
...@@ -2464,6 +2513,8 @@ pub const Type = extern union {...@@ -2464,6 +2513,8 @@ pub const Type = extern union {
2464 .error_set,2513 .error_set,
2465 .error_set_single,2514 .error_set_single,
2466 .empty_struct,2515 .empty_struct,
2516 .inferred_alloc_const,
2517 .inferred_alloc_mut,
2467 => unreachable,2518 => unreachable,
2468 };2519 };
2469 }2520 }
...@@ -2538,6 +2589,8 @@ pub const Type = extern union {...@@ -2538,6 +2589,8 @@ pub const Type = extern union {
2538 .error_set,2589 .error_set,
2539 .error_set_single,2590 .error_set_single,
2540 .empty_struct,2591 .empty_struct,
2592 .inferred_alloc_const,
2593 .inferred_alloc_mut,
2541 => unreachable,2594 => unreachable,
2542 };2595 };
2543 }2596 }
...@@ -2612,6 +2665,8 @@ pub const Type = extern union {...@@ -2612,6 +2665,8 @@ pub const Type = extern union {
2612 .error_set,2665 .error_set,
2613 .error_set_single,2666 .error_set_single,
2614 .empty_struct,2667 .empty_struct,
2668 .inferred_alloc_const,
2669 .inferred_alloc_mut,
2615 => unreachable,2670 => unreachable,
2616 };2671 };
2617 }2672 }
...@@ -2686,6 +2741,8 @@ pub const Type = extern union {...@@ -2686,6 +2741,8 @@ pub const Type = extern union {
2686 .error_set,2741 .error_set,
2687 .error_set_single,2742 .error_set_single,
2688 .empty_struct,2743 .empty_struct,
2744 .inferred_alloc_const,
2745 .inferred_alloc_mut,
2689 => false,2746 => false,
2690 };2747 };
2691 }2748 }
...@@ -2778,6 +2835,8 @@ pub const Type = extern union {...@@ -2778,6 +2835,8 @@ pub const Type = extern union {
2778 ty = ty.castTag(.pointer).?.data.pointee_type;2835 ty = ty.castTag(.pointer).?.data.pointee_type;
2779 continue;2836 continue;
2780 },2837 },
2838 .inferred_alloc_const => unreachable,
2839 .inferred_alloc_mut => unreachable,
2781 };2840 };
2782 }2841 }
27832842
...@@ -2846,6 +2905,8 @@ pub const Type = extern union {...@@ -2846,6 +2905,8 @@ pub const Type = extern union {
2846 .error_set,2905 .error_set,
2847 .error_set_single,2906 .error_set_single,
2848 .empty_struct,2907 .empty_struct,
2908 .inferred_alloc_const,
2909 .inferred_alloc_mut,
2849 => return false,2910 => return false,
28502911
2851 .c_const_pointer,2912 .c_const_pointer,
...@@ -2931,6 +2992,8 @@ pub const Type = extern union {...@@ -2931,6 +2992,8 @@ pub const Type = extern union {
2931 .c_const_pointer,2992 .c_const_pointer,
2932 .c_mut_pointer,2993 .c_mut_pointer,
2933 .pointer,2994 .pointer,
2995 .inferred_alloc_const,
2996 .inferred_alloc_mut,
2934 => unreachable,2997 => unreachable,
29352998
2936 .empty_struct => self.castTag(.empty_struct).?.data,2999 .empty_struct => self.castTag(.empty_struct).?.data,
...@@ -3041,7 +3104,13 @@ pub const Type = extern union {...@@ -3041,7 +3104,13 @@ pub const Type = extern union {
3041 single_const_pointer_to_comptime_int,3104 single_const_pointer_to_comptime_int,
3042 anyerror_void_error_union,3105 anyerror_void_error_union,
3043 @"anyframe",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 // After this, the tag requires a payload.3114 // After this, the tag requires a payload.
30463115
3047 array_u8,3116 array_u8,
...@@ -3069,7 +3138,7 @@ pub const Type = extern union {...@@ -3069,7 +3138,7 @@ pub const Type = extern union {
3069 error_set_single,3138 error_set_single,
3070 empty_struct,3139 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;
3073 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;3142 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
30743143
3075 pub fn Type(comptime t: Tag) type {3144 pub fn Type(comptime t: Tag) type {
...@@ -3116,6 +3185,8 @@ pub const Type = extern union {...@@ -3116,6 +3185,8 @@ pub const Type = extern union {
3116 .anyerror_void_error_union,3185 .anyerror_void_error_union,
3117 .@"anyframe",3186 .@"anyframe",
3118 .const_slice_u8,3187 .const_slice_u8,
3188 .inferred_alloc_const,
3189 .inferred_alloc_mut,
3119 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),3190 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
31203191
3121 .array_u8,3192 .array_u8,
src/value.zig+36
...@@ -7,6 +7,7 @@ const BigIntMutable = std.math.big.int.Mutable;...@@ -7,6 +7,7 @@ const BigIntMutable = std.math.big.int.Mutable;
7const Target = std.Target;7const Target = std.Target;
8const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
9const Module = @import("Module.zig");9const Module = @import("Module.zig");
10const ir = @import("ir.zig");
1011
11/// This is the raw data, with no bookkeeping, no memory awareness,12/// This is the raw data, with no bookkeeping, no memory awareness,
12/// no de-duplication, and no type system awareness.13/// no de-duplication, and no type system awareness.
...@@ -101,6 +102,9 @@ pub const Value = extern union {...@@ -101,6 +102,9 @@ pub const Value = extern union {
101 enum_literal,102 enum_literal,
102 error_set,103 error_set,
103 @"error",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,
104108
105 pub const last_no_payload_tag = Tag.bool_false;109 pub const last_no_payload_tag = Tag.bool_false;
106 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;110 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -189,6 +193,7 @@ pub const Value = extern union {...@@ -189,6 +193,7 @@ pub const Value = extern union {
189 .float_128 => Payload.Float_128,193 .float_128 => Payload.Float_128,
190 .error_set => Payload.ErrorSet,194 .error_set => Payload.ErrorSet,
191 .@"error" => Payload.Error,195 .@"error" => Payload.Error,
196 .inferred_alloc => Payload.InferredAlloc,
192 };197 };
193 }198 }
194199
...@@ -383,6 +388,8 @@ pub const Value = extern union {...@@ -383,6 +388,8 @@ pub const Value = extern union {
383388
384 // memory is managed by the declaration389 // memory is managed by the declaration
385 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),390 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
391
392 .inferred_alloc => unreachable,
386 }393 }
387 }394 }
388395
...@@ -501,6 +508,7 @@ pub const Value = extern union {...@@ -501,6 +508,7 @@ pub const Value = extern union {
501 return out_stream.writeAll("}");508 return out_stream.writeAll("}");
502 },509 },
503 .@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}),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 }
506514
...@@ -613,6 +621,7 @@ pub const Value = extern union {...@@ -613,6 +621,7 @@ pub const Value = extern union {
613 .enum_literal,621 .enum_literal,
614 .@"error",622 .@"error",
615 .empty_struct_value,623 .empty_struct_value,
624 .inferred_alloc,
616 => unreachable,625 => unreachable,
617 };626 };
618 }627 }
...@@ -683,6 +692,7 @@ pub const Value = extern union {...@@ -683,6 +692,7 @@ pub const Value = extern union {
683 .error_set,692 .error_set,
684 .@"error",693 .@"error",
685 .empty_struct_value,694 .empty_struct_value,
695 .inferred_alloc,
686 => unreachable,696 => unreachable,
687697
688 .undef => unreachable,698 .undef => unreachable,
...@@ -768,6 +778,7 @@ pub const Value = extern union {...@@ -768,6 +778,7 @@ pub const Value = extern union {
768 .error_set,778 .error_set,
769 .@"error",779 .@"error",
770 .empty_struct_value,780 .empty_struct_value,
781 .inferred_alloc,
771 => unreachable,782 => unreachable,
772783
773 .undef => unreachable,784 .undef => unreachable,
...@@ -853,6 +864,7 @@ pub const Value = extern union {...@@ -853,6 +864,7 @@ pub const Value = extern union {
853 .error_set,864 .error_set,
854 .@"error",865 .@"error",
855 .empty_struct_value,866 .empty_struct_value,
867 .inferred_alloc,
856 => unreachable,868 => unreachable,
857869
858 .undef => unreachable,870 .undef => unreachable,
...@@ -966,6 +978,7 @@ pub const Value = extern union {...@@ -966,6 +978,7 @@ pub const Value = extern union {
966 .error_set,978 .error_set,
967 .@"error",979 .@"error",
968 .empty_struct_value,980 .empty_struct_value,
981 .inferred_alloc,
969 => unreachable,982 => unreachable,
970983
971 .zero,984 .zero,
...@@ -1055,6 +1068,7 @@ pub const Value = extern union {...@@ -1055,6 +1068,7 @@ pub const Value = extern union {
1055 .error_set,1068 .error_set,
1056 .@"error",1069 .@"error",
1057 .empty_struct_value,1070 .empty_struct_value,
1071 .inferred_alloc,
1058 => unreachable,1072 => unreachable,
10591073
1060 .zero,1074 .zero,
...@@ -1213,6 +1227,7 @@ pub const Value = extern union {...@@ -1213,6 +1227,7 @@ pub const Value = extern union {
1213 .error_set,1227 .error_set,
1214 .@"error",1228 .@"error",
1215 .empty_struct_value,1229 .empty_struct_value,
1230 .inferred_alloc,
1216 => unreachable,1231 => unreachable,
12171232
1218 .zero,1233 .zero,
...@@ -1289,6 +1304,7 @@ pub const Value = extern union {...@@ -1289,6 +1304,7 @@ pub const Value = extern union {
1289 .error_set,1304 .error_set,
1290 .@"error",1305 .@"error",
1291 .empty_struct_value,1306 .empty_struct_value,
1307 .inferred_alloc,
1292 => unreachable,1308 => unreachable,
12931309
1294 .zero,1310 .zero,
...@@ -1525,6 +1541,8 @@ pub const Value = extern union {...@@ -1525,6 +1541,8 @@ pub const Value = extern union {
1525 hasher.update(payload.name);1541 hasher.update(payload.name);
1526 std.hash.autoHash(&hasher, payload.value);1542 std.hash.autoHash(&hasher, payload.value);
1527 },1543 },
1544
1545 .inferred_alloc => unreachable,
1528 }1546 }
1529 return hasher.final();1547 return hasher.final();
1530 }1548 }
...@@ -1602,6 +1620,7 @@ pub const Value = extern union {...@@ -1602,6 +1620,7 @@ pub const Value = extern union {
1602 .error_set,1620 .error_set,
1603 .@"error",1621 .@"error",
1604 .empty_struct_value,1622 .empty_struct_value,
1623 .inferred_alloc,
1605 => unreachable,1624 => unreachable,
16061625
1607 .ref_val => self.castTag(.ref_val).?.data,1626 .ref_val => self.castTag(.ref_val).?.data,
...@@ -1687,6 +1706,7 @@ pub const Value = extern union {...@@ -1687,6 +1706,7 @@ pub const Value = extern union {
1687 .error_set,1706 .error_set,
1688 .@"error",1707 .@"error",
1689 .empty_struct_value,1708 .empty_struct_value,
1709 .inferred_alloc,
1690 => unreachable,1710 => unreachable,
16911711
1692 .empty_array => unreachable, // out of bounds array index1712 .empty_array => unreachable, // out of bounds array index
...@@ -1793,6 +1813,7 @@ pub const Value = extern union {...@@ -1793,6 +1813,7 @@ pub const Value = extern union {
17931813
1794 .undef => unreachable,1814 .undef => unreachable,
1795 .unreachable_value => unreachable,1815 .unreachable_value => unreachable,
1816 .inferred_alloc => unreachable,
1796 .null_value => true,1817 .null_value => true,
1797 };1818 };
1798 }1819 }
...@@ -1801,6 +1822,7 @@ pub const Value = extern union {...@@ -1801,6 +1822,7 @@ pub const Value = extern union {
1801 pub fn isFloat(self: Value) bool {1822 pub fn isFloat(self: Value) bool {
1802 return switch (self.tag()) {1823 return switch (self.tag()) {
1803 .undef => unreachable,1824 .undef => unreachable,
1825 .inferred_alloc => unreachable,
18041826
1805 .float_16,1827 .float_16,
1806 .float_32,1828 .float_32,
...@@ -1890,6 +1912,7 @@ pub const Value = extern union {...@@ -1890,6 +1912,7 @@ pub const Value = extern union {
18901912
1891 .undef => unreachable,1913 .undef => unreachable,
1892 .unreachable_value => unreachable,1914 .unreachable_value => unreachable,
1915 .inferred_alloc => unreachable,
1893 };1916 };
1894 }1917 }
18951918
...@@ -2020,6 +2043,19 @@ pub const Value = extern union {...@@ -2020,6 +2043,19 @@ pub const Value = extern union {
2020 value: u16,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 };
20242060
2025 /// Big enough to fit any non-BigInt value2061 /// Big enough to fit any non-BigInt value
src/zir.zig+12
...@@ -241,12 +241,20 @@ pub const Inst = struct {...@@ -241,12 +241,20 @@ pub const Inst = struct {
241 const_slice_type,241 const_slice_type,
242 /// Create a pointer type with attributes242 /// Create a pointer type with attributes
243 ptr_type,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 /// Slice operation `array_ptr[start..end:sentinel]`249 /// Slice operation `array_ptr[start..end:sentinel]`
245 slice,250 slice,
246 /// Slice operation with just start `lhs[rhs..]`251 /// Slice operation with just start `lhs[rhs..]`
247 slice_start,252 slice_start,
248 /// Write a value to a pointer. For loading, see `deref`.253 /// Write a value to a pointer. For loading, see `deref`.
249 store,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 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.258 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
251 str,259 str,
252 /// Arithmetic subtraction. Asserts no integer overflow.260 /// Arithmetic subtraction. Asserts no integer overflow.
...@@ -319,6 +327,7 @@ pub const Inst = struct {...@@ -319,6 +327,7 @@ pub const Inst = struct {
319 .ref,327 .ref,
320 .bitcast_ref,328 .bitcast_ref,
321 .typeof,329 .typeof,
330 .resolve_inferred_alloc,
322 .single_const_ptr_type,331 .single_const_ptr_type,
323 .single_mut_ptr_type,332 .single_mut_ptr_type,
324 .many_const_ptr_type,333 .many_const_ptr_type,
...@@ -355,6 +364,7 @@ pub const Inst = struct {...@@ -355,6 +364,7 @@ pub const Inst = struct {
355 .shl,364 .shl,
356 .shr,365 .shr,
357 .store,366 .store,
367 .store_to_inferred_ptr,
358 .sub,368 .sub,
359 .subwrap,369 .subwrap,
360 .cmp_lt,370 .cmp_lt,
...@@ -498,6 +508,7 @@ pub const Inst = struct {...@@ -498,6 +508,7 @@ pub const Inst = struct {
498 .mut_slice_type,508 .mut_slice_type,
499 .const_slice_type,509 .const_slice_type,
500 .store,510 .store,
511 .store_to_inferred_ptr,
501 .str,512 .str,
502 .sub,513 .sub,
503 .subwrap,514 .subwrap,
...@@ -522,6 +533,7 @@ pub const Inst = struct {...@@ -522,6 +533,7 @@ pub const Inst = struct {
522 .import,533 .import,
523 .switch_range,534 .switch_range,
524 .typeof_peer,535 .typeof_peer,
536 .resolve_inferred_alloc,
525 => false,537 => false,
526538
527 .@"break",539 .@"break",
src/zir_sema.zig+87-10
...@@ -10,10 +10,12 @@...@@ -10,10 +10,12 @@
10const std = @import("std");10const std = @import("std");
11const mem = std.mem;11const mem = std.mem;
12const Allocator = std.mem.Allocator;12const Allocator = std.mem.Allocator;
13const assert = std.debug.assert;
14const log = std.log.scoped(.sema);
15
13const Value = @import("value.zig").Value;16const Value = @import("value.zig").Value;
14const Type = @import("type.zig").Type;17const Type = @import("type.zig").Type;
15const TypedValue = @import("TypedValue.zig");18const TypedValue = @import("TypedValue.zig");
16const assert = std.debug.assert;
17const ir = @import("ir.zig");19const ir = @import("ir.zig");
18const zir = @import("zir.zig");20const zir = @import("zir.zig");
19const Module = @import("Module.zig");21const Module = @import("Module.zig");
...@@ -28,8 +30,18 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -28,8 +30,18 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
28 switch (old_inst.tag) {30 switch (old_inst.tag) {
29 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),31 .alloc => return analyzeInstAlloc(mod, scope, old_inst.castTag(.alloc).?),
30 .alloc_mut => return analyzeInstAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?),32 .alloc_mut => return analyzeInstAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?),
31 .alloc_inferred => return analyzeInstAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?),33 .alloc_inferred => return analyzeInstAllocInferred(
32 .alloc_inferred_mut => return analyzeInstAllocInferredMut(mod, scope, old_inst.castTag(.alloc_inferred_mut).?),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 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),45 .arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
34 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),46 .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
35 .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),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,8 +67,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
55 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),67 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
56 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),68 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
57 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),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 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),71 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
59 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),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 .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One),74 .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One),
61 .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One),75 .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One),
62 .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many),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,20 +433,83 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro
419433
420fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {434fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
421 const var_type = try resolveType(mod, scope, inst.positionals.operand);435 const var_type = try resolveType(mod, scope, inst.positionals.operand);
422 if (!var_type.isValidVarType(false)) {436 try mod.validateVarType(scope, inst.base.src, var_type);
423 return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type});
424 }
425 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);437 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);
426 const b = try mod.requireRuntimeBlock(scope, inst.base.src);438 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
427 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);439 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
428}440}
429441
430fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {442fn analyzeInstAllocInferred(
431 return mod.fail(scope, inst.base.src, "TODO implement 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);
432}494}
433495
434fn analyzeInstAllocInferredMut(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {496fn analyzeInstStoreToInferredPtr(
435 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferredMut", .{});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}
437514
438fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {515fn 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,6 +51,23 @@ pub fn addCases(ctx: *TestContext) !void {
51 , "");51 , "");
52 }52 }
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
54 ctx.c("empty start function", linux_x64,71 ctx.c("empty start function", linux_x64,
55 \\export fn _start() noreturn {72 \\export fn _start() noreturn {
56 \\ unreachable;73 \\ unreachable;
test/stage2/test.zig+9
...@@ -1322,4 +1322,13 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1322,4 +1322,13 @@ pub fn addCases(ctx: *TestContext) !void {
1322 \\}1322 \\}
1323 , &[_][]const u8{":2:5: error: unused for label"});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}