| author | |
| committer | |
| log | a46d24af1cf2885991c67bf39a2e639891c16121 |
| tree | d4f3c81b798cbae420819434c810a52b6817a85b |
| parent | 3f7d9b5fc19e4081236b3b63aebbc80e1b17f5b5 |
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 | } |
| 3191 | 3191 | ||
| 3192 | pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { | 3192 | pub fn simplePtrType( |
| 3193 | self: *Module, | ||
| 3194 | scope: *Scope, | ||
| 3195 | src: usize, | ||
| 3196 | elem_ty: Type, | ||
| 3197 | mutable: bool, | ||
| 3198 | size: std.builtin.TypeInfo.Pointer.Size, | ||
| 3199 | ) Allocator.Error!Type { | ||
| 3193 | 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( |
| 585 | 585 | ||
| 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 lvalue | 589 | // 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 as | 590 | // 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(" {"); |
| 276 | 276 | ||
| 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 | } |
| 539 | 541 | ||
| 542 | fn 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 | |||
| 540 | fn genBreakpoint(file: *C, inst: *Inst.NoOp) !?[]u8 { | 560 | fn 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; |
| 198 | 198 | ||
| 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 | } |
| 202 | 202 |
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 __int128 | 42 | #define int128_t __int128 |
| 43 | #define uint128_t unsigned __int128 | 43 | #define uint128_t unsigned __int128 |
| 44 | 44 | #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, |
| 82 | 83 | ||
| 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), |
| 160 | 161 | ||
| 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, |
| 388 | 392 | ||
| 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 | } |
| 808 | 816 | ||
| ... | @@ -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, | ||
| 946 | 956 | ||
| 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, |
| 1125 | 1136 | ||
| 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, |
| 1207 | 1219 | ||
| 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, |
| 1277 | 1290 | ||
| 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, |
| 1349 | 1363 | ||
| 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, |
| 1430 | 1445 | ||
| 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, |
| 1506 | 1522 | ||
| 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, |
| 1624 | 1640 | ||
| 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, |
| 1746 | 1763 | ||
| 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, |
| 1812 | 1830 | ||
| 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, |
| 1895 | 1914 | ||
| 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, |
| 1970 | 1990 | ||
| 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, |
| 2035 | 2056 | ||
| 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, |
| 2124 | 2146 | ||
| 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 | } |
| 2783 | 2813 | ||
| ... | @@ -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, |
| 2850 | 2881 | ||
| 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, |
| 2935 | 2967 | ||
| 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, | ||
| 3071 | 3107 | ||
| 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 | } |
| 3153 | 3190 | ||
| ... | @@ -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 | }; |
| 3266 | 3310 |
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; |
| 7 | const Target = std.Target; | 7 | const Target = std.Target; |
| 8 | const Allocator = std.mem.Allocator; | 8 | const Allocator = std.mem.Allocator; |
| 9 | const Module = @import("Module.zig"); | 9 | const Module = @import("Module.zig"); |
| 10 | const ir = @import("ir.zig"); | ||
| 10 | 11 | ||
| 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, | ||
| 104 | 108 | ||
| 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 | } |
| 194 | 199 | ||
| ... | @@ -383,6 +388,8 @@ pub const Value = extern union { | ... | @@ -383,6 +388,8 @@ pub const Value = extern union { |
| 383 | 388 | ||
| 384 | // memory is managed by the declaration | 389 | // 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 | } |
| 388 | 395 | ||
| ... | @@ -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 | } |
| 506 | 514 | ||
| ... | @@ -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, |
| 687 | 697 | ||
| 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, |
| 772 | 783 | ||
| 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, |
| 857 | 869 | ||
| 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, |
| 970 | 983 | ||
| 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, |
| 1059 | 1073 | ||
| 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, |
| 1217 | 1232 | ||
| 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, |
| 1293 | 1309 | ||
| 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, |
| 1606 | 1625 | ||
| 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, |
| 1691 | 1711 | ||
| 1692 | .empty_array => unreachable, // out of bounds array index | 1712 | .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 { |
| 1793 | 1813 | ||
| 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, | ||
| 1804 | 1826 | ||
| 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 { |
| 1890 | 1912 | ||
| 1891 | .undef => unreachable, | 1913 | .undef => unreachable, |
| 1892 | .unreachable_value => unreachable, | 1914 | .unreachable_value => unreachable, |
| 1915 | .inferred_alloc => unreachable, | ||
| 1893 | }; | 1916 | }; |
| 1894 | } | 1917 | } |
| 1895 | 1918 | ||
| ... | @@ -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 | }; |
| 2024 | 2060 | ||
| 2025 | /// Big enough to fit any non-BigInt value | 2061 | /// 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 attributes | 242 | /// 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, |
| 526 | 538 | ||
| 527 | .@"break", | 539 | .@"break", |
src/zir_sema.zig+59-2| ... | @@ -10,10 +10,12 @@ | ... | @@ -10,10 +10,12 @@ |
| 10 | const std = @import("std"); | 10 | const std = @import("std"); |
| 11 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const Allocator = std.mem.Allocator; | 12 | const Allocator = std.mem.Allocator; |
| 13 | const assert = std.debug.assert; | ||
| 14 | const log = std.log.scoped(.sema); | ||
| 15 | |||
| 13 | const Value = @import("value.zig").Value; | 16 | const Value = @import("value.zig").Value; |
| 14 | const Type = @import("type.zig").Type; | 17 | const Type = @import("type.zig").Type; |
| 15 | const TypedValue = @import("TypedValue.zig"); | 18 | const TypedValue = @import("TypedValue.zig"); |
| 16 | const assert = std.debug.assert; | ||
| 17 | const ir = @import("ir.zig"); | 19 | const ir = @import("ir.zig"); |
| 18 | const zir = @import("zir.zig"); | 20 | const zir = @import("zir.zig"); |
| 19 | const Module = @import("Module.zig"); | 21 | const 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 | } |
| 429 | 433 | ||
| 430 | fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 434 | fn 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 | } |
| 433 | 451 | ||
| 434 | fn analyzeInstAllocInferredMut(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 452 | fn 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 | } |
| 437 | 455 | ||
| 456 | fn 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 | |||
| 476 | fn 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 | |||
| 438 | fn analyzeInstStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 495 | fn 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 | } |
| 53 | 53 | ||
| 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; |