mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
stage2: error set declarations
This commit is contained in:
parent
16d7db59ed
commit
e9b15ac9a0
@ -80,6 +80,9 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
|
||||
root_name: []u8,
|
||||
keep_source_files_loaded: bool,
|
||||
|
||||
/// Error tags and their values, tag names are duped with mod.gpa.
|
||||
global_error_set: std.StringHashMapUnmanaged(u16) = .{},
|
||||
|
||||
pub const InnerError = error{ OutOfMemory, AnalysisFail };
|
||||
|
||||
const WorkItem = union(enum) {
|
||||
@ -928,6 +931,11 @@ pub fn deinit(self: *Module) void {
|
||||
|
||||
self.symbol_exports.deinit(gpa);
|
||||
self.root_scope.destroy(gpa);
|
||||
|
||||
for (self.global_error_set.items()) |entry| {
|
||||
gpa.free(entry.key);
|
||||
}
|
||||
self.global_error_set.deinit(gpa);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
@ -2072,6 +2080,15 @@ fn createNewDecl(
|
||||
return new_decl;
|
||||
}
|
||||
|
||||
/// Get error value for error tag `name`.
|
||||
pub fn getErrorValue(self: *Module, name: []const u8) !u16 {
|
||||
const new_val = @intCast(u16, self.global_error_set.items().len);
|
||||
if (self.global_error_set.get(name)) |some| return some;
|
||||
|
||||
try self.global_error_set.put(self.gpa, try self.gpa.dupe(u8, name), new_val);
|
||||
return new_val;
|
||||
}
|
||||
|
||||
/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
|
||||
pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
|
||||
return scope.cast(Scope.Block) orelse
|
||||
|
||||
@ -270,6 +270,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)),
|
||||
.MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)),
|
||||
.AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)),
|
||||
.ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)),
|
||||
|
||||
.Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
|
||||
.Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
|
||||
@ -291,7 +292,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
|
||||
.ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
|
||||
.FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
|
||||
.ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),
|
||||
.ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
|
||||
.Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
|
||||
.Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
|
||||
@ -459,7 +459,9 @@ fn varDecl(
|
||||
const tree = scope.tree();
|
||||
const name_src = tree.token_locs[node.name_token].start;
|
||||
const ident_name = try identifierTokenString(mod, scope, node.name_token);
|
||||
const init_node = node.getTrailer("init_node").?;
|
||||
const init_node = node.getTrailer("init_node") orelse
|
||||
return mod.fail(scope, name_src, "variables must be initialized", .{});
|
||||
|
||||
switch (tree.token_ids[node.mut_token]) {
|
||||
.Keyword_const => {
|
||||
// Depending on the type of AST the initialization expression is, we may need an lvalue
|
||||
@ -582,11 +584,7 @@ fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerE
|
||||
fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*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 operand = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const operand = try typeExpr(mod, scope, node.rhs);
|
||||
return addZIRUnOp(mod, scope, src, .optional_type, operand);
|
||||
}
|
||||
|
||||
@ -611,18 +609,13 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir
|
||||
}
|
||||
|
||||
fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst {
|
||||
const meta_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
|
||||
const simple = ptr_info.allowzero_token == null and
|
||||
ptr_info.align_info == null and
|
||||
ptr_info.volatile_token == null and
|
||||
ptr_info.sentinel == null;
|
||||
|
||||
if (simple) {
|
||||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
|
||||
const child_type = try typeExpr(mod, scope, rhs);
|
||||
const mutable = ptr_info.const_token == null;
|
||||
// TODO stage1 type inference bug
|
||||
const T = zir.Inst.Tag;
|
||||
@ -650,7 +643,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
|
||||
kw_args.sentinel = try expr(mod, scope, .none, some);
|
||||
}
|
||||
|
||||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
|
||||
const child_type = try typeExpr(mod, scope, rhs);
|
||||
if (kw_args.sentinel) |some| {
|
||||
kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
|
||||
}
|
||||
@ -661,10 +654,6 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
|
||||
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),
|
||||
@ -672,18 +661,14 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst
|
||||
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
|
||||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const elem_type = try typeExpr(mod, scope, node.rhs);
|
||||
|
||||
return addZIRBinOp(mod, scope, src, .array_type, len, child_type);
|
||||
return addZIRBinOp(mod, scope, src, .array_type, len, elem_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),
|
||||
@ -692,7 +677,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti
|
||||
// TODO check for [_]T
|
||||
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 elem_type = try typeExpr(mod, scope, node.rhs);
|
||||
const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
|
||||
|
||||
return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
|
||||
@ -706,11 +691,7 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.anyframe_token].start;
|
||||
if (node.result) |some| {
|
||||
const meta_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const return_type = try expr(mod, scope, .{ .ty = meta_type}, some.return_type);
|
||||
const return_type = try typeExpr(mod, scope, some.return_type);
|
||||
return addZIRUnOp(mod, scope, src, .anyframe_type, return_type);
|
||||
} else {
|
||||
return addZIRInstConst(mod, scope, src, .{
|
||||
@ -723,12 +704,8 @@ fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) Inner
|
||||
fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*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 error_set = try expr(mod, scope, .{ .ty = meta_type }, node.lhs);
|
||||
const payload = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const error_set = try typeExpr(mod, scope, node.lhs);
|
||||
const payload = try typeExpr(mod, scope, node.rhs);
|
||||
return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload);
|
||||
}
|
||||
|
||||
@ -751,6 +728,20 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si
|
||||
return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
|
||||
}
|
||||
|
||||
fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.error_token].start;
|
||||
const decls = node.decls();
|
||||
const fields = try scope.arena().alloc([]const u8, decls.len);
|
||||
|
||||
for (decls) |decl, i| {
|
||||
const tag = decl.castTag(.ErrorTag).?;
|
||||
fields[i] = try identifierTokenString(mod, scope, tag.name_token);
|
||||
}
|
||||
|
||||
return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
|
||||
}
|
||||
|
||||
/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.
|
||||
/// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used.
|
||||
fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
|
||||
@ -1517,12 +1508,8 @@ fn simpleCast(
|
||||
try ensureBuiltinParamCount(mod, scope, call, 2);
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
const type_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const params = call.params();
|
||||
const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
|
||||
const dest_type = try typeExpr(mod, scope, params[0]);
|
||||
const rhs = try expr(mod, scope, .none, params[1]);
|
||||
const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs);
|
||||
return rlWrap(mod, scope, rl, result);
|
||||
@ -1584,12 +1571,8 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
|
||||
try ensureBuiltinParamCount(mod, scope, call, 2);
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
const type_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const params = call.params();
|
||||
const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
|
||||
const dest_type = try typeExpr(mod, scope, params[0]);
|
||||
switch (rl) {
|
||||
.none => {
|
||||
const operand = try expr(mod, scope, .none, params[1]);
|
||||
|
||||
@ -91,6 +91,7 @@ pub const Value = extern union {
|
||||
float_64,
|
||||
float_128,
|
||||
enum_literal,
|
||||
error_set,
|
||||
|
||||
pub const last_no_payload_tag = Tag.bool_false;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
@ -243,6 +244,9 @@ pub const Value = extern union {
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
|
||||
// memory is managed by the declaration
|
||||
.error_set => return self,
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,6 +350,14 @@ pub const Value = extern union {
|
||||
.float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
|
||||
.float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
|
||||
.float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
|
||||
.error_set => {
|
||||
const error_set = val.cast(Payload.ErrorSet).?;
|
||||
try out_stream.writeAll("error{");
|
||||
for (error_set.fields.items()) |entry| {
|
||||
try out_stream.print("{},", .{entry.value});
|
||||
}
|
||||
return out_stream.writeAll("}");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -437,6 +449,7 @@ pub const Value = extern union {
|
||||
.float_64,
|
||||
.float_128,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -503,6 +516,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -582,6 +596,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -661,6 +676,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -767,6 +783,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -850,6 +867,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -1017,6 +1035,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.zero => false,
|
||||
@ -1087,6 +1106,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -1230,6 +1250,7 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.ref_val => self.cast(Payload.RefVal).?.val,
|
||||
@ -1310,6 +1331,7 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> unreachable,
|
||||
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
@ -1407,6 +1429,7 @@ pub const Value = extern union {
|
||||
.float_128,
|
||||
.void_value,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
=> false,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -1536,6 +1559,13 @@ pub const Value = extern union {
|
||||
base: Payload = .{ .tag = .float_128 },
|
||||
val: f128,
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
base: Payload = .{ .tag = .error_set },
|
||||
|
||||
// TODO revisit this when we have the concept of the error tag type
|
||||
fields: std.StringHashMapUnmanaged(u16),
|
||||
};
|
||||
};
|
||||
|
||||
/// Big enough to fit any non-BigInt value
|
||||
|
||||
@ -139,6 +139,8 @@ pub const Inst = struct {
|
||||
ensure_result_non_error,
|
||||
/// Create a `E!T` type.
|
||||
error_union_type,
|
||||
/// Create an error set.
|
||||
error_set,
|
||||
/// Export the provided Decl as the provided name in the compilation's output object file.
|
||||
@"export",
|
||||
/// Given a pointer to a struct or object that contains virtual fields, returns a pointer
|
||||
@ -359,6 +361,7 @@ pub const Inst = struct {
|
||||
.condbr => CondBr,
|
||||
.ptr_type => PtrType,
|
||||
.enum_literal => EnumLiteral,
|
||||
.error_set => ErrorSet,
|
||||
};
|
||||
}
|
||||
|
||||
@ -454,6 +457,7 @@ pub const Inst = struct {
|
||||
.anyframe_type,
|
||||
.error_union_type,
|
||||
.bitnot,
|
||||
.error_set,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@ -924,6 +928,16 @@ pub const Inst = struct {
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
pub const base_tag = Tag.error_set;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
fields: [][]const u8,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
};
|
||||
|
||||
pub const ErrorMsg = struct {
|
||||
@ -1158,6 +1172,16 @@ const Writer = struct {
|
||||
const name = self.loop_table.get(param).?;
|
||||
return std.zig.renderStringLiteral(name, stream);
|
||||
},
|
||||
[][]const u8 => {
|
||||
try stream.writeByte('[');
|
||||
for (param) |str, i| {
|
||||
if (i != 0) {
|
||||
try stream.writeAll(", ");
|
||||
}
|
||||
try std.zig.renderStringLiteral(str, stream);
|
||||
}
|
||||
try stream.writeByte(']');
|
||||
},
|
||||
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
||||
}
|
||||
}
|
||||
@ -1555,6 +1579,21 @@ const Parser = struct {
|
||||
const name = try self.parseStringLiteral();
|
||||
return self.loop_table.get(name).?;
|
||||
},
|
||||
[][]const u8 => {
|
||||
try requireEatBytes(self, "[");
|
||||
skipSpace(self);
|
||||
if (eatByte(self, ']')) return &[0][]const u8{};
|
||||
|
||||
var strings = std.ArrayList([]const u8).init(&self.arena.allocator);
|
||||
while (true) {
|
||||
skipSpace(self);
|
||||
try strings.append(try self.parseStringLiteral());
|
||||
skipSpace(self);
|
||||
if (!eatByte(self, ',')) break;
|
||||
}
|
||||
try requireEatBytes(self, "]");
|
||||
return strings.toOwnedSlice();
|
||||
},
|
||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||
}
|
||||
return self.fail("TODO parse parameter {}", .{@typeName(T)});
|
||||
|
||||
@ -126,6 +126,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.merge_error_sets => return analyzeInstMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?),
|
||||
.error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?),
|
||||
.anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?),
|
||||
.error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?),
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,6 +436,7 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr
|
||||
// The bytes references memory inside the ZIR module, which can get deallocated
|
||||
// after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
errdefer new_decl_arena.deinit();
|
||||
const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
|
||||
|
||||
const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
|
||||
@ -737,6 +739,30 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In
|
||||
return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type));
|
||||
}
|
||||
|
||||
fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst {
|
||||
// The bytes references memory inside the ZIR module, which can get deallocated
|
||||
// after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
errdefer new_decl_arena.deinit();
|
||||
|
||||
const payload = try scope.arena().create(Value.Payload.ErrorSet);
|
||||
payload.* = .{ .fields = .{} };
|
||||
try payload.fields.ensureCapacity(&new_decl_arena.allocator, inst.positionals.fields.len);
|
||||
|
||||
for (inst.positionals.fields) |field_name| {
|
||||
const value = try mod.getErrorValue(field_name);
|
||||
if (payload.fields.fetchPutAssumeCapacity(field_name, value)) |prev| {
|
||||
return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name});
|
||||
}
|
||||
}
|
||||
// TODO create name in format "error:line:column"
|
||||
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initPayload(&payload.base),
|
||||
});
|
||||
return mod.analyzeDeclRef(scope, inst.base.src, new_decl);
|
||||
}
|
||||
|
||||
fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{});
|
||||
}
|
||||
@ -1377,7 +1403,7 @@ fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) Inne
|
||||
|
||||
if (host_size != 0 and bit_offset >= host_size * 8)
|
||||
return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{});
|
||||
|
||||
|
||||
const sentinel = if (inst.kw_args.sentinel) |some|
|
||||
(try resolveInstConst(mod, scope, some)).val
|
||||
else
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user