authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-31 01:54:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-31 01:54:02-07:00
loga46d24af1cf2885991c67bf39a2e639891c16121
treed4f3c81b798cbae420819434c810a52b6817a85b
parent3f7d9b5fc19e4081236b3b63aebbc80e1b17f5b5

stage2: inferred local variables

This patch introduces the following new things: Types: - inferred_alloc - This is a special value that tracks a set of types that have been stored to an inferred allocation. It does not support most of the normal type queries. However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. - The payload for this type simply points to the corresponding Value payload. Values: - inferred_alloc - This is a special value that tracks a set of types that have been stored to an inferred allocation. It does not support any of the normal value queries. ZIR instructions: - store_to_inferred_ptr, - Same as `store` but the type of the value being stored will be used to infer the pointer type. - resolve_inferred_alloc - Each `store_to_inferred_ptr` puts the type of the stored value into a set, and then `resolve_inferred_alloc` triggers peer type resolution on the set. The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which is the allocation that needs to have its type inferred. Changes to the C backend: * Implements the bitcast instruction. If the source and dest types are both pointers, uses a cast, otherwise uses memcpy. * Tests are run with -Wno-declaration-after-statement. Someday we can conform to this but not today. In ZIR form it looks like this: ```zir fn_body main { // unanalyzed %0 = dbg_stmt() =>%1 = alloc_inferred() %2 = declval_in_module(Decl(add)) %3 = deref(%2) %4 = param_type(%3, 0) %5 = const(TypedValue{ .ty = comptime_int, .val = 1}) %6 = as(%4, %5) %7 = param_type(%3, 1) %8 = const(TypedValue{ .ty = comptime_int, .val = 2}) %9 = as(%7, %8) %10 = call(%3, [%6, %9], modifier=auto) =>%11 = store_to_inferred_ptr(%1, %10) =>%12 = resolve_inferred_alloc(%1) %13 = dbg_stmt() %14 = ret_type() %15 = const(TypedValue{ .ty = comptime_int, .val = 3}) %16 = sub(%10, %15) %17 = as(%14, %16) %18 = return(%17) } // fn_body main ``` I have not played around with very many test cases yet. Some interesting ones that I want to look at before merging: ```zig var x = blk: { var y = foo(); y.a = 1; break :blk y; }; ``` In the above test case, x and y are supposed to alias. ```zig var x = if (bar()) blk: { var y = foo(); y.a = 1; break :blk y; } else blk: { var z = baz(); z.b = 1; break :blk z; }; ``` In the above test case, x, y, and z are supposed to alias. I also haven't tested with `var` instead of `const` yet.

11 files changed, 261 insertions(+), 58 deletions(-)

src/Module.zig+8-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 }
src/astgen.zig+12-1
...@@ -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 addZIRNoOp(mod, scope, name_src, .alloc_inferred_mut);
629 resolve_inferred_alloc = alloc;
623 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred_mut).? } };630 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred_mut).? } };
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+20
...@@ -275,6 +275,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {...@@ -275,6 +275,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
275 try writer.writeAll(" {");275 try writer.writeAll(" {");
276276
277 const func: *Module.Fn = func_payload.data;277 const func: *Module.Fn = func_payload.data;
278 //func.dump(module.*);
278 const instructions = func.analysis.success.instructions;279 const instructions = func.analysis.success.instructions;
279 if (instructions.len > 0) {280 if (instructions.len > 0) {
280 try writer.writeAll("\n");281 try writer.writeAll("\n");
...@@ -285,6 +286,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {...@@ -285,6 +286,7 @@ pub fn generate(file: *C, module: *Module, decl: *Decl) !void {
285 .arg => try genArg(&ctx),286 .arg => try genArg(&ctx),
286 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),287 .assembly => try genAsm(&ctx, file, inst.castTag(.assembly).?),
287 .block => try genBlock(&ctx, file, inst.castTag(.block).?),288 .block => try genBlock(&ctx, file, inst.castTag(.block).?),
289 .bitcast => try genBitcast(&ctx, file, inst.castTag(.bitcast).?),
288 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),290 .breakpoint => try genBreakpoint(file, inst.castTag(.breakpoint).?),
289 .call => try genCall(&ctx, file, inst.castTag(.call).?),291 .call => try genCall(&ctx, file, inst.castTag(.call).?),
290 .cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="),292 .cmp_eq => try genBinOp(&ctx, file, inst.castTag(.cmp_eq).?, "=="),
...@@ -537,6 +539,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {...@@ -537,6 +539,24 @@ fn genBlock(ctx: *Context, file: *C, inst: *Inst.Block) !?[]u8 {
537 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});539 return ctx.fail(ctx.decl.src(), "TODO: C backend: implement blocks", .{});
538}540}
539541
542fn genBitcast(ctx: *Context, file: *C, inst: *Inst.UnOp) !?[]u8 {
543 const writer = file.main.writer();
544 try indent(file);
545 const local_name = try ctx.name();
546 const operand = try ctx.resolveInst(inst.operand);
547 try renderTypeAndName(ctx, writer, inst.base.ty, local_name, .Const);
548 if (inst.base.ty.zigTypeTag() == .Pointer and inst.operand.ty.zigTypeTag() == .Pointer) {
549 try writer.writeAll(" = (");
550 try renderType(ctx, writer, inst.base.ty);
551 try writer.print("){s};\n", .{operand});
552 } else {
553 try writer.writeAll(";\n");
554 try indent(file);
555 try writer.print("memcpy(&{s}, &{s}, sizeof {s});\n", .{ local_name, operand, local_name });
556 }
557 return local_name;
558}
559
540fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {560fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 {
541 try indent(file);561 try indent(file);
542 try file.main.writer().writeAll("zig_breakpoint();\n");562 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+96-52
...@@ -78,6 +78,7 @@ pub const Type = extern union {...@@ -78,6 +78,7 @@ pub const Type = extern union {
78 .const_slice,78 .const_slice,
79 .mut_slice,79 .mut_slice,
80 .pointer,80 .pointer,
81 .inferred_alloc,
81 => return .Pointer,82 => return .Pointer,
8283
83 .optional,84 .optional,
...@@ -158,6 +159,8 @@ pub const Type = extern union {...@@ -158,6 +159,8 @@ pub const Type = extern union {
158 .optional_single_mut_pointer,159 .optional_single_mut_pointer,
159 => self.cast(Payload.ElemType),160 => self.cast(Payload.ElemType),
160161
162 .inferred_alloc => unreachable,
163
161 else => null,164 else => null,
162 };165 };
163 }166 }
...@@ -384,6 +387,7 @@ pub const Type = extern union {...@@ -384,6 +387,7 @@ pub const Type = extern union {
384 .enum_literal,387 .enum_literal,
385 .anyerror_void_error_union,388 .anyerror_void_error_union,
386 .@"anyframe",389 .@"anyframe",
390 .inferred_alloc,
387 => unreachable,391 => unreachable,
388392
389 .array_u8,393 .array_u8,
...@@ -686,6 +690,7 @@ pub const Type = extern union {...@@ -686,6 +690,7 @@ pub const Type = extern union {
686 const name = ty.castTag(.error_set_single).?.data;690 const name = ty.castTag(.error_set_single).?.data;
687 return out_stream.print("error{{{s}}}", .{name});691 return out_stream.print("error{{{s}}}", .{name});
688 },692 },
693 .inferred_alloc => return out_stream.writeAll("(inferred allocation type)"),
689 }694 }
690 unreachable;695 unreachable;
691 }696 }
...@@ -733,6 +738,7 @@ pub const Type = extern union {...@@ -733,6 +738,7 @@ pub const Type = extern union {
733 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),738 .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),739 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
735 .enum_literal => return Value.initTag(.enum_literal_type),740 .enum_literal => return Value.initTag(.enum_literal_type),
741 .inferred_alloc => unreachable,
736 else => return Value.Tag.ty.create(allocator, self),742 else => return Value.Tag.ty.create(allocator, self),
737 }743 }
738 }744 }
...@@ -803,6 +809,8 @@ pub const Type = extern union {...@@ -803,6 +809,8 @@ pub const Type = extern union {
803 .enum_literal,809 .enum_literal,
804 .empty_struct,810 .empty_struct,
805 => false,811 => false,
812
813 .inferred_alloc => unreachable,
806 };814 };
807 }815 }
808816
...@@ -920,6 +928,7 @@ pub const Type = extern union {...@@ -920,6 +928,7 @@ pub const Type = extern union {
920 .@"undefined",928 .@"undefined",
921 .enum_literal,929 .enum_literal,
922 .empty_struct,930 .empty_struct,
931 .inferred_alloc,
923 => unreachable,932 => unreachable,
924 };933 };
925 }934 }
...@@ -943,6 +952,7 @@ pub const Type = extern union {...@@ -943,6 +952,7 @@ pub const Type = extern union {
943 .enum_literal => unreachable,952 .enum_literal => unreachable,
944 .single_const_pointer_to_comptime_int => unreachable,953 .single_const_pointer_to_comptime_int => unreachable,
945 .empty_struct => unreachable,954 .empty_struct => unreachable,
955 .inferred_alloc => unreachable,
946956
947 .u8,957 .u8,
948 .i8,958 .i8,
...@@ -1121,6 +1131,7 @@ pub const Type = extern union {...@@ -1121,6 +1131,7 @@ pub const Type = extern union {
1121 .single_const_pointer,1131 .single_const_pointer,
1122 .single_mut_pointer,1132 .single_mut_pointer,
1123 .single_const_pointer_to_comptime_int,1133 .single_const_pointer_to_comptime_int,
1134 .inferred_alloc,
1124 => true,1135 => true,
11251136
1126 .pointer => self.castTag(.pointer).?.data.size == .One,1137 .pointer => self.castTag(.pointer).?.data.size == .One,
...@@ -1203,6 +1214,7 @@ pub const Type = extern union {...@@ -1203,6 +1214,7 @@ pub const Type = extern union {
1203 .single_const_pointer,1214 .single_const_pointer,
1204 .single_mut_pointer,1215 .single_mut_pointer,
1205 .single_const_pointer_to_comptime_int,1216 .single_const_pointer_to_comptime_int,
1217 .inferred_alloc,
1206 => .One,1218 => .One,
12071219
1208 .pointer => self.castTag(.pointer).?.data.size,1220 .pointer => self.castTag(.pointer).?.data.size,
...@@ -1273,6 +1285,7 @@ pub const Type = extern union {...@@ -1273,6 +1285,7 @@ pub const Type = extern union {
1273 .error_set,1285 .error_set,
1274 .error_set_single,1286 .error_set_single,
1275 .empty_struct,1287 .empty_struct,
1288 .inferred_alloc,
1276 => false,1289 => false,
12771290
1278 .const_slice,1291 .const_slice,
...@@ -1345,6 +1358,7 @@ pub const Type = extern union {...@@ -1345,6 +1358,7 @@ pub const Type = extern union {
1345 .error_set,1358 .error_set,
1346 .error_set_single,1359 .error_set_single,
1347 .empty_struct,1360 .empty_struct,
1361 .inferred_alloc,
1348 => false,1362 => false,
13491363
1350 .single_const_pointer,1364 .single_const_pointer,
...@@ -1426,6 +1440,7 @@ pub const Type = extern union {...@@ -1426,6 +1440,7 @@ pub const Type = extern union {
1426 .error_set,1440 .error_set,
1427 .error_set_single,1441 .error_set_single,
1428 .empty_struct,1442 .empty_struct,
1443 .inferred_alloc,
1429 => false,1444 => false,
14301445
1431 .pointer => {1446 .pointer => {
...@@ -1502,6 +1517,7 @@ pub const Type = extern union {...@@ -1502,6 +1517,7 @@ pub const Type = extern union {
1502 .error_set,1517 .error_set,
1503 .error_set_single,1518 .error_set_single,
1504 .empty_struct,1519 .empty_struct,
1520 .inferred_alloc,
1505 => false,1521 => false,
15061522
1507 .pointer => {1523 .pointer => {
...@@ -1569,58 +1585,58 @@ pub const Type = extern union {...@@ -1569,58 +1585,58 @@ pub const Type = extern union {
1569 /// Asserts the type is a pointer or array type.1585 /// Asserts the type is a pointer or array type.
1570 pub fn elemType(self: Type) Type {1586 pub fn elemType(self: Type) Type {
1571 return switch (self.tag()) {1587 return switch (self.tag()) {
1572 .u8,1588 .u8 => unreachable,
1573 .i8,1589 .i8 => unreachable,
1574 .u16,1590 .u16 => unreachable,
1575 .i16,1591 .i16 => unreachable,
1576 .u32,1592 .u32 => unreachable,
1577 .i32,1593 .i32 => unreachable,
1578 .u64,1594 .u64 => unreachable,
1579 .i64,1595 .i64 => unreachable,
1580 .usize,1596 .usize => unreachable,
1581 .isize,1597 .isize => unreachable,
1582 .c_short,1598 .c_short => unreachable,
1583 .c_ushort,1599 .c_ushort => unreachable,
1584 .c_int,1600 .c_int => unreachable,
1585 .c_uint,1601 .c_uint => unreachable,
1586 .c_long,1602 .c_long => unreachable,
1587 .c_ulong,1603 .c_ulong => unreachable,
1588 .c_longlong,1604 .c_longlong => unreachable,
1589 .c_ulonglong,1605 .c_ulonglong => unreachable,
1590 .c_longdouble,1606 .c_longdouble => unreachable,
1591 .f16,1607 .f16 => unreachable,
1592 .f32,1608 .f32 => unreachable,
1593 .f64,1609 .f64 => unreachable,
1594 .f128,1610 .f128 => unreachable,
1595 .c_void,1611 .c_void => unreachable,
1596 .bool,1612 .bool => unreachable,
1597 .void,1613 .void => unreachable,
1598 .type,1614 .type => unreachable,
1599 .anyerror,1615 .anyerror => unreachable,
1600 .comptime_int,1616 .comptime_int => unreachable,
1601 .comptime_float,1617 .comptime_float => unreachable,
1602 .noreturn,1618 .noreturn => unreachable,
1603 .@"null",1619 .@"null" => unreachable,
1604 .@"undefined",1620 .@"undefined" => unreachable,
1605 .fn_noreturn_no_args,1621 .fn_noreturn_no_args => unreachable,
1606 .fn_void_no_args,1622 .fn_void_no_args => unreachable,
1607 .fn_naked_noreturn_no_args,1623 .fn_naked_noreturn_no_args => unreachable,
1608 .fn_ccc_void_no_args,1624 .fn_ccc_void_no_args => unreachable,
1609 .function,1625 .function => unreachable,
1610 .int_unsigned,1626 .int_unsigned => unreachable,
1611 .int_signed,1627 .int_signed => unreachable,
1612 .optional,1628 .optional => unreachable,
1613 .optional_single_const_pointer,1629 .optional_single_const_pointer => unreachable,
1614 .optional_single_mut_pointer,1630 .optional_single_mut_pointer => unreachable,
1615 .enum_literal,1631 .enum_literal => unreachable,
1616 .error_union,1632 .error_union => unreachable,
1617 .@"anyframe",1633 .@"anyframe" => unreachable,
1618 .anyframe_T,1634 .anyframe_T => unreachable,
1619 .anyerror_void_error_union,1635 .anyerror_void_error_union => unreachable,
1620 .error_set,1636 .error_set => unreachable,
1621 .error_set_single,1637 .error_set_single => unreachable,
1622 .empty_struct,1638 .empty_struct => unreachable,
1623 => unreachable,1639 .inferred_alloc => unreachable,
16241640
1625 .array => self.castTag(.array).?.data.elem_type,1641 .array => self.castTag(.array).?.data.elem_type,
1626 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,1642 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
...@@ -1742,6 +1758,7 @@ pub const Type = extern union {...@@ -1742,6 +1758,7 @@ pub const Type = extern union {
1742 .error_set,1758 .error_set,
1743 .error_set_single,1759 .error_set_single,
1744 .empty_struct,1760 .empty_struct,
1761 .inferred_alloc,
1745 => unreachable,1762 => unreachable,
17461763
1747 .array => self.castTag(.array).?.data.len,1764 .array => self.castTag(.array).?.data.len,
...@@ -1808,6 +1825,7 @@ pub const Type = extern union {...@@ -1808,6 +1825,7 @@ pub const Type = extern union {
1808 .error_set,1825 .error_set,
1809 .error_set_single,1826 .error_set_single,
1810 .empty_struct,1827 .empty_struct,
1828 .inferred_alloc,
1811 => unreachable,1829 => unreachable,
18121830
1813 .single_const_pointer,1831 .single_const_pointer,
...@@ -1891,6 +1909,7 @@ pub const Type = extern union {...@@ -1891,6 +1909,7 @@ pub const Type = extern union {
1891 .error_set,1909 .error_set,
1892 .error_set_single,1910 .error_set_single,
1893 .empty_struct,1911 .empty_struct,
1912 .inferred_alloc,
1894 => false,1913 => false,
18951914
1896 .int_signed,1915 .int_signed,
...@@ -1966,6 +1985,7 @@ pub const Type = extern union {...@@ -1966,6 +1985,7 @@ pub const Type = extern union {
1966 .error_set,1985 .error_set,
1967 .error_set_single,1986 .error_set_single,
1968 .empty_struct,1987 .empty_struct,
1988 .inferred_alloc,
1969 => false,1989 => false,
19701990
1971 .int_unsigned,1991 .int_unsigned,
...@@ -2031,6 +2051,7 @@ pub const Type = extern union {...@@ -2031,6 +2051,7 @@ pub const Type = extern union {
2031 .error_set,2051 .error_set,
2032 .error_set_single,2052 .error_set_single,
2033 .empty_struct,2053 .empty_struct,
2054 .inferred_alloc,
2034 => unreachable,2055 => unreachable,
20352056
2036 .int_unsigned => .{2057 .int_unsigned => .{
...@@ -2120,6 +2141,7 @@ pub const Type = extern union {...@@ -2120,6 +2141,7 @@ pub const Type = extern union {
2120 .error_set,2141 .error_set,
2121 .error_set_single,2142 .error_set_single,
2122 .empty_struct,2143 .empty_struct,
2144 .inferred_alloc,
2123 => false,2145 => false,
21242146
2125 .usize,2147 .usize,
...@@ -2232,6 +2254,7 @@ pub const Type = extern union {...@@ -2232,6 +2254,7 @@ pub const Type = extern union {
2232 .error_set,2254 .error_set,
2233 .error_set_single,2255 .error_set_single,
2234 .empty_struct,2256 .empty_struct,
2257 .inferred_alloc,
2235 => unreachable,2258 => unreachable,
2236 };2259 };
2237 }2260 }
...@@ -2310,6 +2333,7 @@ pub const Type = extern union {...@@ -2310,6 +2333,7 @@ pub const Type = extern union {
2310 .error_set,2333 .error_set,
2311 .error_set_single,2334 .error_set_single,
2312 .empty_struct,2335 .empty_struct,
2336 .inferred_alloc,
2313 => unreachable,2337 => unreachable,
2314 }2338 }
2315 }2339 }
...@@ -2387,6 +2411,7 @@ pub const Type = extern union {...@@ -2387,6 +2411,7 @@ pub const Type = extern union {
2387 .error_set,2411 .error_set,
2388 .error_set_single,2412 .error_set_single,
2389 .empty_struct,2413 .empty_struct,
2414 .inferred_alloc,
2390 => unreachable,2415 => unreachable,
2391 }2416 }
2392 }2417 }
...@@ -2464,6 +2489,7 @@ pub const Type = extern union {...@@ -2464,6 +2489,7 @@ pub const Type = extern union {
2464 .error_set,2489 .error_set,
2465 .error_set_single,2490 .error_set_single,
2466 .empty_struct,2491 .empty_struct,
2492 .inferred_alloc,
2467 => unreachable,2493 => unreachable,
2468 };2494 };
2469 }2495 }
...@@ -2538,6 +2564,7 @@ pub const Type = extern union {...@@ -2538,6 +2564,7 @@ pub const Type = extern union {
2538 .error_set,2564 .error_set,
2539 .error_set_single,2565 .error_set_single,
2540 .empty_struct,2566 .empty_struct,
2567 .inferred_alloc,
2541 => unreachable,2568 => unreachable,
2542 };2569 };
2543 }2570 }
...@@ -2612,6 +2639,7 @@ pub const Type = extern union {...@@ -2612,6 +2639,7 @@ pub const Type = extern union {
2612 .error_set,2639 .error_set,
2613 .error_set_single,2640 .error_set_single,
2614 .empty_struct,2641 .empty_struct,
2642 .inferred_alloc,
2615 => unreachable,2643 => unreachable,
2616 };2644 };
2617 }2645 }
...@@ -2686,6 +2714,7 @@ pub const Type = extern union {...@@ -2686,6 +2714,7 @@ pub const Type = extern union {
2686 .error_set,2714 .error_set,
2687 .error_set_single,2715 .error_set_single,
2688 .empty_struct,2716 .empty_struct,
2717 .inferred_alloc,
2689 => false,2718 => false,
2690 };2719 };
2691 }2720 }
...@@ -2778,6 +2807,7 @@ pub const Type = extern union {...@@ -2778,6 +2807,7 @@ pub const Type = extern union {
2778 ty = ty.castTag(.pointer).?.data.pointee_type;2807 ty = ty.castTag(.pointer).?.data.pointee_type;
2779 continue;2808 continue;
2780 },2809 },
2810 .inferred_alloc => unreachable,
2781 };2811 };
2782 }2812 }
27832813
...@@ -2846,6 +2876,7 @@ pub const Type = extern union {...@@ -2846,6 +2876,7 @@ pub const Type = extern union {
2846 .error_set,2876 .error_set,
2847 .error_set_single,2877 .error_set_single,
2848 .empty_struct,2878 .empty_struct,
2879 .inferred_alloc,
2849 => return false,2880 => return false,
28502881
2851 .c_const_pointer,2882 .c_const_pointer,
...@@ -2931,6 +2962,7 @@ pub const Type = extern union {...@@ -2931,6 +2962,7 @@ pub const Type = extern union {
2931 .c_const_pointer,2962 .c_const_pointer,
2932 .c_mut_pointer,2963 .c_mut_pointer,
2933 .pointer,2964 .pointer,
2965 .inferred_alloc,
2934 => unreachable,2966 => unreachable,
29352967
2936 .empty_struct => self.castTag(.empty_struct).?.data,2968 .empty_struct => self.castTag(.empty_struct).?.data,
...@@ -3068,6 +3100,10 @@ pub const Type = extern union {...@@ -3068,6 +3100,10 @@ pub const Type = extern union {
3068 error_set,3100 error_set,
3069 error_set_single,3101 error_set_single,
3070 empty_struct,3102 empty_struct,
3103 /// This is a special value that tracks a set of types that have been stored
3104 /// to an inferred allocation. It does not support most of the normal type queries.
3105 /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
3106 inferred_alloc,
30713107
3072 pub const last_no_payload_tag = Tag.const_slice_u8;3108 pub const last_no_payload_tag = Tag.const_slice_u8;
3073 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;3109 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -3148,6 +3184,7 @@ pub const Type = extern union {...@@ -3148,6 +3184,7 @@ pub const Type = extern union {
3148 .error_set => Payload.Decl,3184 .error_set => Payload.Decl,
3149 .error_set_single => Payload.Name,3185 .error_set_single => Payload.Name,
3150 .empty_struct => Payload.ContainerScope,3186 .empty_struct => Payload.ContainerScope,
3187 .inferred_alloc => Payload.InferredAlloc,
3151 };3188 };
3152 }3189 }
31533190
...@@ -3261,6 +3298,13 @@ pub const Type = extern union {...@@ -3261,6 +3298,13 @@ pub const Type = extern union {
3261 base: Payload,3298 base: Payload,
3262 data: *Module.Scope.Container,3299 data: *Module.Scope.Container,
3263 };3300 };
3301
3302 pub const InferredAlloc = struct {
3303 pub const base_tag = Tag.inferred_alloc;
3304
3305 base: Payload = .{ .tag = base_tag },
3306 data: *Value.Payload.InferredAlloc,
3307 };
3264 };3308 };
3265};3309};
32663310
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+59-2
...@@ -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");
...@@ -55,8 +57,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -55,8 +57,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).?),57 .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).?),58 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
57 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),59 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
60 .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).?),61 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
59 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),62 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
63 .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),64 .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),65 .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),66 .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many),
...@@ -428,13 +432,66 @@ fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerE...@@ -428,13 +432,66 @@ fn analyzeInstAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerE
428}432}
429433
430fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {434fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
431 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferred", .{});435 const val_payload = try scope.arena().create(Value.Payload.InferredAlloc);
436 val_payload.* = .{
437 .data = .{},
438 };
439 // `Module.constInst` does not add the instruction to the block because it is
440 // not needed in the case of constant values. However here, we plan to "downgrade"
441 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
442 // to the block even though it is currently a `.constant`.
443 const result = try mod.constInst(scope, inst.base.src, .{
444 .ty = try Type.Tag.inferred_alloc.create(scope.arena(), val_payload),
445 .val = Value.initPayload(&val_payload.base),
446 });
447 const block = try mod.requireFunctionBlock(scope, inst.base.src);
448 try block.instructions.append(mod.gpa, result);
449 return result;
432}450}
433451
434fn analyzeInstAllocInferredMut(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {452fn analyzeInstAllocInferredMut(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
435 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferredMut", .{});453 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferredMut", .{});
436}454}
437455
456fn analyzeInstResolveInferredAlloc(
457 mod: *Module,
458 scope: *Scope,
459 inst: *zir.Inst.UnOp,
460) InnerError!*Inst {
461 const ptr = try resolveInst(mod, scope, inst.positionals.operand);
462 const ptr_val = ptr.castTag(.constant).?.val;
463 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
464 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
465 const final_elem_ty = try mod.resolvePeerTypes(scope, peer_inst_list);
466 const is_mut = true;
467 const final_ptr_ty = try mod.simplePtrType(scope, inst.base.src, final_elem_ty, is_mut, .One);
468
469 // Change it to a normal alloc.
470 ptr.ty = final_ptr_ty;
471 ptr.tag = .alloc;
472
473 return mod.constVoid(scope, inst.base.src);
474}
475
476fn analyzeInstStoreToInferredPtr(
477 mod: *Module,
478 scope: *Scope,
479 inst: *zir.Inst.BinOp,
480) InnerError!*Inst {
481 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);
482 const value = try resolveInst(mod, scope, inst.positionals.rhs);
483 const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;
484 // Add the stored instruction to the set we will use to resolve peer types
485 // for the inferred allocation.
486 try inferred_alloc.data.stored_inst_list.append(scope.arena(), value);
487 // Create a new alloc with exactly the type the pointer wants.
488 // Later it gets cleaned up by aliasing the alloc we are supposed to be storing to.
489 const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One);
490 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
491 const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr);
492 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
493}
494
438fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {495fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
439 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);496 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);
440 const value = try resolveInst(mod, scope, inst.positionals.rhs);497 const value = try resolveInst(mod, scope, inst.positionals.rhs);
test/stage2/cbe.zig+15
...@@ -51,6 +51,21 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -51,6 +51,21 @@ pub fn addCases(ctx: *TestContext) !void {
51 , "");51 , "");
52 }52 }
5353
54 {
55 var case = ctx.exeFromCompiledC("inferred local const", .{});
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 \\ return x - 3;
65 \\}
66 , "");
67 }
68
54 ctx.c("empty start function", linux_x64,69 ctx.c("empty start function", linux_x64,
55 \\export fn _start() noreturn {70 \\export fn _start() noreturn {
56 \\ unreachable;71 \\ unreachable;