*WIP* error sets - allow peer type resolution to create new error set
parent
13b36d458f
commit
406496ca33
|
@ -1277,7 +1277,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
|
|||
TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) {
|
||||
TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
|
||||
buf_resize(&err_set_type->name, 0);
|
||||
buf_appendf(&err_set_type->name, "%s.errors", buf_ptr(&fn_entry->symbol_name));
|
||||
buf_appendf(&err_set_type->name, "@typeOf(%s).ReturnType.ErrorSet", buf_ptr(&fn_entry->symbol_name));
|
||||
err_set_type->is_copyable = true;
|
||||
err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
|
||||
err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
|
||||
|
|
102
src/ir.cpp
102
src/ir.cpp
|
@ -5380,12 +5380,61 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
|
|||
return ir_build_const_type(irb, parent_scope, node, container_type);
|
||||
}
|
||||
|
||||
// errors should be populated with set1's values
|
||||
static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, TypeTableEntry *set1, TypeTableEntry *set2) {
|
||||
assert(set1->id == TypeTableEntryIdErrorSet);
|
||||
assert(set2->id == TypeTableEntryIdErrorSet);
|
||||
|
||||
TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
|
||||
buf_resize(&err_set_type->name, 0);
|
||||
buf_appendf(&err_set_type->name, "error{");
|
||||
|
||||
uint32_t count = set1->data.error_set.err_count;
|
||||
for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
|
||||
ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
|
||||
if (errors[error_entry->value] == nullptr) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
err_set_type->is_copyable = true;
|
||||
err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
|
||||
err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
|
||||
err_set_type->data.error_set.err_count = count;
|
||||
err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(count);
|
||||
|
||||
for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
|
||||
ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
|
||||
buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
|
||||
err_set_type->data.error_set.errors[i] = error_entry;
|
||||
}
|
||||
|
||||
uint32_t index = set1->data.error_set.err_count;
|
||||
for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
|
||||
ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
|
||||
if (errors[error_entry->value] == nullptr) {
|
||||
errors[error_entry->value] = error_entry;
|
||||
buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
|
||||
err_set_type->data.error_set.errors[index] = error_entry;
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
assert(index == count);
|
||||
|
||||
buf_appendf(&err_set_type->name, "}");
|
||||
|
||||
g->error_di_types.append(&err_set_type->di_type);
|
||||
|
||||
return err_set_type;
|
||||
|
||||
}
|
||||
|
||||
static TypeTableEntry *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node,
|
||||
ErrorTableEntry *err_entry)
|
||||
{
|
||||
TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
|
||||
buf_resize(&err_set_type->name, 0);
|
||||
buf_appendf(&err_set_type->name, "@typeOf(error.%s)", buf_ptr(&err_entry->name));
|
||||
buf_appendf(&err_set_type->name, "error{%s}", buf_ptr(&err_entry->name));
|
||||
err_set_type->is_copyable = true;
|
||||
err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
|
||||
err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
|
||||
|
@ -6656,7 +6705,6 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||
}
|
||||
// if err_set_type is a superset of cur_type, keep err_set_type.
|
||||
// if cur_type is a superset of err_set_type, switch err_set_type to cur_type
|
||||
// otherwise emit a compile error
|
||||
bool prev_is_superset = true;
|
||||
for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
|
||||
ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i];
|
||||
|
@ -6689,12 +6737,16 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||
}
|
||||
}
|
||||
if (cur_is_superset) {
|
||||
err_set_type = cur_inst->value.type;
|
||||
err_set_type = cur_type;
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
}
|
||||
|
||||
// neither of them are supersets. so we invent a new error set type that is a union of both of them
|
||||
err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type);
|
||||
continue;
|
||||
} else if (cur_type->id == TypeTableEntryIdErrorUnion) {
|
||||
// err_set_type must be a subset of cur_type's error set
|
||||
// test if err_set_type is a subset of cur_type's error set
|
||||
// unset everything in errors
|
||||
for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
|
||||
ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];
|
||||
|
@ -6719,6 +6771,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||
prev_inst = cur_inst;
|
||||
continue;
|
||||
}
|
||||
|
||||
// not a subset. invent new error set type, union of both of them
|
||||
err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type);
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
} else {
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
|
@ -6746,7 +6803,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||
continue;
|
||||
}
|
||||
if (prev_type->id == TypeTableEntryIdErrorUnion) {
|
||||
// the cur type error set must be a subset
|
||||
// check if the cur type error set must be a subset
|
||||
bool prev_is_superset = true;
|
||||
for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
|
||||
ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i];
|
||||
|
@ -6759,6 +6816,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||
if (prev_is_superset) {
|
||||
continue;
|
||||
}
|
||||
// not a subset. invent new error set type, union of both of them
|
||||
err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6927,21 +6987,25 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||
} else {
|
||||
return slice_type;
|
||||
}
|
||||
} else if (err_set_type != nullptr && prev_inst->value.type->id != TypeTableEntryIdErrorSet) {
|
||||
if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
|
||||
prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("unable to make error union out of number literal"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("unable to make error union out of null literal"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
|
||||
return prev_inst->value.type;
|
||||
} else if (err_set_type != nullptr) {
|
||||
if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
|
||||
return err_set_type;
|
||||
} else {
|
||||
return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type);
|
||||
if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
|
||||
prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("unable to make error union out of number literal"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("unable to make error union out of null literal"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
} else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
|
||||
return prev_inst->value.type;
|
||||
} else {
|
||||
return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type);
|
||||
}
|
||||
}
|
||||
} else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {
|
||||
if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
|
||||
|
|
|
@ -498,12 +498,12 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
|
|||
|
||||
pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {
|
||||
var size: usize = 0;
|
||||
format(&size, error{}, countSize, fmt, args);
|
||||
format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
|
||||
const buf = try allocator.alloc(u8, size);
|
||||
return bufPrint(buf, fmt, args);
|
||||
}
|
||||
|
||||
fn countSize(size: &usize, bytes: []const u8) void {
|
||||
fn countSize(size: &usize, bytes: []const u8) !void {
|
||||
*size += bytes.len;
|
||||
}
|
||||
|
||||
|
|
|
@ -350,10 +350,11 @@ pub const File = struct {
|
|||
};
|
||||
|
||||
pub const InStream = struct {
|
||||
// TODO allow specifying the error set
|
||||
/// Return the number of bytes read. If the number read is smaller than buf.len, it
|
||||
/// means the stream reached the end. Reaching the end of a stream is not an error
|
||||
/// condition.
|
||||
readFn: fn(self: &InStream, buffer: []u8) !usize,
|
||||
readFn: fn(self: &InStream, buffer: []u8) error!usize,
|
||||
|
||||
/// Replaces `buffer` contents by reading from the stream until it is finished.
|
||||
/// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
|
||||
|
|
Loading…
Reference in New Issue