Commit 7c15c9428e

Vexu <git@vexu.eu>
2020-08-18 11:24:23
stage2: array types
1 parent 3eb8f7b
Changed files (5)
src-self-hosted/astgen.zig
@@ -128,6 +128,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),
         .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),
         .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr),
+        .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)),
+        .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)),
 
         .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
         .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
@@ -141,8 +143,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}),
         .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
         .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
-        .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}),
-        .ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}),
         .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),
         .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
         .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
@@ -485,6 +485,48 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir
     return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
 }
 
+fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst {
+    const tree = scope.tree();
+    const src = tree.token_locs[node.op_token].start;
+    const meta_type = try addZIRInstConst(mod, scope, src, .{
+        .ty = Type.initTag(.type),
+        .val = Value.initTag(.type_type),
+    });
+    const usize_type = try addZIRInstConst(mod, scope, src, .{
+        .ty = Type.initTag(.type),
+        .val = Value.initTag(.usize_type),
+    });
+
+    const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
+    const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
+
+    return addZIRBinOp(mod, scope, src, .array_type, len, child_type);
+}
+
+fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst {
+    const tree = scope.tree();
+    const src = tree.token_locs[node.op_token].start;
+    const meta_type = try addZIRInstConst(mod, scope, src, .{
+        .ty = Type.initTag(.type),
+        .val = Value.initTag(.type_type),
+    });
+    const usize_type = try addZIRInstConst(mod, scope, src, .{
+        .ty = Type.initTag(.type),
+        .val = Value.initTag(.usize_type),
+    });
+
+    const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
+    const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);
+    const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
+    const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
+
+    return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
+        .len = len,
+        .sentinel = sentinel,
+        .elem_type = elem_type,
+    }, .{});
+}
+
 fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
     const tree = scope.tree();
     const src = tree.token_locs[node.rtoken].start;
src-self-hosted/Module.zig
@@ -2902,7 +2902,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
     return Value.initPayload(val_payload);
 }
 
-pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type {
+pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type {
     const type_payload = try scope.arena().create(Type.Payload.Pointer);
     type_payload.* = .{
         .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
@@ -2911,6 +2911,71 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el
     return Type.initPayload(&type_payload.base);
 }
 
+pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
+    return Type.initPayload(switch (child_type.tag()) {
+        .single_const_pointer => blk: {
+            const payload = try scope.arena().create(Type.Payload.Pointer);
+            payload.* = .{
+                .base = .{ .tag = .optional_single_const_pointer },
+                .pointee_type = child_type.elemType(),
+            };
+            break :blk &payload.base;
+        },
+        .single_mut_pointer => blk: {
+            const payload = try scope.arena().create(Type.Payload.Pointer);
+            payload.* = .{
+                .base = .{ .tag = .optional_single_mut_pointer },
+                .pointee_type = child_type.elemType(),
+            };
+            break :blk &payload.base;
+        },
+        else => blk: {
+            const payload = try scope.arena().create(Type.Payload.Optional);
+            payload.* = .{
+                .child_type = child_type,
+            };
+            break :blk &payload.base;
+        },
+    });
+}
+
+pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type {
+    if (elem_type.eql(Type.initTag(.u8))) {
+        if (sentinel) |some| {
+            if (some.eql(Value.initTag(.zero))) {
+                const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
+                payload.* = .{
+                    .len = len,
+                };
+                return Type.initPayload(&payload.base);
+            }
+        } else {
+            const payload = try scope.arena().create(Type.Payload.Array_u8);
+            payload.* = .{
+                .len = len,
+            };
+            return Type.initPayload(&payload.base);
+        }
+    }
+
+    if (sentinel) |some| {
+        const payload = try scope.arena().create(Type.Payload.ArraySentinel);
+        payload.* = .{
+            .len = len,
+            .sentinel = some,
+            .elem_type = elem_type,
+        };
+        return Type.initPayload(&payload.base);
+    }
+
+    const payload = try scope.arena().create(Type.Payload.Array);
+    payload.* = .{
+        .len = len,
+        .elem_type = elem_type,
+    };
+    return Type.initPayload(&payload.base);
+}
+
 pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
     const zir_module = scope.namespace();
     const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
src-self-hosted/type.zig
@@ -65,7 +65,7 @@ pub const Type = extern union {
             .fn_ccc_void_no_args => return .Fn,
             .function => return .Fn,
 
-            .array, .array_u8_sentinel_0 => return .Array,
+            .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array,
             .single_const_pointer => return .Pointer,
             .single_mut_pointer => return .Pointer,
             .single_const_pointer_to_comptime_int => return .Pointer,
@@ -330,6 +330,7 @@ pub const Type = extern union {
             => unreachable,
 
             .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
+            .array_u8 => return self.copyPayloadShallow(allocator, Payload.Array_u8),
             .array => {
                 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
                 const new_payload = try allocator.create(Payload.Array);
@@ -340,6 +341,17 @@ pub const Type = extern union {
                 };
                 return Type{ .ptr_otherwise = &new_payload.base };
             },
+            .array_sentinel => {
+                const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise);
+                const new_payload = try allocator.create(Payload.ArraySentinel);
+                new_payload.* = .{
+                    .base = payload.base,
+                    .len = payload.len,
+                    .sentinel = try payload.sentinel.copy(allocator),
+                    .elem_type = try payload.elem_type.copy(allocator),
+                };
+                return Type{ .ptr_otherwise = &new_payload.base };
+            },
             .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
             .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
             .function => {
@@ -445,6 +457,10 @@ pub const Type = extern union {
                     try payload.return_type.format("", .{}, out_stream);
                 },
 
+                .array_u8 => {
+                    const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise);
+                    return out_stream.print("[{}]u8", .{payload.len});
+                },
                 .array_u8_sentinel_0 => {
                     const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
                     return out_stream.print("[{}:0]u8", .{payload.len});
@@ -455,6 +471,12 @@ pub const Type = extern union {
                     ty = payload.elem_type;
                     continue;
                 },
+                .array_sentinel => {
+                    const payload = @fieldParentPtr(Payload.ArraySentinel, "base", ty.ptr_otherwise);
+                    try out_stream.print("[{}:{}]", .{ payload.len, payload.sentinel });
+                    ty = payload.elem_type;
+                    continue;
+                },
                 .single_const_pointer => {
                     const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
                     try out_stream.writeAll("*const ");
@@ -588,6 +610,8 @@ pub const Type = extern union {
             => true,
             // TODO lazy types
             .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
+            .array_u8 => self.arrayLen() != 0,
+            .array_sentinel => self.elemType().hasCodeGenBits(),
             .single_const_pointer => self.elemType().hasCodeGenBits(),
             .single_mut_pointer => self.elemType().hasCodeGenBits(),
             .int_signed => self.cast(Payload.IntSigned).?.bits == 0,
@@ -616,6 +640,7 @@ pub const Type = extern union {
             .i8,
             .bool,
             .array_u8_sentinel_0,
+            .array_u8,
             => return 1,
 
             .fn_noreturn_no_args, // represents machine code; not a pointer
@@ -659,7 +684,7 @@ pub const Type = extern union {
 
             .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
 
-            .array => return self.cast(Payload.Array).?.elem_type.abiAlignment(target),
+            .array, .array_sentinel => return self.elemType().abiAlignment(target),
 
             .int_signed, .int_unsigned => {
                 const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
@@ -717,12 +742,18 @@ pub const Type = extern union {
             .bool,
             => return 1,
 
-            .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,
+            .array_u8 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len,
+            .array_u8_sentinel_0 => @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise).len + 1,
             .array => {
                 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
                 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
                 return payload.len * elem_size;
             },
+            .array_sentinel => {
+                const payload = @fieldParentPtr(Payload.ArraySentinel, "base", self.ptr_otherwise);
+                const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
+                return (payload.len + 1) * elem_size;
+            },
             .i16, .u16 => return 2,
             .i32, .u32 => return 4,
             .i64, .u64 => return 8,
@@ -818,6 +849,8 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
             .array_u8_sentinel_0,
             .const_slice_u8,
             .fn_noreturn_no_args,
@@ -875,6 +908,8 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
             .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
@@ -931,6 +966,8 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
             .array_u8_sentinel_0,
             .fn_noreturn_no_args,
             .fn_void_no_args,
@@ -988,6 +1025,8 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
             .array_u8_sentinel_0,
             .fn_noreturn_no_args,
             .fn_void_no_args,
@@ -1072,9 +1111,10 @@ pub const Type = extern union {
             => unreachable,
 
             .array => self.cast(Payload.Array).?.elem_type,
+            .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type,
             .single_const_pointer => self.castPointer().?.pointee_type,
             .single_mut_pointer => self.castPointer().?.pointee_type,
-            .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
+            .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
             .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
         };
     }
@@ -1176,6 +1216,8 @@ pub const Type = extern union {
             => unreachable,
 
             .array => self.cast(Payload.Array).?.len,
+            .array_sentinel => self.cast(Payload.ArraySentinel).?.len,
+            .array_u8 => self.cast(Payload.Array_u8).?.len,
             .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,
         };
     }
@@ -1232,7 +1274,8 @@ pub const Type = extern union {
             .optional_single_const_pointer,
             => unreachable,
 
-            .array => return null,
+            .array, .array_u8 => return null,
+            .array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
             .array_u8_sentinel_0 => return Value.initTag(.zero),
         };
     }
@@ -1266,10 +1309,12 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .int_unsigned,
             .u8,
@@ -1324,10 +1369,12 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .int_signed,
             .i8,
@@ -1382,10 +1429,12 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .optional,
             .optional_single_mut_pointer,
@@ -1438,10 +1487,12 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .int_unsigned,
             .int_signed,
@@ -1523,10 +1574,12 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .u8,
             .i8,
@@ -1584,10 +1637,12 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .u8,
             .i8,
@@ -1644,10 +1699,12 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .u8,
             .i8,
@@ -1704,10 +1761,12 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .u8,
             .i8,
@@ -1761,10 +1820,12 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .u8,
             .i8,
@@ -1818,10 +1879,12 @@ pub const Type = extern union {
             .@"null",
             .@"undefined",
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .u8,
             .i8,
@@ -1895,10 +1958,12 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .optional,
             .optional_single_mut_pointer,
@@ -1944,6 +2009,7 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .single_const_pointer_to_comptime_int,
+            .array_sentinel,
             .array_u8_sentinel_0,
             .const_slice_u8,
             .c_void,
@@ -1971,11 +2037,10 @@ pub const Type = extern union {
                     return null;
                 }
             },
-            .array => {
-                const array = ty.cast(Payload.Array).?;
-                if (array.len == 0)
+            .array, .array_u8 => {
+                if (ty.arrayLen() == 0)
                     return Value.initTag(.empty_array);
-                ty = array.elem_type;
+                ty = ty.elemType();
                 continue;
             },
             .single_const_pointer, .single_mut_pointer => {
@@ -2022,7 +2087,6 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .function,
             .single_const_pointer_to_comptime_int,
-            .array_u8_sentinel_0,
             .const_slice_u8,
             .c_void,
             .void,
@@ -2032,6 +2096,9 @@ pub const Type = extern union {
             .int_unsigned,
             .int_signed,
             .array,
+            .array_sentinel,
+            .array_u8,
+            .array_u8_sentinel_0,
             .single_const_pointer,
             .single_mut_pointer,
             .optional,
@@ -2090,8 +2157,10 @@ pub const Type = extern union {
         const_slice_u8, // See last_no_payload_tag below.
         // After this, the tag requires a payload.
 
+        array_u8,
         array_u8_sentinel_0,
         array,
+        array_sentinel,
         single_const_pointer,
         single_mut_pointer,
         int_signed,
@@ -2114,11 +2183,25 @@ pub const Type = extern union {
             len: u64,
         };
 
+        pub const Array_u8 = struct {
+            base: Payload = Payload{ .tag = .array_u8 },
+
+            len: u64,
+        };
+
         pub const Array = struct {
             base: Payload = Payload{ .tag = .array },
 
+            len: u64,
             elem_type: Type,
+        };
+
+        pub const ArraySentinel = struct {
+            base: Payload = Payload{ .tag = .array_sentinel },
+
             len: u64,
+            sentinel: Value,
+            elem_type: Type,
         };
 
         pub const Pointer = struct {
src-self-hosted/zir.zig
@@ -47,6 +47,10 @@ pub const Inst = struct {
         array_cat,
         /// Array multiplication `a ** b`
         array_mul,
+        /// Create an array type
+        array_type,
+        /// Create an array type with sentinel
+        array_type_sentinel,
         /// Function parameter value. These must be first in a function's main block,
         /// in respective order with the parameters.
         arg,
@@ -268,6 +272,7 @@ pub const Inst = struct {
                 .addwrap,
                 .array_cat,
                 .array_mul,
+                .array_type,
                 .bitand,
                 .bitor,
                 .div,
@@ -294,6 +299,7 @@ pub const Inst = struct {
                 => BinOp,
 
                 .arg => Arg,
+                .array_type_sentinel => ArrayTypeSentinel,
                 .block => Block,
                 .@"break" => Break,
                 .breakvoid => BreakVoid,
@@ -333,6 +339,8 @@ pub const Inst = struct {
                 .alloc_inferred,
                 .array_cat,
                 .array_mul,
+                .array_type,
+                .array_type_sentinel,
                 .arg,
                 .as,
                 .@"asm",
@@ -849,6 +857,18 @@ pub const Inst = struct {
             sentinel: ?*Inst = null,
         },
     };
+
+    pub const ArrayTypeSentinel = struct {
+        pub const base_tag = Tag.array_type_sentinel;
+        base: Inst,
+
+        positionals: struct {
+            len: *Inst,
+            sentinel: *Inst,
+            elem_type: *Inst,
+        },
+        kw_args: struct {},
+    };
 };
 
 pub const ErrorMsg = struct {
src-self-hosted/zir_sema.zig
@@ -113,6 +113,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
         .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
         .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
         .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
+        .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
+        .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
     }
 }
 
@@ -676,31 +678,24 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I
 fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {
     const child_type = try resolveType(mod, scope, optional.positionals.operand);
 
-    return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {
-        .single_const_pointer => blk: {
-            const payload = try scope.arena().create(Type.Payload.Pointer);
-            payload.* = .{
-                .base = .{ .tag = .optional_single_const_pointer },
-                .pointee_type = child_type.elemType(),
-            };
-            break :blk &payload.base;
-        },
-        .single_mut_pointer => blk: {
-            const payload = try scope.arena().create(Type.Payload.Pointer);
-            payload.* = .{
-                .base = .{ .tag = .optional_single_mut_pointer },
-                .pointee_type = child_type.elemType(),
-            };
-            break :blk &payload.base;
-        },
-        else => blk: {
-            const payload = try scope.arena().create(Type.Payload.Optional);
-            payload.* = .{
-                .child_type = child_type,
-            };
-            break :blk &payload.base;
-        },
-    }));
+    return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
+}
+
+fn analyzeInstArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
+    // TODO these should be lazily evaluated
+    const len = try resolveInstConst(mod, scope, array.positionals.lhs);
+    const elem_type = try resolveType(mod, scope, array.positionals.rhs);
+
+    return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
+}
+
+fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst {
+    // TODO these should be lazily evaluated
+    const len = try resolveInstConst(mod, scope, array.positionals.len);
+    const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
+    const elem_type = try resolveType(mod, scope, array.positionals.elem_type);
+
+    return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
 }
 
 fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {