authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-14 20:25:06+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-17 14:26:32+03:00
log012fac255f35b9cdbe18c14753a195de89d07d28
tree6c7a8290ea5cae3da198bc4c9d97b2ce19478a42
parentc52513e25b69cdd28c5af567b8d3d6a0d9fb979e
signature Commit is signed but in an unrecognized format.

stage2: fix optimization causing wrong optional child types


7 files changed, 199 insertions(+), 115 deletions(-)

src-self-hosted/Module.zig+65-52
......@@ -2200,8 +2200,11 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
22002200 };
22012201
22022202 const decl_tv = try decl.typedValue();
2203 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
2204 ty_payload.* = .{ .pointee_type = decl_tv.ty };
2203 const ty_payload = try scope.arena().create(Type.Payload.Pointer);
2204 ty_payload.* = .{
2205 .base = .{ .tag = .single_const_pointer },
2206 .pointee_type = decl_tv.ty,
2207 };
22052208 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
22062209 val_payload.* = .{ .decl = decl };
22072210
......@@ -2425,6 +2428,16 @@ pub fn cmpNumeric(
24252428 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
24262429}
24272430
2431fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2432 if (inst.value()) |val| {
2433 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2434 }
2435
2436 // TODO how do we get the result location
2437 const b = try self.requireRuntimeBlock(scope, inst.src);
2438 return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
2439}
2440
24282441fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
24292442 if (signed) {
24302443 const int_payload = try scope.arena().create(Type.Payload.IntSigned);
......@@ -2502,14 +2515,12 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25022515
25032516 // T to ?T
25042517 if (dest_type.zigTypeTag() == .Optional) {
2505 const child_type = dest_type.elemType();
2506 if (inst.value()) |val| {
2507 if (child_type.eql(inst.ty)) {
2508 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2509 }
2510 return self.fail(scope, inst.src, "TODO optional wrap {} to {}", .{ val, dest_type });
2511 } else if (child_type.eql(inst.ty)) {
2512 return self.fail(scope, inst.src, "TODO optional wrap {}", .{dest_type});
2518 var buf: Type.Payload.Pointer = undefined;
2519 const child_type = dest_type.optionalChild(&buf);
2520 if (child_type.eql(inst.ty)) {
2521 return self.wrapOptional(scope, dest_type, inst);
2522 } else if (try self.coerceNum(scope, child_type, inst)) |some| {
2523 return self.wrapOptional(scope, dest_type, some);
25132524 }
25142525 }
25152526
......@@ -2527,39 +2538,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25272538 }
25282539
25292540 // comptime known number to other number
2530 if (inst.value()) |val| {
2531 const src_zig_tag = inst.ty.zigTypeTag();
2532 const dst_zig_tag = dest_type.zigTypeTag();
2533
2534 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
2535 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2536 if (val.floatHasFraction()) {
2537 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
2538 }
2539 return self.fail(scope, inst.src, "TODO float to int", .{});
2540 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2541 if (!val.intFitsInType(dest_type, self.target())) {
2542 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
2543 }
2544 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2545 }
2546 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
2547 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2548 const res = val.floatCast(scope.arena(), dest_type, self.target()) catch |err| switch (err) {
2549 error.Overflow => return self.fail(
2550 scope,
2551 inst.src,
2552 "cast of value {} to type '{}' loses information",
2553 .{ val, dest_type },
2554 ),
2555 error.OutOfMemory => return error.OutOfMemory,
2556 };
2557 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
2558 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2559 return self.fail(scope, inst.src, "TODO int to float", .{});
2560 }
2561 }
2562 }
2541 if (try self.coerceNum(scope, dest_type, inst)) |some|
2542 return some;
25632543
25642544 // integer widening
25652545 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
......@@ -2591,6 +2571,42 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25912571 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
25922572}
25932573
2574pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*Inst {
2575 const val = inst.value() orelse return null;
2576 const src_zig_tag = inst.ty.zigTypeTag();
2577 const dst_zig_tag = dest_type.zigTypeTag();
2578
2579 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
2580 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2581 if (val.floatHasFraction()) {
2582 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
2583 }
2584 return self.fail(scope, inst.src, "TODO float to int", .{});
2585 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2586 if (!val.intFitsInType(dest_type, self.target())) {
2587 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
2588 }
2589 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2590 }
2591 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
2592 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2593 const res = val.floatCast(scope.arena(), dest_type, self.target()) catch |err| switch (err) {
2594 error.Overflow => return self.fail(
2595 scope,
2596 inst.src,
2597 "cast of value {} to type '{}' loses information",
2598 .{ val, dest_type },
2599 ),
2600 error.OutOfMemory => return error.OutOfMemory,
2601 };
2602 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
2603 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2604 return self.fail(scope, inst.src, "TODO int to float", .{});
2605 }
2606 }
2607 return null;
2608}
2609
25942610pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
25952611 if (ptr.ty.isConstPtr())
25962612 return self.fail(scope, src, "cannot assign to constant", .{});
......@@ -2878,15 +2894,12 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
28782894 return Value.initPayload(val_payload);
28792895}
28802896
2881pub fn singleMutPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type {
2882 const type_payload = try scope.arena().create(Type.Payload.SingleMutPointer);
2883 type_payload.* = .{ .pointee_type = elem_ty };
2884 return Type.initPayload(&type_payload.base);
2885}
2886
2887pub fn singleConstPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type {
2888 const type_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
2889 type_payload.* = .{ .pointee_type = elem_ty };
2897pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type {
2898 const type_payload = try scope.arena().create(Type.Payload.Pointer);
2899 type_payload.* = .{
2900 .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
2901 .pointee_type = elem_ty,
2902 };
28902903 return Type.initPayload(&type_payload.base);
28912904}
28922905
src-self-hosted/astgen.zig+1-1
......@@ -870,7 +870,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
870870 const int_type_payload = try scope.arena().create(Value.Payload.IntType);
871871 int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };
872872 const result = try addZIRInstConst(mod, scope, src, .{
873 .ty = Type.initTag(.comptime_int),
873 .ty = Type.initTag(.type),
874874 .val = Value.initPayload(&int_type_payload.base),
875875 });
876876 return rlWrap(mod, scope, rl, result);
src-self-hosted/codegen.zig+34-2
......@@ -682,6 +682,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
682682 .sub => return self.genSub(inst.castTag(.sub).?),
683683 .unreach => return MCValue{ .unreach = {} },
684684 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
685 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
685686 }
686687 }
687688
......@@ -840,6 +841,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
840841 }
841842 }
842843
844 fn genWrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
845 const optional_ty = inst.base.ty;
846
847 // No side effects, so if it's unreferenced, do nothing.
848 if (inst.base.isUnused())
849 return MCValue.dead;
850
851 // Optional type is just a boolean true
852 if (optional_ty.abiSize(self.target.*) == 1)
853 return MCValue{ .immediate = 1 };
854
855 switch (arch) {
856 else => return self.fail(inst.base.src, "TODO implement wrap optional for {}", .{self.target.cpu.arch}),
857 }
858 }
859
843860 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
844861 const elem_ty = inst.base.ty;
845862 if (!elem_ty.hasCodeGenBits())
......@@ -2028,9 +2045,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20282045 return mcv;
20292046 }
20302047
2031 fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) !MCValue {
2048 fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) error{ CodegenFail, OutOfMemory }!MCValue {
20322049 if (typed_value.val.isUndef())
2033 return MCValue.undef;
2050 return MCValue{ .undef = {} };
20342051 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
20352052 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
20362053 switch (typed_value.ty.zigTypeTag()) {
......@@ -2055,6 +2072,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20552072 },
20562073 .ComptimeInt => unreachable, // semantic analysis prevents this
20572074 .ComptimeFloat => unreachable, // semantic analysis prevents this
2075 .Optional => {
2076 if (typed_value.ty.isPtrLikeOptional()) {
2077 if (typed_value.val.isNull())
2078 return MCValue{ .immediate = 0 };
2079
2080 var buf: Type.Payload.Pointer = undefined;
2081 return self.genTypedValue(src, .{
2082 .ty = typed_value.ty.optionalChild(&buf),
2083 .val = typed_value.val,
2084 });
2085 } else if (typed_value.ty.abiSize(self.target.*) == 1) {
2086 return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) };
2087 }
2088 return self.fail(src, "TODO non pointer optionals", .{});
2089 },
20582090 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
20592091 }
20602092 }
src-self-hosted/ir.zig+2
......@@ -83,6 +83,7 @@ pub const Inst = struct {
8383 floatcast,
8484 intcast,
8585 unwrap_optional,
86 wrap_optional,
8687
8788 pub fn Type(tag: Tag) type {
8889 return switch (tag) {
......@@ -104,6 +105,7 @@ pub const Inst = struct {
104105 .intcast,
105106 .load,
106107 .unwrap_optional,
108 .wrap_optional,
107109 => UnOp,
108110
109111 .add,
src-self-hosted/type.zig+78-46
......@@ -107,6 +107,17 @@ pub const Type = extern union {
107107 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108108 }
109109
110 pub fn castPointer(self: Type) ?*Payload.Pointer {
111 return switch (self.tag()) {
112 .single_const_pointer,
113 .single_mut_pointer,
114 .optional_single_const_pointer,
115 .optional_single_mut_pointer,
116 => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise),
117 else => null,
118 };
119 }
120
110121 pub fn eql(a: Type, b: Type) bool {
111122 // As a shortcut, if the small tags / addresses match, we're done.
112123 if (a.tag_if_small_enough == b.tag_if_small_enough)
......@@ -126,8 +137,8 @@ pub const Type = extern union {
126137 .Null => return true,
127138 .Pointer => {
128139 // Hot path for common case:
129 if (a.cast(Payload.SingleConstPointer)) |a_payload| {
130 if (b.cast(Payload.SingleConstPointer)) |b_payload| {
140 if (a.castPointer()) |a_payload| {
141 if (b.castPointer()) |b_payload| {
131142 return eql(a_payload.pointee_type, b_payload.pointee_type);
132143 }
133144 }
......@@ -185,7 +196,9 @@ pub const Type = extern union {
185196 return true;
186197 },
187198 .Optional => {
188 return a.elemType().eql(b.elemType());
199 var buf_a: Payload.Pointer = undefined;
200 var buf_b: Payload.Pointer = undefined;
201 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
189202 },
190203 .Float,
191204 .Struct,
......@@ -249,7 +262,8 @@ pub const Type = extern union {
249262 }
250263 },
251264 .Optional => {
252 std.hash.autoHash(&hasher, self.elemType().hash());
265 var buf: Payload.Pointer = undefined;
266 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());
253267 },
254268 .Float,
255269 .Struct,
......@@ -326,8 +340,6 @@ pub const Type = extern union {
326340 };
327341 return Type{ .ptr_otherwise = &new_payload.base };
328342 },
329 .single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleConstPointer, "pointee_type"),
330 .single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleMutPointer, "pointee_type"),
331343 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
332344 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
333345 .function => {
......@@ -346,8 +358,11 @@ pub const Type = extern union {
346358 return Type{ .ptr_otherwise = &new_payload.base };
347359 },
348360 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),
349 .optional_single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleMutPointer, "pointee_type"),
350 .optional_single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleConstPointer, "pointee_type"),
361 .single_const_pointer,
362 .single_mut_pointer,
363 .optional_single_mut_pointer,
364 .optional_single_const_pointer,
365 => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"),
351366 }
352367 }
353368
......@@ -441,13 +456,13 @@ pub const Type = extern union {
441456 continue;
442457 },
443458 .single_const_pointer => {
444 const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", ty.ptr_otherwise);
459 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
445460 try out_stream.writeAll("*const ");
446461 ty = payload.pointee_type;
447462 continue;
448463 },
449464 .single_mut_pointer => {
450 const payload = @fieldParentPtr(Payload.SingleMutPointer, "base", ty.ptr_otherwise);
465 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
451466 try out_stream.writeAll("*");
452467 ty = payload.pointee_type;
453468 continue;
......@@ -467,13 +482,13 @@ pub const Type = extern union {
467482 continue;
468483 },
469484 .optional_single_const_pointer => {
470 const payload = @fieldParentPtr(Payload.OptionalSingleConstPointer, "base", ty.ptr_otherwise);
485 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
471486 try out_stream.writeAll("?*const ");
472487 ty = payload.pointee_type;
473488 continue;
474489 },
475490 .optional_single_mut_pointer => {
476 const payload = @fieldParentPtr(Payload.OptionalSingleMutPointer, "base", ty.ptr_otherwise);
491 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
477492 try out_stream.writeAll("?*");
478493 ty = payload.pointee_type;
479494 continue;
......@@ -658,7 +673,8 @@ pub const Type = extern union {
658673 },
659674
660675 .optional => {
661 const child_type = self.cast(Payload.Optional).?.child_type;
676 var buf: Payload.Pointer = undefined;
677 const child_type = self.optionalChild(&buf);
662678 if (!child_type.hasCodeGenBits()) return 1;
663679
664680 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
......@@ -750,7 +766,8 @@ pub const Type = extern union {
750766 },
751767
752768 .optional => {
753 const child_type = self.cast(Payload.Optional).?.child_type;
769 var buf: Payload.Pointer = undefined;
770 const child_type = self.optionalChild(&buf);
754771 if (!child_type.hasCodeGenBits()) return 1;
755772
756773 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
......@@ -990,7 +1007,23 @@ pub const Type = extern union {
9901007 };
9911008 }
9921009
993 /// Asserts the type is a pointer, optional or array type.
1010 /// Asserts that the type is an optional
1011 pub fn isPtrLikeOptional(self: Type) bool {
1012 switch (self.tag()) {
1013 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1014 .optional => {
1015 var buf: Payload.Pointer = undefined;
1016 const child_type = self.optionalChild(&buf);
1017 // optionals of zero sized pointers behave like bools
1018 if (!child_type.hasCodeGenBits()) return false;
1019
1020 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();
1021 },
1022 else => unreachable,
1023 }
1024 }
1025
1026 /// Asserts the type is a pointer or array type.
9941027 pub fn elemType(self: Type) Type {
9951028 return switch (self.tag()) {
9961029 .u8,
......@@ -1033,16 +1066,38 @@ pub const Type = extern union {
10331066 .function,
10341067 .int_unsigned,
10351068 .int_signed,
1069 .optional,
1070 .optional_single_const_pointer,
1071 .optional_single_mut_pointer,
10361072 => unreachable,
10371073
10381074 .array => self.cast(Payload.Array).?.elem_type,
1039 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
1040 .single_mut_pointer => self.cast(Payload.SingleMutPointer).?.pointee_type,
1075 .single_const_pointer => self.castPointer().?.pointee_type,
1076 .single_mut_pointer => self.castPointer().?.pointee_type,
10411077 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
10421078 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1079 };
1080 }
1081
1082 /// Asserts that the type is an optional.
1083 pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type {
1084 return switch (self.tag()) {
10431085 .optional => self.cast(Payload.Optional).?.child_type,
1044 .optional_single_mut_pointer => self.cast(Payload.OptionalSingleMutPointer).?.pointee_type,
1045 .optional_single_const_pointer => self.cast(Payload.OptionalSingleConstPointer).?.pointee_type,
1086 .optional_single_mut_pointer => {
1087 buf.* = .{
1088 .base = .{ .tag = .single_mut_pointer },
1089 .pointee_type = self.castPointer().?.pointee_type
1090 };
1091 return Type.initPayload(&buf.base);
1092 },
1093 .optional_single_const_pointer => {
1094 buf.* = .{
1095 .base = .{ .tag = .single_const_pointer },
1096 .pointee_type = self.castPointer().?.pointee_type
1097 };
1098 return Type.initPayload(&buf.base);
1099 },
1100 else => unreachable,
10461101 };
10471102 }
10481103
......@@ -1901,13 +1956,8 @@ pub const Type = extern union {
19011956 ty = array.elem_type;
19021957 continue;
19031958 },
1904 .single_const_pointer => {
1905 const ptr = ty.cast(Payload.SingleConstPointer).?;
1906 ty = ptr.pointee_type;
1907 continue;
1908 },
1909 .single_mut_pointer => {
1910 const ptr = ty.cast(Payload.SingleMutPointer).?;
1959 .single_const_pointer, .single_mut_pointer => {
1960 const ptr = ty.castPointer().?;
19111961 ty = ptr.pointee_type;
19121962 continue;
19131963 },
......@@ -2049,14 +2099,8 @@ pub const Type = extern union {
20492099 len: u64,
20502100 };
20512101
2052 pub const SingleConstPointer = struct {
2053 base: Payload = Payload{ .tag = .single_const_pointer },
2054
2055 pointee_type: Type,
2056 };
2057
2058 pub const SingleMutPointer = struct {
2059 base: Payload = Payload{ .tag = .single_mut_pointer },
2102 pub const Pointer = struct {
2103 base: Payload,
20602104
20612105 pointee_type: Type,
20622106 };
......@@ -2086,18 +2130,6 @@ pub const Type = extern union {
20862130
20872131 child_type: Type,
20882132 };
2089
2090 pub const OptionalSingleConstPointer = struct {
2091 base: Payload = Payload{ .tag = .optional_single_const_pointer },
2092
2093 pointee_type: Type,
2094 };
2095
2096 pub const OptionalSingleMutPointer = struct {
2097 base: Payload = Payload{ .tag = .optional_single_mut_pointer },
2098
2099 pointee_type: Type,
2100 };
21012133 };
21022134};
21032135
src-self-hosted/zir.zig+3-1
......@@ -2017,6 +2017,7 @@ const EmitZIR = struct {
20172017 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
20182018 .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),
20192019 .unwrap_optional => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional).?, .unwrap_optional_unsafe),
2020 .wrap_optional => try self.emitCast(inst.src, new_body, inst.castTag(.wrap_optional).?, .as),
20202021
20212022 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
20222023 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
......@@ -2360,6 +2361,7 @@ const EmitZIR = struct {
23602361 }
23612362 },
23622363 .Optional => {
2364 var buf: Type.Payload.Pointer = undefined;
23632365 const inst = try self.arena.allocator.create(Inst.UnOp);
23642366 inst.* = .{
23652367 .base = .{
......@@ -2367,7 +2369,7 @@ const EmitZIR = struct {
23672369 .tag = .optional_type,
23682370 },
23692371 .positionals = .{
2370 .operand = (try self.emitType(src, ty.elemType())).inst,
2372 .operand = (try self.emitType(src, ty.optionalChild(&buf))).inst,
23712373 },
23722374 .kw_args = .{},
23732375 };
src-self-hosted/zir_sema.zig+16-13
......@@ -317,7 +317,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr
317317
318318fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
319319 const operand = try resolveInst(mod, scope, inst.positionals.operand);
320 const ptr_type = try mod.singleConstPtrType(scope, inst.base.src, operand.ty);
320 const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty);
321321
322322 if (operand.value()) |val| {
323323 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
......@@ -358,7 +358,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
358358
359359fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
360360 const var_type = try resolveType(mod, scope, inst.positionals.operand);
361 const ptr_type = try mod.singleMutPtrType(scope, inst.base.src, var_type);
361 const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type);
362362 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
363363 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
364364}
......@@ -674,15 +674,17 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp
674674
675675 return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {
676676 .single_const_pointer => blk: {
677 const payload = try scope.arena().create(Type.Payload.OptionalSingleConstPointer);
677 const payload = try scope.arena().create(Type.Payload.Pointer);
678678 payload.* = .{
679 .base = .{ .tag = .optional_single_const_pointer },
679680 .pointee_type = child_type.elemType(),
680681 };
681682 break :blk &payload.base;
682683 },
683684 .single_mut_pointer => blk: {
684 const payload = try scope.arena().create(Type.Payload.OptionalSingleMutPointer);
685 const payload = try scope.arena().create(Type.Payload.Pointer);
685686 payload.* = .{
687 .base = .{ .tag = .optional_single_mut_pointer },
686688 .pointee_type = child_type.elemType(),
687689 };
688690 break :blk &payload.base;
......@@ -705,11 +707,9 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
705707 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()});
706708 }
707709
708 const child_type = operand.ty.elemType().elemType();
709 const child_pointer = if (operand.ty.isConstPtr())
710 try mod.singleConstPtrType(scope, unwrap.base.src, child_type)
711 else
712 try mod.singleMutPtrType(scope, unwrap.base.src, child_type);
710 var buf: Type.Payload.Pointer = undefined;
711 const child_type = try operand.ty.elemType().optionalChild(&buf).copy(scope.arena());
712 const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type);
713713
714714 if (operand.value()) |val| {
715715 if (val.isNull()) {
......@@ -913,8 +913,11 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
913913 // required a larger index.
914914 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
915915
916 const type_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
917 type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };
916 const type_payload = try scope.arena().create(Type.Payload.Pointer);
917 type_payload.* = .{
918 .base = .{ .tag = .single_const_pointer },
919 .pointee_type = array_ptr.ty.elemType().elemType(),
920 };
918921
919922 return mod.constInst(scope, inst.base.src, .{
920923 .ty = Type.initPayload(&type_payload.base),
......@@ -1279,13 +1282,13 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr
12791282
12801283fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
12811284 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1282 const ty = try mod.singleConstPtrType(scope, inst.base.src, elem_type);
1285 const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type);
12831286 return mod.constType(scope, inst.base.src, ty);
12841287}
12851288
12861289fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
12871290 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1288 const ty = try mod.singleMutPtrType(scope, inst.base.src, elem_type);
1291 const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type);
12891292 return mod.constType(scope, inst.base.src, ty);
12901293}
12911294