stage2: array types

This commit is contained in:
Vexu 2020-08-18 12:24:23 +03:00
parent 3eb8f7be10
commit 7c15c9428e
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
5 changed files with 255 additions and 50 deletions

View File

@ -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");

View File

@ -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;

View File

@ -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 },
elem_type: Type,
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 {

View File

@ -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 {

View File

@ -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 {