authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-01 23:32:09-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-01 23:32:09-05:00
log406496ca3371b7f50aee141fa37c52e86d96783f
tree817587a21d0f0f12b871e5ff04955d5cd553ffb0
parent13b36d458f6ba45fdda1c1510e056a7012fb3fff

*WIP* error sets - allow peer type resolution to create new error set


4 files changed, 88 insertions(+), 23 deletions(-)

src/analyze.cpp+1-1
...@@ -1277,7 +1277,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {...@@ -1277,7 +1277,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
1277TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) {1277TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) {
1278 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);1278 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
1279 buf_resize(&err_set_type->name, 0);1279 buf_resize(&err_set_type->name, 0);
1280 buf_appendf(&err_set_type->name, "%s.errors", buf_ptr(&fn_entry->symbol_name));1280 buf_appendf(&err_set_type->name, "@typeOf(%s).ReturnType.ErrorSet", buf_ptr(&fn_entry->symbol_name));
1281 err_set_type->is_copyable = true;1281 err_set_type->is_copyable = true;
1282 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;1282 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
1283 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;1283 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
src/ir.cpp+83-19
...@@ -5380,12 +5380,61 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,...@@ -5380,12 +5380,61 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
5380 return ir_build_const_type(irb, parent_scope, node, container_type);5380 return ir_build_const_type(irb, parent_scope, node, container_type);
5381}5381}
53825382
5383// errors should be populated with set1's values
5384static TypeTableEntry *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, TypeTableEntry *set1, TypeTableEntry *set2) {
5385 assert(set1->id == TypeTableEntryIdErrorSet);
5386 assert(set2->id == TypeTableEntryIdErrorSet);
5387
5388 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
5389 buf_resize(&err_set_type->name, 0);
5390 buf_appendf(&err_set_type->name, "error{");
5391
5392 uint32_t count = set1->data.error_set.err_count;
5393 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
5394 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
5395 if (errors[error_entry->value] == nullptr) {
5396 count += 1;
5397 }
5398 }
5399
5400 err_set_type->is_copyable = true;
5401 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
5402 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;
5403 err_set_type->data.error_set.err_count = count;
5404 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(count);
5405
5406 for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
5407 ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
5408 buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
5409 err_set_type->data.error_set.errors[i] = error_entry;
5410 }
5411
5412 uint32_t index = set1->data.error_set.err_count;
5413 for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
5414 ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
5415 if (errors[error_entry->value] == nullptr) {
5416 errors[error_entry->value] = error_entry;
5417 buf_appendf(&err_set_type->name, "%s,", buf_ptr(&error_entry->name));
5418 err_set_type->data.error_set.errors[index] = error_entry;
5419 index += 1;
5420 }
5421 }
5422 assert(index == count);
5423
5424 buf_appendf(&err_set_type->name, "}");
5425
5426 g->error_di_types.append(&err_set_type->di_type);
5427
5428 return err_set_type;
5429
5430}
5431
5383static TypeTableEntry *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node,5432static TypeTableEntry *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstNode *node,
5384 ErrorTableEntry *err_entry)5433 ErrorTableEntry *err_entry)
5385{5434{
5386 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);5435 TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
5387 buf_resize(&err_set_type->name, 0);5436 buf_resize(&err_set_type->name, 0);
5388 buf_appendf(&err_set_type->name, "@typeOf(error.%s)", buf_ptr(&err_entry->name));5437 buf_appendf(&err_set_type->name, "error{%s}", buf_ptr(&err_entry->name));
5389 err_set_type->is_copyable = true;5438 err_set_type->is_copyable = true;
5390 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;5439 err_set_type->type_ref = g->builtin_types.entry_global_error_set->type_ref;
5391 err_set_type->di_type = g->builtin_types.entry_global_error_set->di_type;5440 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...@@ -6656,7 +6705,6 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6656 }6705 }
6657 // if err_set_type is a superset of cur_type, keep err_set_type.6706 // if err_set_type is a superset of cur_type, keep err_set_type.
6658 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type6707 // if cur_type is a superset of err_set_type, switch err_set_type to cur_type
6659 // otherwise emit a compile error
6660 bool prev_is_superset = true;6708 bool prev_is_superset = true;
6661 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {6709 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
6662 ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i];6710 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...@@ -6689,12 +6737,16 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6689 }6737 }
6690 }6738 }
6691 if (cur_is_superset) {6739 if (cur_is_superset) {
6692 err_set_type = cur_inst->value.type;6740 err_set_type = cur_type;
6693 prev_inst = cur_inst;6741 prev_inst = cur_inst;
6694 continue;6742 continue;
6695 }6743 }
6744
6745 // neither of them are supersets. so we invent a new error set type that is a union of both of them
6746 err_set_type = get_error_set_union(ira->codegen, errors, cur_type, err_set_type);
6747 continue;
6696 } else if (cur_type->id == TypeTableEntryIdErrorUnion) {6748 } else if (cur_type->id == TypeTableEntryIdErrorUnion) {
6697 // err_set_type must be a subset of cur_type's error set6749 // test if err_set_type is a subset of cur_type's error set
6698 // unset everything in errors6750 // unset everything in errors
6699 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {6751 for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
6700 ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i];6752 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...@@ -6719,6 +6771,11 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6719 prev_inst = cur_inst;6771 prev_inst = cur_inst;
6720 continue;6772 continue;
6721 }6773 }
6774
6775 // not a subset. invent new error set type, union of both of them
6776 err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, err_set_type);
6777 prev_inst = cur_inst;
6778 continue;
6722 } else {6779 } else {
6723 prev_inst = cur_inst;6780 prev_inst = cur_inst;
6724 continue;6781 continue;
...@@ -6746,7 +6803,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6746,7 +6803,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6746 continue;6803 continue;
6747 }6804 }
6748 if (prev_type->id == TypeTableEntryIdErrorUnion) {6805 if (prev_type->id == TypeTableEntryIdErrorUnion) {
6749 // the cur type error set must be a subset6806 // check if the cur type error set must be a subset
6750 bool prev_is_superset = true;6807 bool prev_is_superset = true;
6751 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {6808 for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
6752 ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i];6809 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...@@ -6759,6 +6816,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6759 if (prev_is_superset) {6816 if (prev_is_superset) {
6760 continue;6817 continue;
6761 }6818 }
6819 // not a subset. invent new error set type, union of both of them
6820 err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type);
6821 continue;
6762 }6822 }
6763 }6823 }
67646824
...@@ -6927,21 +6987,25 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -6927,21 +6987,25 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
6927 } else {6987 } else {
6928 return slice_type;6988 return slice_type;
6929 }6989 }
6930 } else if (err_set_type != nullptr && prev_inst->value.type->id != TypeTableEntryIdErrorSet) {6990 } else if (err_set_type != nullptr) {
6931 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||6991 if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
6932 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)6992 return err_set_type;
6933 {
6934 ir_add_error_node(ira, source_node,
6935 buf_sprintf("unable to make error union out of number literal"));
6936 return ira->codegen->builtin_types.entry_invalid;
6937 } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
6938 ir_add_error_node(ira, source_node,
6939 buf_sprintf("unable to make error union out of null literal"));
6940 return ira->codegen->builtin_types.entry_invalid;
6941 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
6942 return prev_inst->value.type;
6943 } else {6993 } else {
6944 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type);6994 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
6995 prev_inst->value.type->id == TypeTableEntryIdNumLitFloat)
6996 {
6997 ir_add_error_node(ira, source_node,
6998 buf_sprintf("unable to make error union out of number literal"));
6999 return ira->codegen->builtin_types.entry_invalid;
7000 } else if (prev_inst->value.type->id == TypeTableEntryIdNullLit) {
7001 ir_add_error_node(ira, source_node,
7002 buf_sprintf("unable to make error union out of null literal"));
7003 return ira->codegen->builtin_types.entry_invalid;
7004 } else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
7005 return prev_inst->value.type;
7006 } else {
7007 return get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type);
7008 }
6945 }7009 }
6946 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {7010 } else if (any_are_null && prev_inst->value.type->id != TypeTableEntryIdNullLit) {
6947 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||7011 if (prev_inst->value.type->id == TypeTableEntryIdNumLitInt ||
std/fmt/index.zig+2-2
...@@ -498,12 +498,12 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {...@@ -498,12 +498,12 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
498498
499pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {499pub fn allocPrint(allocator: &mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {
500 var size: usize = 0;500 var size: usize = 0;
501 format(&size, error{}, countSize, fmt, args);501 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
502 const buf = try allocator.alloc(u8, size);502 const buf = try allocator.alloc(u8, size);
503 return bufPrint(buf, fmt, args);503 return bufPrint(buf, fmt, args);
504}504}
505505
506fn countSize(size: &usize, bytes: []const u8) void {506fn countSize(size: &usize, bytes: []const u8) !void {
507 *size += bytes.len;507 *size += bytes.len;
508}508}
509509
std/io.zig+2-1
...@@ -350,10 +350,11 @@ pub const File = struct {...@@ -350,10 +350,11 @@ pub const File = struct {
350};350};
351351
352pub const InStream = struct {352pub const InStream = struct {
353 // TODO allow specifying the error set
353 /// Return the number of bytes read. If the number read is smaller than buf.len, it354 /// Return the number of bytes read. If the number read is smaller than buf.len, it
354 /// means the stream reached the end. Reaching the end of a stream is not an error355 /// means the stream reached the end. Reaching the end of a stream is not an error
355 /// condition.356 /// condition.
356 readFn: fn(self: &InStream, buffer: []u8) !usize,357 readFn: fn(self: &InStream, buffer: []u8) error!usize,
357358
358 /// Replaces `buffer` contents by reading from the stream until it is finished.359 /// Replaces `buffer` contents by reading from the stream until it is finished.
359 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and360 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and