aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/all_types.hpp68
-rw-r--r--src/analyze.cpp369
-rw-r--r--src/analyze.hpp8
-rw-r--r--src/ast_render.cpp33
-rw-r--r--src/codegen.cpp159
-rw-r--r--src/codegen.hpp1
-rw-r--r--src/ir.cpp1597
-rw-r--r--src/ir_print.cpp12
-rw-r--r--src/main.cpp8
-rw-r--r--src/parser.cpp112
-rw-r--r--src/tokenizer.cpp29
-rw-r--r--src/tokenizer.hpp2
-rw-r--r--src/util.hpp19
-rw-r--r--src/zig_llvm.cpp4
-rw-r--r--src/zig_llvm.h1
15 files changed, 1869 insertions, 553 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 0f41760718..04b781a598 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -236,7 +236,7 @@ struct ConstExprValue {
TypeTableEntry *x_type;
ConstExprValue *x_maybe;
ConstErrValue x_err_union;
- ErrorTableEntry *x_pure_err;
+ ErrorTableEntry *x_err_set;
BigInt x_enum_tag;
ConstStructValue x_struct;
ConstUnionValue x_union;
@@ -353,7 +353,6 @@ enum NodeType {
NodeTypeReturnExpr,
NodeTypeDefer,
NodeTypeVariableDeclaration,
- NodeTypeErrorValueDecl,
NodeTypeTestDecl,
NodeTypeBinOpExpr,
NodeTypeUnwrapErrorExpr,
@@ -393,6 +392,7 @@ enum NodeType {
NodeTypeVarLiteral,
NodeTypeIfErrorExpr,
NodeTypeTestExpr,
+ NodeTypeErrorSetDecl,
};
struct AstNodeRoot {
@@ -424,6 +424,8 @@ struct AstNodeFnProto {
AstNode *align_expr;
// populated if the "section(S)" is present
AstNode *section_expr;
+
+ bool auto_err_set;
};
struct AstNodeFnDef {
@@ -486,12 +488,6 @@ struct AstNodeVariableDeclaration {
AstNode *section_expr;
};
-struct AstNodeErrorValueDecl {
- Buf *name;
-
- ErrorTableEntry *err;
-};
-
struct AstNodeTestDecl {
Buf *name;
@@ -514,8 +510,7 @@ enum BinOpType {
BinOpTypeAssignBitAnd,
BinOpTypeAssignBitXor,
BinOpTypeAssignBitOr,
- BinOpTypeAssignBoolAnd,
- BinOpTypeAssignBoolOr,
+ BinOpTypeAssignMergeErrorSets,
BinOpTypeBoolOr,
BinOpTypeBoolAnd,
BinOpTypeCmpEq,
@@ -540,6 +535,8 @@ enum BinOpType {
BinOpTypeUnwrapMaybe,
BinOpTypeArrayCat,
BinOpTypeArrayMult,
+ BinOpTypeErrorUnion,
+ BinOpTypeMergeErrorSets,
};
struct AstNodeBinOpExpr {
@@ -563,6 +560,7 @@ enum CastOp {
CastOpResizeSlice,
CastOpBytesToSlice,
CastOpNumLitToConcrete,
+ CastOpErrSet,
};
struct AstNodeFnCallExpr {
@@ -595,7 +593,6 @@ enum PrefixOp {
PrefixOpNegationWrap,
PrefixOpDereference,
PrefixOpMaybe,
- PrefixOpError,
PrefixOpUnwrapMaybe,
};
@@ -762,6 +759,10 @@ struct AstNodeContainerDecl {
bool auto_enum; // union(enum)
};
+struct AstNodeErrorSetDecl {
+ ZigList<AstNode *> decls;
+};
+
struct AstNodeStructField {
VisibMod visib_mod;
Buf *name;
@@ -858,7 +859,6 @@ struct AstNode {
AstNodeReturnExpr return_expr;
AstNodeDefer defer;
AstNodeVariableDeclaration variable_declaration;
- AstNodeErrorValueDecl error_value_decl;
AstNodeTestDecl test_decl;
AstNodeBinOpExpr bin_op_expr;
AstNodeCatchExpr unwrap_err_expr;
@@ -899,6 +899,7 @@ struct AstNode {
AstNodeArrayType array_type;
AstNodeErrorType error_type;
AstNodeVarLiteral var_literal;
+ AstNodeErrorSetDecl err_set_decl;
} data;
};
@@ -993,8 +994,15 @@ struct TypeTableEntryMaybe {
TypeTableEntry *child_type;
};
-struct TypeTableEntryError {
- TypeTableEntry *child_type;
+struct TypeTableEntryErrorUnion {
+ TypeTableEntry *err_set_type;
+ TypeTableEntry *payload_type;
+};
+
+struct TypeTableEntryErrorSet {
+ uint32_t err_count;
+ ErrorTableEntry **errors;
+ FnTableEntry *infer_fn;
};
struct TypeTableEntryEnum {
@@ -1097,7 +1105,7 @@ enum TypeTableEntryId {
TypeTableEntryIdNullLit,
TypeTableEntryIdMaybe,
TypeTableEntryIdErrorUnion,
- TypeTableEntryIdPureError,
+ TypeTableEntryIdErrorSet,
TypeTableEntryIdEnum,
TypeTableEntryIdUnion,
TypeTableEntryIdFn,
@@ -1126,7 +1134,8 @@ struct TypeTableEntry {
TypeTableEntryArray array;
TypeTableEntryStruct structure;
TypeTableEntryMaybe maybe;
- TypeTableEntryError error;
+ TypeTableEntryErrorUnion error_union;
+ TypeTableEntryErrorSet error_set;
TypeTableEntryEnum enumeration;
TypeTableEntryUnion unionation;
TypeTableEntryFn fn;
@@ -1136,7 +1145,6 @@ struct TypeTableEntry {
// use these fields to make sure we don't duplicate type table entries for the same type
TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
TypeTableEntry *maybe_parent;
- TypeTableEntry *error_parent;
// If we generate a constant name value for this type, we memoize it here.
// The type of this is array
ConstExprValue *cached_const_name_val;
@@ -1340,6 +1348,10 @@ struct TypeId {
bool is_signed;
uint32_t bit_count;
} integer;
+ struct {
+ TypeTableEntry *err_set_type;
+ TypeTableEntry *payload_type;
+ } error_union;
} data;
};
@@ -1481,7 +1493,7 @@ struct CodeGen {
TypeTableEntry *entry_undef;
TypeTableEntry *entry_null;
TypeTableEntry *entry_var;
- TypeTableEntry *entry_pure_error;
+ TypeTableEntry *entry_global_error_set;
TypeTableEntry *entry_arg_tuple;
} builtin_types;
@@ -1570,7 +1582,6 @@ struct CodeGen {
LLVMValueRef return_address_fn_val;
LLVMValueRef frame_address_fn_val;
bool error_during_imports;
- TypeTableEntry *err_tag_type;
const char **clang_argv;
size_t clang_argv_len;
@@ -1584,7 +1595,9 @@ struct CodeGen {
bool each_lib_rpath;
- ZigList<AstNode *> error_decls;
+ TypeTableEntry *err_tag_type;
+ ZigList<ZigLLVMDIEnumerator *> err_enumerators;
+ ZigList<ErrorTableEntry *> errors_by_index;
bool generate_error_name_table;
LLVMValueRef err_name_table;
size_t largest_err_name_len;
@@ -1617,6 +1630,10 @@ struct CodeGen {
TypeTableEntry *align_amt_type;
TypeTableEntry *stack_trace_type;
TypeTableEntry *ptr_to_stack_trace_type;
+
+ ZigList<ZigLLVMDIType **> error_di_types;
+
+ ZigList<Buf *> forbidden_libs;
};
enum VarLinkage {
@@ -1653,6 +1670,7 @@ struct ErrorTableEntry {
Buf name;
uint32_t value;
AstNode *decl_node;
+ TypeTableEntry *set_with_only_this_in_it;
// If we generate a constant error name value for this error, we memoize it here.
// The type of this is array
ConstExprValue *cached_error_name_val;
@@ -1920,6 +1938,7 @@ enum IrInstructionId {
IrInstructionIdArgType,
IrInstructionIdExport,
IrInstructionIdErrorReturnTrace,
+ IrInstructionIdErrorUnion,
};
struct IrInstruction {
@@ -1996,7 +2015,6 @@ enum IrUnOp {
IrUnOpNegation,
IrUnOpNegationWrap,
IrUnOpDereference,
- IrUnOpError,
IrUnOpMaybe,
};
@@ -2039,6 +2057,7 @@ enum IrBinOp {
IrBinOpRemMod,
IrBinOpArrayCat,
IrBinOpArrayMult,
+ IrBinOpMergeErrorSets,
};
struct IrInstructionBinOp {
@@ -2750,6 +2769,13 @@ struct IrInstructionErrorReturnTrace {
IrInstruction base;
};
+struct IrInstructionErrorUnion {
+ IrInstruction base;
+
+ IrInstruction *err_set;
+ IrInstruction *payload;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 4c982c160c..b6f08b7aec 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -224,7 +224,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -260,7 +260,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -514,29 +514,46 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
}
}
-TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
- if (child_type->error_parent)
- return child_type->error_parent;
+TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type) {
+ assert(err_set_type->id == TypeTableEntryIdErrorSet);
+ assert(!type_is_invalid(payload_type));
+
+ TypeId type_id = {};
+ type_id.id = TypeTableEntryIdErrorUnion;
+ type_id.data.error_union.err_set_type = err_set_type;
+ type_id.data.error_union.payload_type = payload_type;
+
+ auto existing_entry = g->type_table.maybe_get(type_id);
+ if (existing_entry) {
+ return existing_entry->value;
+ }
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);
entry->is_copyable = true;
- assert(child_type->type_ref);
- assert(child_type->di_type);
- ensure_complete_type(g, child_type);
+ assert(payload_type->di_type);
+ ensure_complete_type(g, payload_type);
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "%%%s", buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name));
- entry->data.error.child_type = child_type;
-
- if (!type_has_bits(child_type)) {
- entry->type_ref = g->err_tag_type->type_ref;
- entry->di_type = g->err_tag_type->di_type;
+ entry->data.error_union.err_set_type = err_set_type;
+ entry->data.error_union.payload_type = payload_type;
+ if (!type_has_bits(payload_type)) {
+ if (type_has_bits(err_set_type)) {
+ entry->type_ref = err_set_type->type_ref;
+ entry->di_type = err_set_type->di_type;
+ } else {
+ entry->zero_bits = true;
+ entry->di_type = g->builtin_types.entry_void->di_type;
+ }
+ } else if (!type_has_bits(err_set_type)) {
+ entry->type_ref = payload_type->type_ref;
+ entry->di_type = payload_type->di_type;
} else {
LLVMTypeRef elem_types[] = {
- g->err_tag_type->type_ref,
- child_type->type_ref,
+ err_set_type->type_ref,
+ payload_type->type_ref,
};
entry->type_ref = LLVMStructType(elem_types, 2, false);
@@ -547,12 +564,12 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
ZigLLVMTag_DW_structure_type(), buf_ptr(&entry->name),
compile_unit_scope, di_file, line);
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, err_set_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, err_set_type->type_ref);
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref, err_union_err_index);
- uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_type->type_ref);
- uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_type->type_ref);
+ uint64_t value_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, payload_type->type_ref);
+ uint64_t value_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, payload_type->type_ref);
uint64_t value_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, entry->type_ref,
err_union_payload_index);
@@ -565,13 +582,13 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
tag_debug_size_in_bits,
tag_debug_align_in_bits,
tag_offset_in_bits,
- 0, child_type->di_type),
+ 0, err_set_type->di_type),
ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(entry->di_type),
"value", di_file, line,
value_debug_size_in_bits,
value_debug_align_in_bits,
value_offset_in_bits,
- 0, child_type->di_type),
+ 0, payload_type->di_type),
};
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
@@ -587,7 +604,7 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
entry->di_type = replacement_di_type;
}
- child_type->error_parent = entry;
+ g->type_table.put(type_id, entry);
return entry;
}
@@ -937,7 +954,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
handle_is_ptr(fn_type_id->return_type);
bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
(fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
- fn_type_id->return_type->id == TypeTableEntryIdPureError);
+ fn_type_id->return_type->id == TypeTableEntryIdErrorSet);
// +1 for maybe making the first argument the return value
// +1 for maybe last argument the error return trace
LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
@@ -1177,7 +1194,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -1218,7 +1235,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -1263,7 +1280,23 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
zig_unreachable();
}
-static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) {
+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, "@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;
+ err_set_type->data.error_set.err_count = 0;
+ err_set_type->data.error_set.errors = nullptr;
+ err_set_type->data.error_set.infer_fn = fn_entry;
+
+ g->error_di_types.append(&err_set_type->di_type);
+
+ return err_set_type;
+}
+
+static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, FnTableEntry *fn_entry) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
@@ -1359,7 +1392,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -1382,13 +1415,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
}
}
- fn_type_id.return_type = (fn_proto->return_type == nullptr) ?
- g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type);
-
- if (type_is_invalid(fn_type_id.return_type)) {
+ TypeTableEntry *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
+ if (type_is_invalid(specified_return_type)) {
+ fn_type_id.return_type = g->builtin_types.entry_invalid;
return g->builtin_types.entry_invalid;
}
+ if (fn_proto->auto_err_set) {
+ TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(g, fn_entry);
+ fn_type_id.return_type = get_error_union_type(g, inferred_err_set_type, specified_return_type);
+ } else {
+ fn_type_id.return_type = specified_return_type;
+ }
+
if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) {
add_node_error(g, fn_proto->return_type,
buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
@@ -1434,7 +1473,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -2756,7 +2795,8 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) {
return g->test_fn_type;
FnTypeId fn_type_id = {0};
- fn_type_id.return_type = get_error_type(g, g->builtin_types.entry_void);
+ fn_type_id.return_type = get_error_union_type(g, g->builtin_types.entry_global_error_set,
+ g->builtin_types.entry_void);
g->test_fn_type = get_fn_type(g, &fn_type_id);
return g->test_fn_type;
}
@@ -2824,7 +2864,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope;
- fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope);
+ fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope, fn_table_entry);
if (fn_proto->section_expr != nullptr) {
if (fn_table_entry->body_node == nullptr) {
@@ -2949,29 +2989,6 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
g->resolve_queue.append(&tld_fn->base);
}
-static void preview_error_value_decl(CodeGen *g, AstNode *node) {
- assert(node->type == NodeTypeErrorValueDecl);
-
- ErrorTableEntry *err = allocate<ErrorTableEntry>(1);
-
- err->decl_node = node;
- buf_init_from_buf(&err->name, node->data.error_value_decl.name);
-
- auto existing_entry = g->error_table.maybe_get(&err->name);
- if (existing_entry) {
- // duplicate error definitions allowed and they get the same value
- err->value = existing_entry->value->value;
- } else {
- size_t error_value_count = g->error_decls.length;
- assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count));
- err->value = (uint32_t)error_value_count;
- g->error_decls.append(node);
- g->error_table.put(&err->name, err);
- }
-
- node->data.error_value_decl.err = err;
-}
-
static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope) {
assert(node->type == NodeTypeCompTime);
@@ -3045,10 +3062,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
import->use_decls.append(node);
break;
}
- case NodeTypeErrorValueDecl:
- // error value declarations do not depend on other top level decls
- preview_error_value_decl(g, node);
- break;
case NodeTypeTestDecl:
preview_test_decl(g, node, decls_scope);
break;
@@ -3097,6 +3110,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeVarLiteral:
case NodeTypeIfErrorExpr:
case NodeTypeTestExpr:
+ case NodeTypeErrorSetDecl:
zig_unreachable();
}
}
@@ -3147,7 +3161,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -3362,108 +3376,6 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
g->tld_ref_source_node_stack.pop();
}
-bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
- if (expected_type == actual_type)
- return true;
-
- // pointer const
- if (expected_type->id == TypeTableEntryIdPointer &&
- actual_type->id == TypeTableEntryIdPointer &&
- (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
- (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
- actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
- actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count &&
- actual_type->data.pointer.alignment >= expected_type->data.pointer.alignment)
- {
- return types_match_const_cast_only(expected_type->data.pointer.child_type,
- actual_type->data.pointer.child_type);
- }
-
- // slice const
- if (is_slice(expected_type) && is_slice(actual_type)) {
- TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
- TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
- if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
- (!actual_ptr_type->data.pointer.is_volatile || expected_ptr_type->data.pointer.is_volatile) &&
- actual_ptr_type->data.pointer.bit_offset == expected_ptr_type->data.pointer.bit_offset &&
- actual_ptr_type->data.pointer.unaligned_bit_count == expected_ptr_type->data.pointer.unaligned_bit_count &&
- actual_ptr_type->data.pointer.alignment >= expected_ptr_type->data.pointer.alignment)
- {
- return types_match_const_cast_only(expected_ptr_type->data.pointer.child_type,
- actual_ptr_type->data.pointer.child_type);
- }
- }
-
- // maybe
- if (expected_type->id == TypeTableEntryIdMaybe &&
- actual_type->id == TypeTableEntryIdMaybe)
- {
- return types_match_const_cast_only(
- expected_type->data.maybe.child_type,
- actual_type->data.maybe.child_type);
- }
-
- // error
- if (expected_type->id == TypeTableEntryIdErrorUnion &&
- actual_type->id == TypeTableEntryIdErrorUnion)
- {
- return types_match_const_cast_only(
- expected_type->data.error.child_type,
- actual_type->data.error.child_type);
- }
-
- // fn
- if (expected_type->id == TypeTableEntryIdFn &&
- actual_type->id == TypeTableEntryIdFn)
- {
- if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
- return false;
- }
- if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
- return false;
- }
- if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
- return false;
- }
- if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
- return false;
- }
- if (!expected_type->data.fn.is_generic &&
- actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
- !types_match_const_cast_only(
- expected_type->data.fn.fn_type_id.return_type,
- actual_type->data.fn.fn_type_id.return_type))
- {
- return false;
- }
- if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
- return false;
- }
- if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
- return false;
- }
- assert(expected_type->data.fn.is_generic ||
- expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
- for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
- // note it's reversed for parameters
- FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
- FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
-
- if (!types_match_const_cast_only(actual_param_info->type, expected_param_info->type)) {
- return false;
- }
-
- if (expected_param_info->is_noalias != actual_param_info->is_noalias) {
- return false;
- }
- }
- return true;
- }
-
-
- return false;
-}
-
Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
// we must resolve all the use decls
ImportTableEntry *import = get_scope_import(scope);
@@ -3625,7 +3537,7 @@ static bool is_container(TypeTableEntry *type_entry) {
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -3673,7 +3585,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -3765,6 +3677,27 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
}
}
+static bool analyze_resolve_inferred_error_set(CodeGen *g, TypeTableEntry *err_set_type, AstNode *source_node) {
+ FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
+ if (infer_fn != nullptr) {
+ if (infer_fn->anal_state == FnAnalStateInvalid) {
+ return false;
+ } else if (infer_fn->anal_state == FnAnalStateReady) {
+ analyze_fn_body(g, infer_fn);
+ if (err_set_type->data.error_set.infer_fn != nullptr) {
+ assert(g->errors.length != 0);
+ return false;
+ }
+ } else {
+ add_node_error(g, source_node,
+ buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
+ buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
+ return false;
+ }
+ }
+ return true;
+}
+
void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) {
TypeTableEntry *fn_type = fn_table_entry->type_entry;
assert(!fn_type->data.fn.is_generic);
@@ -3774,14 +3707,49 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
&fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
fn_table_entry->implicit_return_type = block_return_type;
- if (block_return_type->id == TypeTableEntryIdInvalid ||
- fn_table_entry->analyzed_executable.invalid)
- {
+ if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
assert(g->errors.length > 0);
fn_table_entry->anal_state = FnAnalStateInvalid;
return;
}
+ if (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
+ TypeTableEntry *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
+ if (return_err_set_type->data.error_set.infer_fn != nullptr) {
+ TypeTableEntry *inferred_err_set_type;
+ if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorSet) {
+ inferred_err_set_type = fn_table_entry->implicit_return_type;
+ } else if (fn_table_entry->implicit_return_type->id == TypeTableEntryIdErrorUnion) {
+ inferred_err_set_type = fn_table_entry->implicit_return_type->data.error_union.err_set_type;
+ } else {
+ add_node_error(g, return_type_node,
+ buf_sprintf("function with inferred error set must return at least one possible error"));
+ fn_table_entry->anal_state = FnAnalStateInvalid;
+ return;
+ }
+
+ if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
+ if (!analyze_resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
+ fn_table_entry->anal_state = FnAnalStateInvalid;
+ return;
+ }
+ }
+
+ return_err_set_type->data.error_set.infer_fn = nullptr;
+ if (type_is_global_error_set(inferred_err_set_type)) {
+ return_err_set_type->data.error_set.err_count = UINT32_MAX;
+ } else {
+ return_err_set_type->data.error_set.err_count = inferred_err_set_type->data.error_set.err_count;
+ if (inferred_err_set_type->data.error_set.err_count > 0) {
+ return_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(inferred_err_set_type->data.error_set.err_count);
+ for (uint32_t i = 0; i < inferred_err_set_type->data.error_set.err_count; i += 1) {
+ return_err_set_type->data.error_set.errors[i] = inferred_err_set_type->data.error_set.errors[i];
+ }
+ }
+ }
+ }
+ }
+
if (g->verbose_ir) {
fprintf(stderr, "{ // (analyzed)\n");
ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
@@ -3791,7 +3759,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
fn_table_entry->anal_state = FnAnalStateComplete;
}
-static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
+void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
assert(fn_table_entry->anal_state != FnAnalStateProbing);
if (fn_table_entry->anal_state != FnAnalStateReady)
return;
@@ -4022,7 +3990,8 @@ void semantic_analyze(CodeGen *g) {
for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) {
Tld *tld = g->resolve_queue.at(g->resolve_queue_index);
bool pointer_only = false;
- resolve_top_level_decl(g, tld, pointer_only, nullptr);
+ AstNode *source_node = nullptr;
+ resolve_top_level_decl(g, tld, pointer_only, source_node);
}
for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
@@ -4114,7 +4083,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdEnum:
return false;
@@ -4122,7 +4091,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
case TypeTableEntryIdStruct:
return type_has_bits(type_entry);
case TypeTableEntryIdErrorUnion:
- return type_has_bits(type_entry->data.error.child_type);
+ return type_has_bits(type_entry->data.error_union.payload_type);
case TypeTableEntryIdMaybe:
return type_has_bits(type_entry->data.maybe.child_type) &&
type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
@@ -4386,9 +4355,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
case TypeTableEntryIdErrorUnion:
// TODO better hashing algorithm
return 3415065496;
- case TypeTableEntryIdPureError:
- // TODO better hashing algorithm
- return 2630160122;
+ case TypeTableEntryIdErrorSet:
+ assert(const_val->data.x_err_set != nullptr);
+ return const_val->data.x_err_set->value ^ 2630160122;
case TypeTableEntryIdFn:
return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);
case TypeTableEntryIdNamespace:
@@ -4515,7 +4484,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdEnum:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
@@ -4894,8 +4863,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
return a->data.x_type == b->data.x_type;
case TypeTableEntryIdVoid:
return true;
- case TypeTableEntryIdPureError:
- return a->data.x_pure_err == b->data.x_pure_err;
+ case TypeTableEntryIdErrorSet:
+ return a->data.x_err_set->value == b->data.x_err_set->value;
case TypeTableEntryIdFn:
return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;
case TypeTableEntryIdBool:
@@ -5256,9 +5225,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name));
return;
}
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
{
- buf_appendf(buf, "(pure error constant)");
+ buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
return;
}
case TypeTableEntryIdArgTuple:
@@ -5319,8 +5288,7 @@ uint32_t type_id_hash(TypeId x) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -5329,6 +5297,8 @@ uint32_t type_id_hash(TypeId x) {
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
zig_unreachable();
+ case TypeTableEntryIdErrorUnion:
+ return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type);
case TypeTableEntryIdPointer:
return hash_ptr(x.data.pointer.child_type) +
(x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
@@ -5363,8 +5333,7 @@ bool type_id_eql(TypeId a, TypeId b) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -5374,6 +5343,10 @@ bool type_id_eql(TypeId a, TypeId b) {
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdOpaque:
zig_unreachable();
+ case TypeTableEntryIdErrorUnion:
+ return a.data.error_union.err_set_type == b.data.error_union.err_set_type &&
+ a.data.error_union.payload_type == b.data.error_union.payload_type;
+
case TypeTableEntryIdPointer:
return a.data.pointer.child_type == b.data.pointer.child_type &&
a.data.pointer.is_const == b.data.pointer.is_const &&
@@ -5478,7 +5451,7 @@ static const TypeTableEntryId all_type_ids[] = {
TypeTableEntryIdNullLit,
TypeTableEntryIdMaybe,
TypeTableEntryIdErrorUnion,
- TypeTableEntryIdPureError,
+ TypeTableEntryIdErrorSet,
TypeTableEntryIdEnum,
TypeTableEntryIdUnion,
TypeTableEntryIdFn,
@@ -5533,7 +5506,7 @@ size_t type_id_index(TypeTableEntryId id) {
return 13;
case TypeTableEntryIdErrorUnion:
return 14;
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
return 15;
case TypeTableEntryIdEnum:
return 16;
@@ -5590,8 +5563,8 @@ const char *type_id_name(TypeTableEntryId id) {
return "Nullable";
case TypeTableEntryIdErrorUnion:
return "ErrorUnion";
- case TypeTableEntryIdPureError:
- return "Error";
+ case TypeTableEntryIdErrorSet:
+ return "ErrorSet";
case TypeTableEntryIdEnum:
return "Enum";
case TypeTableEntryIdUnion:
@@ -5640,17 +5613,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
return link_lib;
}
-void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name) {
- LinkLib *link_lib = add_link_lib(g, lib_name);
- for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
- Buf *existing_symbol_name = link_lib->symbols.at(i);
- if (buf_eql_buf(existing_symbol_name, symbol_name)) {
- return;
- }
- }
- link_lib->symbols.append(symbol_name);
-}
-
uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
type_ensure_zero_bits_known(g, type_entry);
if (type_entry->zero_bits) return 0;
@@ -5696,3 +5658,8 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
return var_value;
}
+bool type_is_global_error_set(TypeTableEntry *err_set_type) {
+ assert(err_set_type->id == TypeTableEntryIdErrorSet);
+ assert(err_set_type->data.error_set.infer_fn == nullptr);
+ return err_set_type->data.error_set.err_count == UINT32_MAX;
+}
diff --git a/src/analyze.hpp b/src/analyze.hpp
index dab6d17d0c..c0c89cf36b 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -30,7 +30,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);
TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
AstNode *decl_node, const char *name, ContainerLayout layout);
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
-TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type);
+TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, TypeTableEntry *payload_type);
TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);
TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *name);
TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
@@ -46,8 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry);
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
-// TODO move these over, these used to be static
-bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
@@ -58,6 +56,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
bool type_is_complete(TypeTableEntry *type_entry);
bool type_is_invalid(TypeTableEntry *type_entry);
+bool type_is_global_error_set(TypeTableEntry *err_set_type);
bool type_has_zero_bits_known(TypeTableEntry *type_entry);
void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
@@ -176,7 +175,6 @@ bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
LinkLib *create_link_lib(Buf *name);
bool calling_convention_does_first_arg_return(CallingConvention cc);
LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
-void add_link_lib_symbol(CodeGen *g, Buf *lib_name, Buf *symbol_name);
uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry);
TypeTableEntry *get_align_amt_type(CodeGen *g);
@@ -188,6 +186,8 @@ void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, G
ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
+void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
+TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
#endif
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index 79cbc1b49a..aed4b3e6db 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -49,11 +49,12 @@ static const char *bin_op_str(BinOpType bin_op) {
case BinOpTypeAssignBitAnd: return "&=";
case BinOpTypeAssignBitXor: return "^=";
case BinOpTypeAssignBitOr: return "|=";
- case BinOpTypeAssignBoolAnd: return "&&=";
- case BinOpTypeAssignBoolOr: return "||=";
+ case BinOpTypeAssignMergeErrorSets: return "||=";
case BinOpTypeUnwrapMaybe: return "??";
case BinOpTypeArrayCat: return "++";
case BinOpTypeArrayMult: return "**";
+ case BinOpTypeErrorUnion: return "!";
+ case BinOpTypeMergeErrorSets: return "||";
}
zig_unreachable();
}
@@ -67,7 +68,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
case PrefixOpBinNot: return "~";
case PrefixOpDereference: return "*";
case PrefixOpMaybe: return "?";
- case PrefixOpError: return "%";
case PrefixOpUnwrapMaybe: return "??";
}
zig_unreachable();
@@ -174,8 +174,6 @@ static const char *node_type_str(NodeType node_type) {
return "Defer";
case NodeTypeVariableDeclaration:
return "VariableDeclaration";
- case NodeTypeErrorValueDecl:
- return "ErrorValueDecl";
case NodeTypeTestDecl:
return "TestDecl";
case NodeTypeIntLiteral:
@@ -244,6 +242,8 @@ static const char *node_type_str(NodeType node_type) {
return "IfErrorExpr";
case NodeTypeTestExpr:
return "TestExpr";
+ case NodeTypeErrorSetDecl:
+ return "ErrorSetDecl";
}
zig_unreachable();
}
@@ -396,7 +396,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
if (child->type == NodeTypeUse ||
child->type == NodeTypeVariableDeclaration ||
- child->type == NodeTypeErrorValueDecl ||
child->type == NodeTypeFnProto)
{
fprintf(ar->f, ";");
@@ -452,6 +451,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
AstNode *return_type_node = node->data.fn_proto.return_type;
assert(return_type_node != nullptr);
fprintf(ar->f, " ");
+ if (node->data.fn_proto.auto_err_set) {
+ fprintf(ar->f, "!");
+ }
render_node_grouped(ar, return_type_node);
break;
}
@@ -1017,9 +1019,26 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);
break;
}
+ case NodeTypeErrorSetDecl:
+ {
+ fprintf(ar->f, "error {\n");
+ ar->indent += ar->indent_size;
+
+ for (size_t i = 0; i < node->data.err_set_decl.decls.length; i += 1) {
+ AstNode *field_node = node->data.err_set_decl.decls.at(i);
+ assert(field_node->type == NodeTypeSymbol);
+ print_indent(ar);
+ print_symbol(ar, field_node->data.symbol_expr.symbol);
+ fprintf(ar->f, ",\n");
+ }
+
+ ar->indent -= ar->indent_size;
+ print_indent(ar);
+ fprintf(ar->f, "}");
+ break;
+ }
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeErrorValueDecl:
case NodeTypeTestDecl:
case NodeTypeStructField:
case NodeTypeUse:
diff --git a/src/codegen.cpp b/src/codegen.cpp
index b1412b2b59..69460d723a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -92,9 +92,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
buf_resize(&g->global_asm, 0);
- // reserve index 0 to indicate no error
- g->error_decls.append(nullptr);
-
if (root_src_path) {
Buf *src_basename = buf_alloc();
Buf *src_dir = buf_alloc();
@@ -256,6 +253,10 @@ LinkLib *codegen_add_link_lib(CodeGen *g, Buf *name) {
return add_link_lib(g, name);
}
+void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib) {
+ codegen->forbidden_libs.append(lib);
+}
+
void codegen_add_framework(CodeGen *g, const char *framework) {
g->darwin_frameworks.append(buf_create_from_str(framework));
}
@@ -410,7 +411,7 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
}
TypeTableEntry *fn_type = fn_table_entry->type_entry;
TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
- if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) {
+ if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdErrorSet) {
return UINT32_MAX;
}
bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
@@ -1442,7 +1443,7 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
// TODO: emit a branch to check if the return value is an error
}
- } else if (return_type->id == TypeTableEntryIdPureError) {
+ } else if (return_type->id == TypeTableEntryIdErrorSet) {
is_err_return = true;
}
if (is_err_return) {
@@ -1789,7 +1790,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy ||
op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy ||
- op_id == IrBinOpBitShiftRightExact);
+ op_id == IrBinOpBitShiftRightExact ||
+ (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet));
TypeTableEntry *type_entry = op1->value.type;
bool want_runtime_safety = bin_op_instruction->safety_check_on &&
@@ -1802,6 +1804,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
case IrBinOpArrayCat:
case IrBinOpArrayMult:
case IrBinOpRemUnspecified:
+ case IrBinOpMergeErrorSets:
zig_unreachable();
case IrBinOpBoolOr:
return LLVMBuildOr(g->builder, op1_value, op2_value, "");
@@ -1823,7 +1826,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
} else if (type_entry->id == TypeTableEntryIdEnum) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
- } else if (type_entry->id == TypeTableEntryIdPureError ||
+ } else if (type_entry->id == TypeTableEntryIdErrorSet ||
type_entry->id == TypeTableEntryIdPointer ||
type_entry->id == TypeTableEntryIdBool)
{
@@ -2078,6 +2081,9 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
assert(wanted_type->id == TypeTableEntryIdInt);
assert(actual_type->id == TypeTableEntryIdBool);
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+ case CastOpErrSet:
+ // TODO runtime safety for error casting
+ return expr_val;
}
zig_unreachable();
}
@@ -2139,7 +2145,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
TypeTableEntry *wanted_type = instruction->base.value.type;
- assert(wanted_type->id == TypeTableEntryIdPureError);
+ assert(wanted_type->id == TypeTableEntryIdErrorSet);
TypeTableEntry *actual_type = instruction->target->value.type;
assert(actual_type->id == TypeTableEntryIdInt);
@@ -2156,11 +2162,11 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I
eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true);
if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) &&
- bigint_as_unsigned(&biggest_possible_err_val) < g->error_decls.length)
+ bigint_as_unsigned(&biggest_possible_err_val) < g->errors_by_index.length)
{
ok_bit = neq_zero_bit;
} else {
- LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false);
+ LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->errors_by_index.length, false);
LLVMValueRef in_bounds_bit = LLVMBuildICmp(g->builder, LLVMIntULT, target_val, error_value_count, "");
ok_bit = LLVMBuildAnd(g->builder, neq_zero_bit, in_bounds_bit, "");
}
@@ -2187,15 +2193,18 @@ static LLVMValueRef ir_render_err_to_int(CodeGen *g, IrExecutable *executable, I
TypeTableEntry *actual_type = instruction->target->value.type;
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
- if (actual_type->id == TypeTableEntryIdPureError) {
+ if (actual_type->id == TypeTableEntryIdErrorSet) {
return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
g->err_tag_type, wanted_type, target_val);
} else if (actual_type->id == TypeTableEntryIdErrorUnion) {
- if (!type_has_bits(actual_type->data.error.child_type)) {
+ // this should have been a compile time constant
+ assert(type_has_bits(actual_type->data.error_union.err_set_type));
+
+ if (!type_has_bits(actual_type->data.error_union.payload_type)) {
return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
g->err_tag_type, wanted_type, target_val);
} else {
- zig_panic("TODO");
+ zig_panic("TODO err to int when error union payload type not void");
}
} else {
zig_unreachable();
@@ -2235,7 +2244,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
switch (op_id) {
case IrUnOpInvalid:
- case IrUnOpError:
case IrUnOpMaybe:
case IrUnOpDereference:
zig_unreachable();
@@ -2489,7 +2497,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
TypeTableEntry *src_return_type = fn_type_id->return_type;
bool ret_has_bits = type_has_bits(src_return_type);
bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
- bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError);
+ bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdErrorSet);
size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
bool is_var_args = fn_type_id->is_var_args;
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
@@ -2907,7 +2915,7 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrInstructionErrName *instruction) {
assert(g->generate_error_name_table);
- if (g->error_decls.length == 1) {
+ if (g->errors_by_index.length == 1) {
LLVMBuildUnreachable(g->builder);
return nullptr;
}
@@ -2915,7 +2923,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
if (ir_want_runtime_safety(g, &instruction->base)) {
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val));
- LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false);
+ LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->errors_by_index.length, false);
add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val);
}
@@ -3393,11 +3401,11 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
TypeTableEntry *err_union_type = instruction->value->value.type;
- TypeTableEntry *child_type = err_union_type->data.error.child_type;
+ TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
LLVMValueRef err_val;
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
} else {
@@ -3412,11 +3420,11 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
- TypeTableEntry *child_type = err_union_type->data.error.child_type;
+ TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
return gen_load_untyped(g, err_val_ptr, 0, false, "");
} else {
@@ -3428,13 +3436,17 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
TypeTableEntry *ptr_type = instruction->value->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *err_union_type = ptr_type->data.pointer.child_type;
- TypeTableEntry *child_type = err_union_type->data.error.child_type;
+ TypeTableEntry *payload_type = err_union_type->data.error_union.payload_type;
LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
- if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->error_decls.length > 1) {
+ if (!type_has_bits(err_union_type->data.error_union.err_set_type)) {
+ return err_union_handle;
+ }
+
+ if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
LLVMValueRef err_val;
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
err_val = gen_load_untyped(g, err_val_ptr, 0, false, "");
} else {
@@ -3452,7 +3464,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
- if (type_has_bits(child_type)) {
+ if (type_has_bits(payload_type)) {
return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
} else {
return nullptr;
@@ -3493,10 +3505,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = wanted_type->data.error.child_type;
+ TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
+ TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
+
LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
- if (!type_has_bits(child_type))
+ if (!type_has_bits(payload_type) || !type_has_bits(err_set_type))
return err_val;
assert(instruction->tmp_ptr);
@@ -3512,11 +3526,16 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = wanted_type->data.error.child_type;
+ TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
+ TypeTableEntry *err_set_type = wanted_type->data.error_union.err_set_type;
+
+ if (!type_has_bits(err_set_type)) {
+ return ir_llvm_value(g, instruction->value);
+ }
LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
- if (!type_has_bits(child_type))
+ if (!type_has_bits(payload_type))
return ok_err_val;
assert(instruction->tmp_ptr);
@@ -3527,7 +3546,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
- gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, child_type, false), payload_val);
+ gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val);
return instruction->tmp_ptr;
}
@@ -3700,6 +3719,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdArgType:
case IrInstructionIdTagType:
case IrInstructionIdExport:
+ case IrInstructionIdErrorUnion:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -3933,7 +3953,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -4026,10 +4046,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
switch (type_entry->id) {
case TypeTableEntryIdInt:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
- case TypeTableEntryIdPureError:
- assert(const_val->data.x_pure_err);
- return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
- const_val->data.x_pure_err->value, false);
+ case TypeTableEntryIdErrorSet:
+ assert(const_val->data.x_err_set != nullptr);
+ return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
+ const_val->data.x_err_set->value, false);
case TypeTableEntryIdFloat:
switch (type_entry->data.floating.bit_count) {
case 32:
@@ -4330,17 +4350,22 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
}
case TypeTableEntryIdErrorUnion:
{
- TypeTableEntry *child_type = type_entry->data.error.child_type;
- if (!type_has_bits(child_type)) {
+ TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
+ TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
+ if (!type_has_bits(payload_type)) {
+ assert(type_has_bits(err_set_type));
uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
+ } else if (!type_has_bits(err_set_type)) {
+ assert(type_has_bits(payload_type));
+ return gen_const_val(g, const_val->data.x_err_union.payload);
} else {
LLVMValueRef err_tag_value;
LLVMValueRef err_payload_value;
bool make_unnamed_struct;
if (const_val->data.x_err_union.err) {
err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
- err_payload_value = LLVMConstNull(child_type->type_ref);
+ err_payload_value = LLVMConstNull(payload_type->type_ref);
make_unnamed_struct = false;
} else {
err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
@@ -4410,21 +4435,20 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const
}
static void generate_error_name_table(CodeGen *g) {
- if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) {
+ if (g->err_name_table != nullptr || !g->generate_error_name_table || g->errors_by_index.length == 1) {
return;
}
- assert(g->error_decls.length > 0);
+ assert(g->errors_by_index.length > 0);
TypeTableEntry *u8_ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type);
- LLVMValueRef *values = allocate<LLVMValueRef>(g->error_decls.length);
+ LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
values[0] = LLVMGetUndef(str_type->type_ref);
- for (size_t i = 1; i < g->error_decls.length; i += 1) {
- AstNode *error_decl_node = g->error_decls.at(i);
- assert(error_decl_node->type == NodeTypeErrorValueDecl);
- Buf *name = error_decl_node->data.error_value_decl.name;
+ for (size_t i = 1; i < g->errors_by_index.length; i += 1) {
+ ErrorTableEntry *err_entry = g->errors_by_index.at(i);
+ Buf *name = &err_entry->name;
g->largest_err_name_len = max(g->largest_err_name_len, buf_len(name));
@@ -4443,7 +4467,7 @@ static void generate_error_name_table(CodeGen *g) {
values[i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2);
}
- LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->error_decls.length);
+ LLVMValueRef err_name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)g->errors_by_index.length);
g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));
@@ -4573,6 +4597,28 @@ static void validate_inline_fns(CodeGen *g) {
static void do_code_gen(CodeGen *g) {
assert(!g->errors.length);
+ {
+ // create debug type for error sets
+ assert(g->err_enumerators.length == g->errors_by_index.length);
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, g->err_tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, g->err_tag_type->type_ref);
+ ZigLLVMDIFile *err_set_di_file = nullptr;
+ ZigLLVMDIType *err_set_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMCompileUnitToScope(g->compile_unit), buf_ptr(&g->builtin_types.entry_global_error_set->name),
+ err_set_di_file, 0,
+ tag_debug_size_in_bits,
+ tag_debug_align_in_bits,
+ g->err_enumerators.items, g->err_enumerators.length,
+ g->err_tag_type->di_type, "");
+ ZigLLVMReplaceTemporary(g->dbuilder, g->builtin_types.entry_global_error_set->di_type, err_set_di_type);
+ g->builtin_types.entry_global_error_set->di_type = err_set_di_type;
+
+ for (size_t i = 0; i < g->error_di_types.length; i += 1) {
+ ZigLLVMDIType **di_type_ptr = g->error_di_types.at(i);
+ *di_type_ptr = err_set_di_type;
+ }
+ }
+
codegen_add_time_event(g, "Code Generation");
generate_error_name_table(g);
@@ -5176,16 +5222,24 @@ static void define_builtin_types(CodeGen *g) {
}
{
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorSet);
buf_init_from_str(&entry->name, "error");
+ entry->data.error_set.err_count = UINT32_MAX;
// TODO allow overriding this type and keep track of max value and emit an
// error if there are too many errors declared
g->err_tag_type = g->builtin_types.entry_u16;
- g->builtin_types.entry_pure_error = entry;
+ g->builtin_types.entry_global_error_set = entry;
entry->type_ref = g->err_tag_type->type_ref;
- entry->di_type = g->err_tag_type->di_type;
+
+ entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
+ ZigLLVMTag_DW_enumeration_type(), "error",
+ ZigLLVMCompileUnitToScope(g->compile_unit), nullptr, 0);
+
+ // reserve index 0 to indicate no error
+ g->err_enumerators.append(ZigLLVMCreateDebugEnumerator(g->dbuilder, "(none)", 0));
+ g->errors_by_index.append(nullptr);
g->primitive_type_table.put(&entry->name, entry);
}
@@ -5815,7 +5869,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
zig_unreachable();
case TypeTableEntryIdVoid:
case TypeTableEntryIdUnreachable:
@@ -5988,7 +6042,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
return;
}
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
zig_panic("TODO implement get_c_type for more types");
case TypeTableEntryIdInvalid:
@@ -6155,7 +6209,7 @@ static void gen_h_file(CodeGen *g) {
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -6265,3 +6319,4 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
}
return pkg;
}
+
diff --git a/src/codegen.hpp b/src/codegen.hpp
index b29cadee55..a7a4b748c4 100644
--- a/src/codegen.hpp
+++ b/src/codegen.hpp
@@ -36,6 +36,7 @@ void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
+void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
void codegen_add_framework(CodeGen *codegen, const char *name);
void codegen_add_rpath(CodeGen *codegen, const char *name);
diff --git a/src/ir.cpp b/src/ir.cpp
index ae8ef00f2f..9cc05a2bc2 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -45,6 +45,59 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {
return { true, is_const, is_volatile };
}
+enum ConstCastResultId {
+ ConstCastResultIdOk,
+ ConstCastResultIdErrSet,
+ ConstCastResultIdErrSetGlobal,
+ ConstCastResultIdPointerChild,
+ ConstCastResultIdSliceChild,
+ ConstCastResultIdNullableChild,
+ ConstCastResultIdErrorUnionPayload,
+ ConstCastResultIdErrorUnionErrorSet,
+ ConstCastResultIdFnAlign,
+ ConstCastResultIdFnCC,
+ ConstCastResultIdFnVarArgs,
+ ConstCastResultIdFnIsGeneric,
+ ConstCastResultIdFnReturnType,
+ ConstCastResultIdFnArgCount,
+ ConstCastResultIdFnGenericArgCount,
+ ConstCastResultIdFnArg,
+ ConstCastResultIdFnArgNoAlias,
+ ConstCastResultIdType,
+ ConstCastResultIdUnresolvedInferredErrSet,
+};
+
+struct ConstCastErrSetMismatch {
+ ZigList<ErrorTableEntry *> missing_errors;
+};
+
+struct ConstCastOnly;
+
+struct ConstCastArg {
+ size_t arg_index;
+ ConstCastOnly *child;
+};
+
+struct ConstCastArgNoAlias {
+ size_t arg_index;
+};
+
+struct ConstCastOnly {
+ ConstCastResultId id;
+ union {
+ ConstCastErrSetMismatch error_set;
+ ConstCastOnly *pointer_child;
+ ConstCastOnly *slice_child;
+ ConstCastOnly *nullable_child;
+ ConstCastOnly *error_union_payload;
+ ConstCastOnly *error_union_error_set;
+ ConstCastOnly *return_type;
+ ConstCastArg fn_arg;
+ ConstCastArgNoAlias arg_no_alias;
+ } data;
+};
+
+
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
@@ -580,6 +633,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace
return IrInstructionIdErrorReturnTrace;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) {
+ return IrInstructionIdErrorUnion;
+}
+
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -2326,6 +2383,19 @@ static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope,
return &instruction->base;
}
+static IrInstruction *ir_build_error_union(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *err_set, IrInstruction *payload)
+{
+ IrInstructionErrorUnion *instruction = ir_build_instruction<IrInstructionErrorUnion>(irb, scope, source_node);
+ instruction->err_set = err_set;
+ instruction->payload = payload;
+
+ ir_ref_instruction(err_set, irb->current_basic_block);
+ ir_ref_instruction(payload, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -2800,6 +2870,23 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
}
+static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+ assert(node->type == NodeTypeBinOpExpr);
+
+ AstNode *op1_node = node->data.bin_op_expr.op1;
+ AstNode *op2_node = node->data.bin_op_expr.op2;
+
+ IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope);
+ if (err_set == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope);
+ if (payload == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ return ir_build_error_union(irb, parent_scope, node, err_set, payload);
+}
+
static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
@@ -2835,10 +2922,8 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);
case BinOpTypeAssignBitOr:
return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);
- case BinOpTypeAssignBoolAnd:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBoolAnd);
- case BinOpTypeAssignBoolOr:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBoolOr);
+ case BinOpTypeAssignMergeErrorSets:
+ return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets);
case BinOpTypeBoolOr:
return ir_gen_bool_or(irb, scope, node);
case BinOpTypeBoolAnd:
@@ -2885,8 +2970,12 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);
case BinOpTypeArrayMult:
return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
+ case BinOpTypeMergeErrorSets:
+ return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
case BinOpTypeUnwrapMaybe:
return ir_gen_maybe_ok_or(irb, scope, node);
+ case BinOpTypeErrorUnion:
+ return ir_gen_error_union(irb, scope, node);
}
zig_unreachable();
}
@@ -3990,8 +4079,6 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
case PrefixOpMaybe:
return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval);
- case PrefixOpError:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpError), lval);
case PrefixOpUnwrapMaybe:
return ir_gen_maybe_assert_ok(irb, scope, node, lval);
}
@@ -5165,7 +5252,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeErrorType);
- return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_pure_error);
+ return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_global_error_set);
}
static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -5249,8 +5336,6 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
Scope *err_scope;
if (var_node) {
assert(var_node->type == NodeTypeSymbol);
- IrInstruction *var_type = ir_build_const_type(irb, parent_scope, node,
- irb->codegen->builtin_types.entry_pure_error);
Buf *var_name = var_node->data.symbol_expr.symbol;
bool is_const = true;
bool is_shadowable = false;
@@ -5258,7 +5343,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
- ir_build_var_decl(irb, err_scope, var_node, var, var_type, nullptr, err_val);
+ ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
} else {
err_scope = parent_scope;
}
@@ -5348,6 +5433,135 @@ 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{");
+
+ for (uint32_t i = 0, count = set1->data.error_set.err_count; i < count; i += 1) {
+ assert(errors[set1->data.error_set.errors[i]->value] == set1->data.error_set.errors[i]);
+ }
+
+ 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);
+ assert(count != 0);
+
+ 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, "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;
+ err_set_type->data.error_set.err_count = 1;
+ err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1);
+
+ g->error_di_types.append(&err_set_type->di_type);
+
+ err_set_type->data.error_set.errors[0] = err_entry;
+
+ return err_set_type;
+}
+
+static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+ assert(node->type == NodeTypeErrorSetDecl);
+
+ uint32_t err_count = node->data.err_set_decl.decls.length;
+
+ Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error set", node);
+ TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
+ buf_init_from_buf(&err_set_type->name, type_name);
+ err_set_type->is_copyable = true;
+ err_set_type->data.error_set.err_count = err_count;
+
+ if (err_count == 0) {
+ err_set_type->zero_bits = true;
+ err_set_type->di_type = irb->codegen->builtin_types.entry_void->di_type;
+ } else {
+ err_set_type->type_ref = irb->codegen->builtin_types.entry_global_error_set->type_ref;
+ err_set_type->di_type = irb->codegen->builtin_types.entry_global_error_set->di_type;
+ irb->codegen->error_di_types.append(&err_set_type->di_type);
+ err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
+ }
+
+ ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
+
+ for (uint32_t i = 0; i < err_count; i += 1) {
+ AstNode *symbol_node = node->data.err_set_decl.decls.at(i);
+ assert(symbol_node->type == NodeTypeSymbol);
+ Buf *err_name = symbol_node->data.symbol_expr.symbol;
+ ErrorTableEntry *err = allocate<ErrorTableEntry>(1);
+ err->decl_node = symbol_node;
+ buf_init_from_buf(&err->name, err_name);
+
+ auto existing_entry = irb->codegen->error_table.put_unique(err_name, err);
+ if (existing_entry) {
+ err->value = existing_entry->value->value;
+ } else {
+ size_t error_value_count = irb->codegen->errors_by_index.length;
+ assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)irb->codegen->err_tag_type->data.integral.bit_count));
+ err->value = error_value_count;
+ irb->codegen->errors_by_index.append(err);
+ irb->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(irb->codegen->dbuilder,
+ buf_ptr(err_name), error_value_count));
+ }
+ err_set_type->data.error_set.errors[i] = err;
+
+ ErrorTableEntry *prev_err = errors[err->value];
+ if (prev_err != nullptr) {
+ ErrorMsg *msg = add_node_error(irb->codegen, err->decl_node, buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name)));
+ add_error_note(irb->codegen, msg, prev_err->decl_node, buf_sprintf("other error here"));
+ return irb->codegen->invalid_instruction;
+ }
+ errors[err->value] = err;
+ }
+ free(errors);
+ return ir_build_const_type(irb, parent_scope, node, err_set_type);
+}
+
static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
assert(node->type == NodeTypeFnProto);
@@ -5401,7 +5615,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeStructField:
case NodeTypeFnDef:
case NodeTypeFnDecl:
- case NodeTypeErrorValueDecl:
case NodeTypeTestDecl:
zig_unreachable();
case NodeTypeBlock:
@@ -5482,6 +5695,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
case NodeTypeFnProto:
return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
+ case NodeTypeErrorSetDecl:
+ return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
}
zig_unreachable();
}
@@ -6287,6 +6502,274 @@ static bool slice_is_const(TypeTableEntry *type) {
return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
}
+static bool resolve_inferred_error_set(IrAnalyze *ira, TypeTableEntry *err_set_type, AstNode *source_node) {
+ assert(err_set_type->id == TypeTableEntryIdErrorSet);
+ FnTableEntry *infer_fn = err_set_type->data.error_set.infer_fn;
+ if (infer_fn != nullptr) {
+ if (infer_fn->anal_state == FnAnalStateInvalid) {
+ return false;
+ } else if (infer_fn->anal_state == FnAnalStateReady) {
+ analyze_fn_body(ira->codegen, infer_fn);
+ if (err_set_type->data.error_set.infer_fn != nullptr) {
+ assert(ira->codegen->errors.length != 0);
+ return false;
+ }
+ } else {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("cannot resolve inferred error set '%s': function '%s' not fully analyzed yet",
+ buf_ptr(&err_set_type->name), buf_ptr(&err_set_type->data.error_set.infer_fn->symbol_name)));
+ return false;
+ }
+ }
+ return true;
+}
+
+static TypeTableEntry *get_error_set_intersection(IrAnalyze *ira, TypeTableEntry *set1, TypeTableEntry *set2,
+ AstNode *source_node)
+{
+ assert(set1->id == TypeTableEntryIdErrorSet);
+ assert(set2->id == TypeTableEntryIdErrorSet);
+
+ if (!resolve_inferred_error_set(ira, set1, source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (!resolve_inferred_error_set(ira, set2, source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (type_is_global_error_set(set1)) {
+ return set2;
+ }
+ if (type_is_global_error_set(set2)) {
+ return set1;
+ }
+ ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
+ for (uint32_t i = 0; i < set1->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = set1->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ ZigList<ErrorTableEntry *> intersection_list = {};
+
+ TypeTableEntry *err_set_type = new_type_table_entry(TypeTableEntryIdErrorSet);
+ buf_resize(&err_set_type->name, 0);
+ buf_appendf(&err_set_type->name, "error{");
+
+ for (uint32_t i = 0; i < set2->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = set2->data.error_set.errors[i];
+ ErrorTableEntry *existing_entry = errors[error_entry->value];
+ if (existing_entry != nullptr) {
+ intersection_list.append(existing_entry);
+ buf_appendf(&err_set_type->name, "%s,", buf_ptr(&existing_entry->name));
+ }
+ }
+ free(errors);
+
+ err_set_type->is_copyable = true;
+ err_set_type->type_ref = ira->codegen->builtin_types.entry_global_error_set->type_ref;
+ err_set_type->di_type = ira->codegen->builtin_types.entry_global_error_set->di_type;
+ err_set_type->data.error_set.err_count = intersection_list.length;
+ err_set_type->data.error_set.errors = intersection_list.items;
+ err_set_type->zero_bits = intersection_list.length == 0;
+
+ buf_appendf(&err_set_type->name, "}");
+
+ ira->codegen->error_di_types.append(&err_set_type->di_type);
+
+ return err_set_type;
+}
+
+
+static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry *expected_type,
+ TypeTableEntry *actual_type, AstNode *source_node)
+{
+ CodeGen *g = ira->codegen;
+ ConstCastOnly result = {};
+ result.id = ConstCastResultIdOk;
+
+ if (expected_type == actual_type)
+ return result;
+
+ // pointer const
+ if (expected_type->id == TypeTableEntryIdPointer &&
+ actual_type->id == TypeTableEntryIdPointer &&
+ (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const) &&
+ (!actual_type->data.pointer.is_volatile || expected_type->data.pointer.is_volatile) &&
+ actual_type->data.pointer.bit_offset == expected_type->data.pointer.bit_offset &&
+ actual_type->data.pointer.unaligned_bit_count == expected_type->data.pointer.unaligned_bit_count &&
+ actual_type->data.pointer.alignment >= expected_type->data.pointer.alignment)
+ {
+ ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.pointer.child_type, actual_type->data.pointer.child_type, source_node);
+ if (child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdPointerChild;
+ result.data.pointer_child = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.pointer_child = child;
+ }
+ return result;
+ }
+
+ // slice const
+ if (is_slice(expected_type) && is_slice(actual_type)) {
+ TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
+ TypeTableEntry *expected_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
+ if ((!actual_ptr_type->data.pointer.is_const || expected_ptr_type->data.pointer.is_const) &&
+ (!actual_ptr_type->data.pointer.is_volatile || expected_ptr_type->data.pointer.is_volatile) &&
+ actual_ptr_type->data.pointer.bit_offset == expected_ptr_type->data.pointer.bit_offset &&
+ actual_ptr_type->data.pointer.unaligned_bit_count == expected_ptr_type->data.pointer.unaligned_bit_count &&
+ actual_ptr_type->data.pointer.alignment >= expected_ptr_type->data.pointer.alignment)
+ {
+ ConstCastOnly child = types_match_const_cast_only(ira, expected_ptr_type->data.pointer.child_type,
+ actual_ptr_type->data.pointer.child_type, source_node);
+ if (child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdSliceChild;
+ result.data.slice_child = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.slice_child = child;
+ }
+ return result;
+ }
+ }
+
+ // maybe
+ if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) {
+ ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type, source_node);
+ if (child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdNullableChild;
+ result.data.nullable_child = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.nullable_child = child;
+ }
+ return result;
+ }
+
+ // error union
+ if (expected_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
+ ConstCastOnly payload_child = types_match_const_cast_only(ira, expected_type->data.error_union.payload_type, actual_type->data.error_union.payload_type, source_node);
+ if (payload_child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdErrorUnionPayload;
+ result.data.error_union_payload = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.error_union_payload = payload_child;
+ return result;
+ }
+ ConstCastOnly error_set_child = types_match_const_cast_only(ira, expected_type->data.error_union.err_set_type, actual_type->data.error_union.err_set_type, source_node);
+ if (error_set_child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdErrorUnionErrorSet;
+ result.data.error_union_error_set = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.error_union_error_set = error_set_child;
+ return result;
+ }
+ return result;
+ }
+
+ // error set
+ if (expected_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
+ TypeTableEntry *contained_set = actual_type;
+ TypeTableEntry *container_set = expected_type;
+
+ // if the container set is inferred, then this will always work.
+ if (container_set->data.error_set.infer_fn != nullptr) {
+ return result;
+ }
+ // if the container set is the global one, it will always work.
+ if (type_is_global_error_set(container_set)) {
+ return result;
+ }
+
+ if (!resolve_inferred_error_set(ira, contained_set, source_node)) {
+ result.id = ConstCastResultIdUnresolvedInferredErrSet;
+ return result;
+ }
+
+ if (type_is_global_error_set(contained_set)) {
+ result.id = ConstCastResultIdErrSetGlobal;
+ return result;
+ }
+
+ ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);
+ for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ if (result.id == ConstCastResultIdOk) {
+ result.id = ConstCastResultIdErrSet;
+ }
+ result.data.error_set.missing_errors.append(contained_error_entry);
+ }
+ }
+ free(errors);
+ return result;
+ }
+
+ // fn
+ if (expected_type->id == TypeTableEntryIdFn &&
+ actual_type->id == TypeTableEntryIdFn)
+ {
+ if (expected_type->data.fn.fn_type_id.alignment > actual_type->data.fn.fn_type_id.alignment) {
+ result.id = ConstCastResultIdFnAlign;
+ return result;
+ }
+ if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
+ result.id = ConstCastResultIdFnCC;
+ return result;
+ }
+ if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
+ result.id = ConstCastResultIdFnVarArgs;
+ return result;
+ }
+ if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
+ result.id = ConstCastResultIdFnIsGeneric;
+ return result;
+ }
+ if (!expected_type->data.fn.is_generic &&
+ actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable)
+ {
+ ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.fn.fn_type_id.return_type, actual_type->data.fn.fn_type_id.return_type, source_node);
+ if (child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdFnReturnType;
+ result.data.return_type = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.return_type = child;
+ }
+ return result;
+ }
+ if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
+ result.id = ConstCastResultIdFnArgCount;
+ return result;
+ }
+ if (expected_type->data.fn.fn_type_id.next_param_index != actual_type->data.fn.fn_type_id.next_param_index) {
+ result.id = ConstCastResultIdFnGenericArgCount;
+ return result;
+ }
+ assert(expected_type->data.fn.is_generic ||
+ expected_type->data.fn.fn_type_id.next_param_index == expected_type->data.fn.fn_type_id.param_count);
+ for (size_t i = 0; i < expected_type->data.fn.fn_type_id.next_param_index; i += 1) {
+ // note it's reversed for parameters
+ FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
+ FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
+
+ ConstCastOnly arg_child = types_match_const_cast_only(ira, actual_param_info->type, expected_param_info->type, source_node);
+ if (arg_child.id != ConstCastResultIdOk) {
+ result.id = ConstCastResultIdFnArg;
+ result.data.fn_arg.arg_index = i;
+ result.data.fn_arg.child = allocate_nonzero<ConstCastOnly>(1);
+ *result.data.fn_arg.child = arg_child;
+ return result;
+ }
+
+ if (expected_param_info->is_noalias != actual_param_info->is_noalias) {
+ result.id = ConstCastResultIdFnArgNoAlias;
+ result.data.arg_no_alias.arg_index = i;
+ return result;
+ }
+ }
+ return result;
+ }
+
+ result.id = ConstCastResultIdType;
+ return result;
+}
+
enum ImplicitCastMatchResult {
ImplicitCastMatchResultNo,
ImplicitCastMatchResultYes,
@@ -6296,10 +6779,46 @@ enum ImplicitCastMatchResult {
static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type,
TypeTableEntry *actual_type, IrInstruction *value)
{
- if (types_match_const_cast_only(expected_type, actual_type)) {
+ AstNode *source_node = value->source_node;
+ ConstCastOnly const_cast_result = types_match_const_cast_only(ira, expected_type, actual_type, source_node);
+ if (const_cast_result.id == ConstCastResultIdOk) {
return ImplicitCastMatchResultYes;
}
+ // if we got here with error sets, make an error showing the incompatibilities
+ ZigList<ErrorTableEntry *> *missing_errors = nullptr;
+ if (const_cast_result.id == ConstCastResultIdErrSet) {
+ missing_errors = &const_cast_result.data.error_set.missing_errors;
+ }
+ if (const_cast_result.id == ConstCastResultIdErrorUnionErrorSet) {
+ if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSet) {
+ missing_errors = &const_cast_result.data.error_union_error_set->data.error_set.missing_errors;
+ } else if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSetGlobal) {
+ ErrorMsg *msg = ir_add_error(ira, value,
+ buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
+ add_error_note(ira->codegen, msg, value->source_node,
+ buf_sprintf("unable to cast global error set into smaller set"));
+ return ImplicitCastMatchResultReportedError;
+ }
+ } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) {
+ ErrorMsg *msg = ir_add_error(ira, value,
+ buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
+ add_error_note(ira->codegen, msg, value->source_node,
+ buf_sprintf("unable to cast global error set into smaller set"));
+ return ImplicitCastMatchResultReportedError;
+ }
+ if (missing_errors != nullptr) {
+ ErrorMsg *msg = ir_add_error(ira, value,
+ buf_sprintf("expected '%s', found '%s'", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name)));
+ for (size_t i = 0; i < missing_errors->length; i += 1) {
+ ErrorTableEntry *error_entry = missing_errors->at(i);
+ add_error_note(ira->codegen, msg, error_entry->decl_node,
+ buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name)));
+ }
+
+ return ImplicitCastMatchResultReportedError;
+ }
+
// implicit conversion from anything to var
if (expected_type->id == TypeTableEntryIdVar) {
return ImplicitCastMatchResultYes;
@@ -6319,25 +6838,25 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
return ImplicitCastMatchResultYes;
}
- // implicit T to %T
+ // implicit T to U!T
if (expected_type->id == TypeTableEntryIdErrorUnion &&
- ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value))
+ ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type, actual_type, value))
{
return ImplicitCastMatchResultYes;
}
- // implicit conversion from pure error to error union type
+ // implicit conversion from error set to error union type
if (expected_type->id == TypeTableEntryIdErrorUnion &&
- actual_type->id == TypeTableEntryIdPureError)
+ actual_type->id == TypeTableEntryIdErrorSet)
{
return ImplicitCastMatchResultYes;
}
- // implicit conversion from T to %?T
+ // implicit conversion from T to U!?T
if (expected_type->id == TypeTableEntryIdErrorUnion &&
- expected_type->data.error.child_type->id == TypeTableEntryIdMaybe &&
+ expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
ir_types_match_with_implicit_cast(ira,
- expected_type->data.error.child_type->data.maybe.child_type,
+ expected_type->data.error_union.payload_type->data.maybe.child_type,
actual_type, value))
{
return ImplicitCastMatchResultYes;
@@ -6374,7 +6893,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
return ImplicitCastMatchResultYes;
}
@@ -6392,7 +6911,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
TypeTableEntry *array_type = actual_type->data.pointer.child_type;
if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
return ImplicitCastMatchResultYes;
}
@@ -6408,7 +6927,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
expected_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
return ImplicitCastMatchResultYes;
}
@@ -6423,7 +6942,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
expected_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
return ImplicitCastMatchResultYes;
}
@@ -6503,7 +7022,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
// implicitly take a const pointer to something
if (!type_requires_comptime(actual_type)) {
TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
- if (types_match_const_cast_only(expected_type, const_ptr_actual)) {
+ if (types_match_const_cast_only(ira, expected_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
return ImplicitCastMatchResultYes;
}
}
@@ -6511,13 +7030,39 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
return ImplicitCastMatchResultNo;
}
+static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
+ size_t old_errors_count = *errors_count;
+ *errors_count = g->errors_by_index.length;
+ *errors = reallocate(*errors, old_errors_count, *errors_count);
+}
+
static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, IrInstruction **instructions, size_t instruction_count) {
assert(instruction_count >= 1);
IrInstruction *prev_inst = instructions[0];
if (type_is_invalid(prev_inst->value.type)) {
return ira->codegen->builtin_types.entry_invalid;
}
- bool any_are_pure_error = (prev_inst->value.type->id == TypeTableEntryIdPureError);
+ ErrorTableEntry **errors = nullptr;
+ size_t errors_count = 0;
+ TypeTableEntry *err_set_type = nullptr;
+ if (prev_inst->value.type->id == TypeTableEntryIdErrorSet) {
+ if (type_is_global_error_set(prev_inst->value.type)) {
+ err_set_type = ira->codegen->builtin_types.entry_global_error_set;
+ } else {
+ err_set_type = prev_inst->value.type;
+ if (!resolve_inferred_error_set(ira, err_set_type, prev_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ update_errors_helper(ira->codegen, &errors, &errors_count);
+
+ 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];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ }
+ }
+
bool any_are_null = (prev_inst->value.type->id == TypeTableEntryIdNullLit);
bool convert_to_const_slice = false;
for (size_t i = 1; i < instruction_count; i += 1) {
@@ -6538,34 +7083,280 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
continue;
}
- if (prev_type->id == TypeTableEntryIdPureError) {
+ if (prev_type->id == TypeTableEntryIdNullLit) {
prev_inst = cur_inst;
continue;
}
- if (prev_type->id == TypeTableEntryIdNullLit) {
- prev_inst = cur_inst;
+ if (cur_type->id == TypeTableEntryIdNullLit) {
+ any_are_null = true;
continue;
}
- if (cur_type->id == TypeTableEntryIdPureError) {
+ if (prev_type->id == TypeTableEntryIdErrorSet) {
+ assert(err_set_type != nullptr);
+ if (cur_type->id == TypeTableEntryIdErrorSet) {
+ if (type_is_global_error_set(err_set_type)) {
+ continue;
+ }
+ if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (type_is_global_error_set(cur_type)) {
+ err_set_type = ira->codegen->builtin_types.entry_global_error_set;
+ prev_inst = cur_inst;
+ continue;
+ }
+
+ // number of declared errors might have increased now
+ update_errors_helper(ira->codegen, &errors, &errors_count);
+
+ // 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
+ 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];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ prev_is_superset = false;
+ break;
+ }
+ }
+ if (prev_is_superset) {
+ continue;
+ }
+
+ // 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];
+ errors[error_entry->value] = nullptr;
+ }
+ for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
+ assert(errors[i] == nullptr);
+ }
+ for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = cur_type->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ bool cur_is_superset = true;
+ for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ cur_is_superset = false;
+ break;
+ }
+ }
+ if (cur_is_superset) {
+ err_set_type = cur_type;
+ prev_inst = cur_inst;
+ assert(errors != nullptr);
+ 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);
+ assert(errors != nullptr);
+ continue;
+ } else if (cur_type->id == TypeTableEntryIdErrorUnion) {
+ if (type_is_global_error_set(err_set_type)) {
+ prev_inst = cur_inst;
+ continue;
+ }
+ TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
+ if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (type_is_global_error_set(cur_err_set_type)) {
+ err_set_type = ira->codegen->builtin_types.entry_global_error_set;
+ prev_inst = cur_inst;
+ continue;
+ }
+
+ update_errors_helper(ira->codegen, &errors, &errors_count);
+
+ // 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];
+ errors[error_entry->value] = nullptr;
+ }
+ for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
+ assert(errors[i] == nullptr);
+ }
+ for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ bool cur_is_superset = true;
+ for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *contained_error_entry = err_set_type->data.error_set.errors[i];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ cur_is_superset = false;
+ break;
+ }
+ }
+ if (cur_is_superset) {
+ err_set_type = cur_err_set_type;
+ prev_inst = cur_inst;
+ assert(errors != nullptr);
+ 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;
+ assert(errors != nullptr);
+ continue;
+ } else {
+ prev_inst = cur_inst;
+ continue;
+ }
+ }
+
+ if (cur_type->id == TypeTableEntryIdErrorSet) {
if (prev_type->id == TypeTableEntryIdArray) {
convert_to_const_slice = true;
}
- any_are_pure_error = true;
+ if (type_is_global_error_set(cur_type)) {
+ err_set_type = ira->codegen->builtin_types.entry_global_error_set;
+ continue;
+ }
+ if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
+ continue;
+ }
+ if (!resolve_inferred_error_set(ira, cur_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ update_errors_helper(ira->codegen, &errors, &errors_count);
+
+ if (err_set_type == nullptr) {
+ if (prev_type->id == TypeTableEntryIdErrorUnion) {
+ err_set_type = prev_type->data.error_union.err_set_type;
+ } else {
+ err_set_type = cur_type;
+ }
+ 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];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ if (err_set_type == cur_type) {
+ continue;
+ }
+ }
+ // check if the cur type error set is 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];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ prev_is_superset = false;
+ break;
+ }
+ }
+ 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);
+ assert(errors != nullptr);
continue;
}
- if (cur_type->id == TypeTableEntryIdNullLit) {
- any_are_null = true;
- continue;
+ if (prev_type->id == TypeTableEntryIdErrorUnion && cur_type->id == TypeTableEntryIdErrorUnion) {
+ TypeTableEntry *prev_payload_type = prev_type->data.error_union.payload_type;
+ TypeTableEntry *cur_payload_type = cur_type->data.error_union.payload_type;
+
+ bool const_cast_prev = types_match_const_cast_only(ira, prev_payload_type, cur_payload_type,
+ source_node).id == ConstCastResultIdOk;
+ bool const_cast_cur = types_match_const_cast_only(ira, cur_payload_type, prev_payload_type,
+ source_node).id == ConstCastResultIdOk;
+
+ if (const_cast_prev || const_cast_cur) {
+ if (const_cast_cur) {
+ prev_inst = cur_inst;
+ }
+
+ TypeTableEntry *prev_err_set_type = prev_type->data.error_union.err_set_type;
+ TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
+
+ if (!resolve_inferred_error_set(ira, prev_err_set_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (type_is_global_error_set(prev_err_set_type) || type_is_global_error_set(cur_err_set_type)) {
+ err_set_type = ira->codegen->builtin_types.entry_global_error_set;
+ continue;
+ }
+
+ update_errors_helper(ira->codegen, &errors, &errors_count);
+
+ if (err_set_type == nullptr) {
+ err_set_type = prev_err_set_type;
+ for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = prev_err_set_type->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ }
+ bool prev_is_superset = true;
+ for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *contained_error_entry = cur_err_set_type->data.error_set.errors[i];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ prev_is_superset = false;
+ break;
+ }
+ }
+ if (prev_is_superset) {
+ continue;
+ }
+ // unset all the 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];
+ errors[error_entry->value] = nullptr;
+ }
+ for (uint32_t i = 0, count = ira->codegen->errors_by_index.length; i < count; i += 1) {
+ assert(errors[i] == nullptr);
+ }
+ for (uint32_t i = 0; i < cur_err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *error_entry = cur_err_set_type->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ bool cur_is_superset = true;
+ for (uint32_t i = 0; i < prev_err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *contained_error_entry = prev_err_set_type->data.error_set.errors[i];
+ ErrorTableEntry *error_entry = errors[contained_error_entry->value];
+ if (error_entry == nullptr) {
+ cur_is_superset = false;
+ break;
+ }
+ }
+ if (cur_is_superset) {
+ err_set_type = cur_err_set_type;
+ continue;
+ }
+
+ err_set_type = get_error_set_union(ira->codegen, errors, cur_err_set_type, prev_err_set_type);
+ continue;
+ }
}
- if (types_match_const_cast_only(prev_type, cur_type)) {
+ if (types_match_const_cast_only(ira, prev_type, cur_type, source_node).id == ConstCastResultIdOk) {
continue;
}
- if (types_match_const_cast_only(cur_type, prev_type)) {
+ if (types_match_const_cast_only(ira, cur_type, prev_type, source_node).id == ConstCastResultIdOk) {
prev_inst = cur_inst;
continue;
}
@@ -6588,26 +7379,41 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
}
if (prev_type->id == TypeTableEntryIdErrorUnion &&
- types_match_const_cast_only(prev_type->data.error.child_type, cur_type))
+ types_match_const_cast_only(ira, prev_type->data.error_union.payload_type, cur_type, source_node).id == ConstCastResultIdOk)
{
continue;
}
if (cur_type->id == TypeTableEntryIdErrorUnion &&
- types_match_const_cast_only(cur_type->data.error.child_type, prev_type))
+ types_match_const_cast_only(ira, cur_type->data.error_union.payload_type, prev_type, source_node).id == ConstCastResultIdOk)
{
+ if (err_set_type != nullptr) {
+ TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
+ if (!resolve_inferred_error_set(ira, cur_err_set_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (type_is_global_error_set(cur_err_set_type) || type_is_global_error_set(err_set_type)) {
+ err_set_type = ira->codegen->builtin_types.entry_global_error_set;
+ prev_inst = cur_inst;
+ continue;
+ }
+
+ update_errors_helper(ira->codegen, &errors, &errors_count);
+
+ err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_err_set_type);
+ }
prev_inst = cur_inst;
continue;
}
if (prev_type->id == TypeTableEntryIdMaybe &&
- types_match_const_cast_only(prev_type->data.maybe.child_type, cur_type))
+ types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, source_node).id == ConstCastResultIdOk)
{
continue;
}
if (cur_type->id == TypeTableEntryIdMaybe &&
- types_match_const_cast_only(cur_type->data.maybe.child_type, prev_type))
+ types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, source_node).id == ConstCastResultIdOk)
{
prev_inst = cur_inst;
continue;
@@ -6645,7 +7451,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
cur_type->data.array.len != prev_type->data.array.len &&
- types_match_const_cast_only(cur_type->data.array.child_type, prev_type->data.array.child_type))
+ types_match_const_cast_only(ira, cur_type->data.array.child_type, prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
convert_to_const_slice = true;
prev_inst = cur_inst;
@@ -6654,7 +7460,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
if (cur_type->id == TypeTableEntryIdArray && prev_type->id == TypeTableEntryIdArray &&
cur_type->data.array.len != prev_type->data.array.len &&
- types_match_const_cast_only(prev_type->data.array.child_type, cur_type->data.array.child_type))
+ types_match_const_cast_only(ira, prev_type->data.array.child_type, cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
convert_to_const_slice = true;
continue;
@@ -6663,8 +7469,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
if (cur_type->id == TypeTableEntryIdArray && is_slice(prev_type) &&
(prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
cur_type->data.array.len == 0) &&
- types_match_const_cast_only(prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
- cur_type->data.array.child_type))
+ types_match_const_cast_only(ira, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
+ cur_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
convert_to_const_slice = false;
continue;
@@ -6673,8 +7479,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
if (prev_type->id == TypeTableEntryIdArray && is_slice(cur_type) &&
(cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const ||
prev_type->data.array.len == 0) &&
- types_match_const_cast_only(cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
- prev_type->data.array.child_type))
+ types_match_const_cast_only(ira, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
+ prev_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
prev_inst = cur_inst;
convert_to_const_slice = false;
@@ -6714,30 +7520,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
return ira->codegen->builtin_types.entry_invalid;
}
+
+ free(errors);
+
if (convert_to_const_slice) {
assert(prev_inst->value.type->id == TypeTableEntryIdArray);
TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, prev_inst->value.type->data.array.child_type, true);
TypeTableEntry *slice_type = get_slice_type(ira->codegen, ptr_type);
- if (any_are_pure_error) {
- return get_error_type(ira->codegen, slice_type);
+ if (err_set_type != nullptr) {
+ return get_error_union_type(ira->codegen, err_set_type, slice_type);
} else {
return slice_type;
}
- } else if (any_are_pure_error && prev_inst->value.type->id != TypeTableEntryIdPureError) {
- 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_type(ira->codegen, 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 get_error_union_type(ira->codegen, err_set_type, prev_inst->value.type->data.error_union.payload_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 ||
@@ -6783,6 +7596,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
switch (cast_op) {
case CastOpNoCast:
zig_unreachable();
+ case CastOpErrSet:
+ zig_panic("TODO");
case CastOpNoop:
{
copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic);
@@ -7213,7 +8028,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
assert(wanted_type->id == TypeTableEntryIdErrorUnion);
if (instr_is_comptime(value)) {
- TypeTableEntry *payload_type = wanted_type->data.error.child_type;
+ TypeTableEntry *payload_type = wanted_type->data.error_union.payload_type;
IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);
if (type_is_invalid(casted_payload->value.type))
return ira->codegen->invalid_instruction;
@@ -7238,19 +8053,64 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
return result;
}
-static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ TypeTableEntry *wanted_type)
+{
+ assert(value->value.type->id == TypeTableEntryIdErrorSet);
+ assert(wanted_type->id == TypeTableEntryIdErrorSet);
if (instr_is_comptime(value)) {
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
+ if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
+ return ira->codegen->invalid_instruction;
+ }
+ if (!type_is_global_error_set(wanted_type)) {
+ bool subset = false;
+ for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) {
+ if (wanted_type->data.error_set.errors[i]->value == val->data.x_err_set->value) {
+ subset = true;
+ break;
+ }
+ }
+ if (!subset) {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("error.%s not a member of error set '%s'",
+ buf_ptr(&val->data.x_err_set->name), buf_ptr(&wanted_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ const_instruction->base.value.type = wanted_type;
+ const_instruction->base.value.special = ConstValSpecialStatic;
+ const_instruction->base.value.data.x_err_set = val->data.x_err_set;
+ return &const_instruction->base;
+ }
+
+ IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, CastOpErrSet);
+ result->value.type = wanted_type;
+ return result;
+}
+
+static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type);
+
+ if (instr_is_comptime(casted_value)) {
+ ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = val->data.x_pure_err;
+ const_instruction->base.value.data.x_err_union.err = val->data.x_err_set;
const_instruction->base.value.data.x_err_union.payload = nullptr;
return &const_instruction->base;
}
@@ -7630,9 +8490,12 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
return result;
}
-static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
+static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
+ TypeTableEntry *wanted_type)
+{
assert(target->value.type->id == TypeTableEntryIdInt);
assert(!target->value.type->data.integral.is_signed);
+ assert(wanted_type->id == TypeTableEntryIdErrorSet);
if (instr_is_comptime(target)) {
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
@@ -7640,10 +8503,10 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
return ira->codegen->invalid_instruction;
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_pure_error);
+ source_instr->source_node, wanted_type);
BigInt err_count;
- bigint_init_unsigned(&err_count, ira->codegen->error_decls.length);
+ bigint_init_unsigned(&err_count, ira->codegen->errors_by_index.length);
if (bigint_cmp_zero(&val->data.x_bigint) == CmpEQ || bigint_cmp(&val->data.x_bigint, &err_count) != CmpLT) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
@@ -7653,13 +8516,12 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
}
size_t index = bigint_as_unsigned(&val->data.x_bigint);
- AstNode *error_decl_node = ira->codegen->error_decls.at(index);
- result->value.data.x_pure_err = error_decl_node->data.error_value_decl.err;
+ result->value.data.x_err_set = ira->codegen->errors_by_index.at(index);
return result;
}
IrInstruction *result = ir_build_int_to_err(&ira->new_irb, source_instr->scope, source_instr->source_node, target);
- result->value.type = ira->codegen->builtin_types.entry_pure_error;
+ result->value.type = wanted_type;
return result;
}
@@ -7681,8 +8543,8 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
ErrorTableEntry *err;
if (err_type->id == TypeTableEntryIdErrorUnion) {
err = val->data.x_err_union.err;
- } else if (err_type->id == TypeTableEntryIdPureError) {
- err = val->data.x_pure_err;
+ } else if (err_type->id == TypeTableEntryIdErrorSet) {
+ err = val->data.x_err_set;
} else {
zig_unreachable();
}
@@ -7702,8 +8564,36 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
return result;
}
+ TypeTableEntry *err_set_type;
+ if (err_type->id == TypeTableEntryIdErrorUnion) {
+ err_set_type = err_type->data.error_union.err_set_type;
+ } else if (err_type->id == TypeTableEntryIdErrorSet) {
+ err_set_type = err_type;
+ } else {
+ zig_unreachable();
+ }
+ if (!type_is_global_error_set(err_set_type)) {
+ if (!resolve_inferred_error_set(ira, err_set_type, source_instr->source_node)) {
+ return ira->codegen->invalid_instruction;
+ }
+ if (err_set_type->data.error_set.err_count == 0) {
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, wanted_type);
+ result->value.type = wanted_type;
+ bigint_init_unsigned(&result->value.data.x_bigint, 0);
+ return result;
+ } else if (err_set_type->data.error_set.err_count == 1) {
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, wanted_type);
+ result->value.type = wanted_type;
+ ErrorTableEntry *err = err_set_type->data.error_set.errors[0];
+ bigint_init_unsigned(&result->value.data.x_bigint, err->value);
+ return result;
+ }
+ }
+
BigInt bn;
- bigint_init_unsigned(&bn, ira->codegen->error_decls.length);
+ bigint_init_unsigned(&bn, ira->codegen->errors_by_index.length);
if (!bigint_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) {
ir_add_error_node(ira, source_instr->source_node,
buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
@@ -7719,6 +8609,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
TypeTableEntry *wanted_type, IrInstruction *value)
{
TypeTableEntry *actual_type = value->value.type;
+ AstNode *source_node = source_instr->source_node;
if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
return ira->codegen->invalid_instruction;
@@ -7728,7 +8619,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return value;
// explicit match or non-const to const
- if (types_match_const_cast_only(wanted_type, actual_type)) {
+ if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node).id == ConstCastResultIdOk) {
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
}
@@ -7748,6 +8639,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
}
+ // explicit error set cast
+ if (wanted_type->id == TypeTableEntryIdErrorSet &&
+ actual_type->id == TypeTableEntryIdErrorSet)
+ {
+ return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type);
+ }
+
// explicit cast from int to float
if (wanted_type->id == TypeTableEntryIdFloat &&
actual_type->id == TypeTableEntryIdInt)
@@ -7767,7 +8665,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
}
@@ -7785,7 +8683,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
TypeTableEntry *array_type = actual_type->data.pointer.child_type;
if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
}
@@ -7801,7 +8699,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
if (type_is_invalid(cast1->value.type))
@@ -7824,7 +8722,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
if (type_is_invalid(cast1->value.type))
@@ -7886,7 +8784,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit cast from child type of maybe type to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe) {
- if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
+ if (types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node).id == ConstCastResultIdOk) {
return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
@@ -7908,12 +8806,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit cast from child type of error type to error type
if (wanted_type->id == TypeTableEntryIdErrorUnion) {
- if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
+ if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node).id == ConstCastResultIdOk) {
return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
- if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type, true)) {
+ if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) {
return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
@@ -7923,16 +8821,16 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit cast from [N]T to %[]const T
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
- is_slice(wanted_type->data.error.child_type) &&
+ is_slice(wanted_type->data.error_union.payload_type) &&
actual_type->id == TypeTableEntryIdArray)
{
TypeTableEntry *ptr_type =
- wanted_type->data.error.child_type->data.structure.fields[slice_ptr_index].type_entry;
+ wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == TypeTableEntryIdPointer);
if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
- types_match_const_cast_only(ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
{
- IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value);
+ IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
@@ -7944,25 +8842,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // explicit cast from pure error to error union type
+ // explicit cast from error set to error union type
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
- actual_type->id == TypeTableEntryIdPureError)
+ actual_type->id == TypeTableEntryIdErrorSet)
{
return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
}
// explicit cast from T to %?T
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
- wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe &&
+ wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe &&
actual_type->id != TypeTableEntryIdMaybe)
{
- TypeTableEntry *wanted_child_type = wanted_type->data.error.child_type->data.maybe.child_type;
- if (types_match_const_cast_only(wanted_child_type, actual_type) ||
+ TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
+ if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk ||
actual_type->id == TypeTableEntryIdNullLit ||
actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
- IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value);
+ IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
@@ -8031,21 +8929,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
}
- // explicit cast from %void to integer type which can fit it
+ // explicit cast from T!void to integer type which can fit it
bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
- !type_has_bits(actual_type->data.error.child_type);
- bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
- if ((actual_type_is_void_err || actual_type_is_pure_err) &&
- wanted_type->id == TypeTableEntryIdInt)
- {
+ !type_has_bits(actual_type->data.error_union.payload_type);
+ bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet;
+ if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) {
return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
}
- // explicit cast from integer to pure error
- if (wanted_type->id == TypeTableEntryIdPureError && actual_type->id == TypeTableEntryIdInt &&
+ // explicit cast from integer to error set
+ if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt &&
!actual_type->data.integral.is_signed)
{
- return ir_analyze_int_to_err(ira, source_instr, value);
+ return ir_analyze_int_to_err(ira, source_instr, value, wanted_type);
}
// explicit cast from integer to enum type with no payload
@@ -8109,7 +9005,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit cast from something to const pointer of it
if (!type_requires_comptime(actual_type)) {
TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
- if (types_match_const_cast_only(wanted_type, const_ptr_actual)) {
+ if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node).id == ConstCastResultIdOk) {
return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
}
}
@@ -8471,6 +9367,7 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
IrInstruction *op1 = bin_op_instruction->op1->other;
IrInstruction *op2 = bin_op_instruction->op2->other;
+ AstNode *source_node = bin_op_instruction->base.source_node;
IrBinOp op_id = bin_op_instruction->op_id;
bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq);
@@ -8503,7 +9400,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
}
IrInstruction *is_non_null = ir_build_test_nonnull(&ira->new_irb, bin_op_instruction->base.scope,
- bin_op_instruction->base.source_node, maybe_op);
+ source_node, maybe_op);
is_non_null->value.type = ira->codegen->builtin_types.entry_bool;
if (op_id == IrBinOpCmpEq) {
@@ -8514,8 +9411,88 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
return ira->codegen->builtin_types.entry_bool;
}
+ if (op1->value.type->id == TypeTableEntryIdErrorSet && op2->value.type->id == TypeTableEntryIdErrorSet) {
+ if (!is_equality_cmp) {
+ ir_add_error_node(ira, source_node, buf_sprintf("operator not allowed for errors"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeTableEntry *intersect_type = get_error_set_intersection(ira, op1->value.type, op2->value.type, source_node);
+ if (type_is_invalid(intersect_type)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (!resolve_inferred_error_set(ira, intersect_type, source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ // exception if one of the operators has the type of the empty error set, we allow the comparison
+ // (and make it comptime known)
+ // this is a function which is evaluated at comptime and returns an inferred error set will have an empty
+ // error set.
+ if (op1->value.type->data.error_set.err_count == 0 || op2->value.type->data.error_set.err_count == 0) {
+ bool are_equal = false;
+ bool answer;
+ if (op_id == IrBinOpCmpEq) {
+ answer = are_equal;
+ } else if (op_id == IrBinOpCmpNotEq) {
+ answer = !are_equal;
+ } else {
+ zig_unreachable();
+ }
+ ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
+ out_val->data.x_bool = answer;
+ return ira->codegen->builtin_types.entry_bool;
+ }
+
+ if (!type_is_global_error_set(intersect_type)) {
+ if (intersect_type->data.error_set.err_count == 0) {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("error sets '%s' and '%s' have no common errors",
+ buf_ptr(&op1->value.type->name), buf_ptr(&op2->value.type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (op1->value.type->data.error_set.err_count == 1 && op2->value.type->data.error_set.err_count == 1) {
+ bool are_equal = true;
+ bool answer;
+ if (op_id == IrBinOpCmpEq) {
+ answer = are_equal;
+ } else if (op_id == IrBinOpCmpNotEq) {
+ answer = !are_equal;
+ } else {
+ zig_unreachable();
+ }
+ ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
+ out_val->data.x_bool = answer;
+ return ira->codegen->builtin_types.entry_bool;
+ }
+ }
+
+ ConstExprValue *op1_val = &op1->value;
+ ConstExprValue *op2_val = &op2->value;
+ if (value_is_comptime(op1_val) && value_is_comptime(op2_val)) {
+ bool answer;
+ bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value;
+ if (op_id == IrBinOpCmpEq) {
+ answer = are_equal;
+ } else if (op_id == IrBinOpCmpNotEq) {
+ answer = !are_equal;
+ } else {
+ zig_unreachable();
+ }
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
+ out_val->data.x_bool = answer;
+ return ira->codegen->builtin_types.entry_bool;
+ }
+
+ ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id,
+ op1, op2, bin_op_instruction->safety_check_on);
+
+ return ira->codegen->builtin_types.entry_bool;
+ }
+
IrInstruction *instructions[] = {op1, op2};
- TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, bin_op_instruction->base.source_node, instructions, 2);
+ TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, instructions, 2);
if (type_is_invalid(resolved_type))
return resolved_type;
type_ensure_zero_bits_known(ira->codegen, resolved_type);
@@ -8523,7 +9500,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
return resolved_type;
- AstNode *source_node = bin_op_instruction->base.source_node;
switch (resolved_type->id) {
case TypeTableEntryIdInvalid:
zig_unreachable(); // handled above
@@ -8538,7 +9514,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
case TypeTableEntryIdPointer:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
case TypeTableEntryIdOpaque:
case TypeTableEntryIdNamespace:
@@ -8692,6 +9668,7 @@ static int ir_eval_math_op(TypeTableEntry *type_entry, ConstExprValue *op1_val,
case IrBinOpArrayCat:
case IrBinOpArrayMult:
case IrBinOpRemUnspecified:
+ case IrBinOpMergeErrorSets:
zig_unreachable();
case IrBinOpBinOr:
assert(is_int);
@@ -9264,6 +10241,46 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
return get_array_type(ira->codegen, child_type, new_array_len);
}
+static TypeTableEntry *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) {
+ TypeTableEntry *op1_type = ir_resolve_type(ira, instruction->op1->other);
+ if (type_is_invalid(op1_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *op2_type = ir_resolve_type(ira, instruction->op2->other);
+ if (type_is_invalid(op2_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (type_is_global_error_set(op1_type) ||
+ type_is_global_error_set(op2_type))
+ {
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = ira->codegen->builtin_types.entry_global_error_set;
+ return ira->codegen->builtin_types.entry_type;
+ }
+
+ if (!resolve_inferred_error_set(ira, op1_type, instruction->op1->other->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (!resolve_inferred_error_set(ira, op2_type, instruction->op2->other->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
+ for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) {
+ ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];
+ assert(errors[error_entry->value] == nullptr);
+ errors[error_entry->value] = error_entry;
+ }
+ TypeTableEntry *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type);
+ free(errors);
+
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = result_type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
IrBinOp op_id = bin_op_instruction->op_id;
switch (op_id) {
@@ -9305,6 +10322,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
return ir_analyze_array_cat(ira, bin_op_instruction);
case IrBinOpArrayMult:
return ir_analyze_array_mult(ira, bin_op_instruction);
+ case IrBinOpMergeErrorSets:
+ return ir_analyze_merge_error_sets(ira, bin_op_instruction);
}
zig_unreachable();
}
@@ -9326,7 +10345,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdVoid:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdFn:
return VarClassRequiredAny;
case TypeTableEntryIdNumLitFloat:
@@ -9352,7 +10371,7 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
case TypeTableEntryIdMaybe:
return get_var_class_required(type_entry->data.maybe.child_type);
case TypeTableEntryIdErrorUnion:
- return get_var_class_required(type_entry->data.error.child_type);
+ return get_var_class_required(type_entry->data.error_union.payload_type);
case TypeTableEntryIdStruct:
case TypeTableEntryIdEnum:
@@ -9587,7 +10606,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -9610,7 +10629,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name));
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -9644,6 +10663,31 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
return nullable_type;
}
+static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
+ IrInstructionErrorUnion *instruction)
+{
+ TypeTableEntry *err_set_type = ir_resolve_type(ira, instruction->err_set->other);
+ if (type_is_invalid(err_set_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *payload_type = ir_resolve_type(ira, instruction->payload->other);
+ if (type_is_invalid(payload_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (err_set_type->id != TypeTableEntryIdErrorSet) {
+ ir_add_error(ira, instruction->err_set->other,
+ buf_sprintf("expected error set type, found type '%s'",
+ buf_ptr(&err_set_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ TypeTableEntry *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type);
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = result_type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
{
@@ -9926,9 +10970,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
}
AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
- TypeTableEntry *return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
- if (type_is_invalid(return_type))
+ TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, exec_scope, return_type_node);
+ if (type_is_invalid(specified_return_type))
return ira->codegen->builtin_types.entry_invalid;
+ TypeTableEntry *return_type;
+ TypeTableEntry *inferred_err_set_type = nullptr;
+ if (fn_proto_node->data.fn_proto.auto_err_set) {
+ inferred_err_set_type = get_auto_err_set_type(ira->codegen, fn_entry);
+ return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
+ } else {
+ return_type = specified_return_type;
+ }
IrInstruction *result;
@@ -9942,6 +10994,23 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);
+ if (inferred_err_set_type != nullptr) {
+ inferred_err_set_type->data.error_set.infer_fn = nullptr;
+ if (result->value.type->id == TypeTableEntryIdErrorUnion) {
+ if (result->value.data.x_err_union.err != nullptr) {
+ inferred_err_set_type->data.error_set.err_count = 1;
+ inferred_err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(1);
+ inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err;
+ }
+ TypeTableEntry *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
+ inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
+ inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors;
+ } else if (result->value.type->id == TypeTableEntryIdErrorSet) {
+ inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count;
+ inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors;
+ }
+ }
+
ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
if (type_is_invalid(result->value.type))
@@ -10092,12 +11161,17 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
{
AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
- TypeTableEntry *return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
- if (type_is_invalid(return_type))
+ TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
+ if (type_is_invalid(specified_return_type))
return ira->codegen->builtin_types.entry_invalid;
- inst_fn_type_id.return_type = return_type;
+ if (fn_proto_node->data.fn_proto.auto_err_set) {
+ TypeTableEntry *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);
+ inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
+ } else {
+ inst_fn_type_id.return_type = specified_return_type;
+ }
- if (type_requires_comptime(return_type)) {
+ if (type_requires_comptime(specified_return_type)) {
// Throw out our work and call the function as if it were comptime.
return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, true, FnInlineAuto);
}
@@ -10128,7 +11202,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
ir_add_alloca(ira, new_call_instruction, return_type);
- if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
+ if (return_type->id == TypeTableEntryIdErrorSet || return_type->id == TypeTableEntryIdErrorUnion) {
parent_fn_entry->calls_errorable_function = true;
}
@@ -10138,7 +11212,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
assert(fn_type_id->return_type != nullptr);
assert(parent_fn_entry != nullptr);
- if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
+ if (fn_type_id->return_type->id == TypeTableEntryIdErrorSet || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
parent_fn_entry->calls_errorable_function = true;
}
@@ -10257,58 +11331,6 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
}
}
-static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
- assert(un_op_instruction->op_id == IrUnOpError);
- IrInstruction *value = un_op_instruction->value->other;
-
- TypeTableEntry *meta_type = ir_resolve_type(ira, value);
- if (type_is_invalid(meta_type))
- return ira->codegen->builtin_types.entry_invalid;
-
-
- switch (meta_type->id) {
- case TypeTableEntryIdInvalid: // handled above
- zig_unreachable();
-
- case TypeTableEntryIdVoid:
- case TypeTableEntryIdBool:
- case TypeTableEntryIdInt:
- case TypeTableEntryIdFloat:
- case TypeTableEntryIdPointer:
- case TypeTableEntryIdArray:
- case TypeTableEntryIdStruct:
- case TypeTableEntryIdMaybe:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnum:
- case TypeTableEntryIdUnion:
- case TypeTableEntryIdFn:
- case TypeTableEntryIdBoundFn:
- {
- ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
- TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type);
- out_val->data.x_type = result_type;
- return ira->codegen->builtin_types.entry_type;
- }
- case TypeTableEntryIdMetaType:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdNullLit:
- case TypeTableEntryIdNamespace:
- case TypeTableEntryIdBlock:
- case TypeTableEntryIdUnreachable:
- case TypeTableEntryIdVar:
- case TypeTableEntryIdArgTuple:
- case TypeTableEntryIdOpaque:
- ir_add_error_node(ira, un_op_instruction->base.source_node,
- buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));
- return ira->codegen->builtin_types.entry_invalid;
- }
- zig_unreachable();
-}
-
-
static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
IrInstruction *value = un_op_instruction->value->other;
@@ -10364,7 +11386,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -10474,8 +11496,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
return ir_analyze_dereference(ira, un_op_instruction);
case IrUnOpMaybe:
return ir_analyze_maybe(ira, un_op_instruction);
- case IrUnOpError:
- return ir_analyze_unary_prefix_op_err(ira, un_op_instruction);
}
zig_unreachable();
}
@@ -10633,6 +11653,9 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
IrInstruction *branch_instruction = predecessor->instruction_list.pop();
ir_set_cursor_at_end(&ira->new_irb, predecessor);
IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type);
+ if (casted_value == ira->codegen->invalid_instruction) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
new_incoming_values.items[i] = casted_value;
predecessor->instruction_list.append(branch_instruction);
@@ -11048,6 +12071,25 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
}
}
+static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) {
+ LinkLib *link_lib = add_link_lib(ira->codegen, lib_name);
+ for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
+ Buf *existing_symbol_name = link_lib->symbols.at(i);
+ if (buf_eql_buf(existing_symbol_name, symbol_name)) {
+ return;
+ }
+ }
+ for (size_t i = 0; i < ira->codegen->forbidden_libs.length; i += 1) {
+ Buf *forbidden_lib_name = ira->codegen->forbidden_libs.at(i);
+ if (buf_eql_buf(lib_name, forbidden_lib_name)) {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("linking against forbidden library '%s'", buf_ptr(symbol_name)));
+ }
+ }
+ link_lib->symbols.append(symbol_name);
+}
+
+
static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) {
bool pointer_only = false;
resolve_top_level_decl(ira->codegen, tld, pointer_only, source_instruction->source_node);
@@ -11063,7 +12105,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
TldVar *tld_var = (TldVar *)tld;
VariableTableEntry *var = tld_var->var;
if (tld_var->extern_lib_name != nullptr) {
- add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);
+ add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node);
}
return ir_analyze_var_ptr(ira, source_instruction, var, false, false);
@@ -11085,7 +12127,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
const_val->data.x_fn.fn_entry = fn_entry;
if (tld_fn->extern_lib_name != nullptr) {
- add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);
+ add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_instruction->source_node);
}
bool ptr_is_const = true;
@@ -11097,6 +12139,17 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
zig_unreachable();
}
+static ErrorTableEntry *find_err_table_entry(TypeTableEntry *err_set_type, Buf *field_name) {
+ assert(err_set_type->id == TypeTableEntryIdErrorSet);
+ for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *err_table_entry = err_set_type->data.error_set.errors[i];
+ if (buf_eql_buf(&err_table_entry->name, field_name)) {
+ return err_table_entry;
+ }
+ }
+ return nullptr;
+}
+
static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) {
IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other;
if (type_is_invalid(container_ptr->value.type))
@@ -11238,23 +12291,52 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
buf_sprintf("container '%s' has no member called '%s'",
buf_ptr(&child_type->name), buf_ptr(field_name)));
return ira->codegen->builtin_types.entry_invalid;
- } else if (child_type->id == TypeTableEntryIdPureError) {
- auto err_table_entry = ira->codegen->error_table.maybe_get(field_name);
- if (err_table_entry) {
- ConstExprValue *const_val = create_const_vals(1);
- const_val->special = ConstValSpecialStatic;
- const_val->type = child_type;
- const_val->data.x_pure_err = err_table_entry->value;
-
- bool ptr_is_const = true;
- bool ptr_is_volatile = false;
- return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
- child_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else if (child_type->id == TypeTableEntryIdErrorSet) {
+ ErrorTableEntry *err_entry;
+ TypeTableEntry *err_set_type;
+ if (type_is_global_error_set(child_type)) {
+ auto existing_entry = ira->codegen->error_table.maybe_get(field_name);
+ if (existing_entry) {
+ err_entry = existing_entry->value;
+ } else {
+ err_entry = allocate<ErrorTableEntry>(1);
+ err_entry->decl_node = field_ptr_instruction->base.source_node;
+ buf_init_from_buf(&err_entry->name, field_name);
+ size_t error_value_count = ira->codegen->errors_by_index.length;
+ assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
+ err_entry->value = error_value_count;
+ ira->codegen->errors_by_index.append(err_entry);
+ ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder,
+ buf_ptr(field_name), error_value_count));
+ ira->codegen->error_table.put(field_name, err_entry);
+ }
+ if (err_entry->set_with_only_this_in_it == nullptr) {
+ err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen,
+ field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node,
+ err_entry);
+ }
+ err_set_type = err_entry->set_with_only_this_in_it;
+ } else {
+ if (!resolve_inferred_error_set(ira, child_type, field_ptr_instruction->base.source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ err_entry = find_err_table_entry(child_type, field_name);
+ if (err_entry == nullptr) {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ err_set_type = child_type;
}
+ ConstExprValue *const_val = create_const_vals(1);
+ const_val->special = ConstValSpecialStatic;
+ const_val->type = err_set_type;
+ const_val->data.x_err_set = err_entry;
- ir_add_error(ira, &field_ptr_instruction->base,
- buf_sprintf("use of undeclared error value '%s'", buf_ptr(field_name)));
- return ira->codegen->builtin_types.entry_invalid;
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val,
+ err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
} else if (child_type->id == TypeTableEntryIdInt) {
if (buf_eql_str(field_name, "bit_count")) {
bool ptr_is_const = true;
@@ -11337,11 +12419,18 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
return ira->codegen->builtin_types.entry_invalid;
}
} else if (child_type->id == TypeTableEntryIdErrorUnion) {
- if (buf_eql_str(field_name, "Child")) {
+ if (buf_eql_str(field_name, "Payload")) {
bool ptr_is_const = true;
bool ptr_is_volatile = false;
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
- create_const_type(ira->codegen, child_type->data.error.child_type),
+ create_const_type(ira->codegen, child_type->data.error_union.payload_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else if (buf_eql_str(field_name, "ErrorSet")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.error_union.err_set_type),
ira->codegen->builtin_types.entry_type,
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
} else {
@@ -11528,7 +12617,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -11795,7 +12884,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -11903,7 +12992,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -11956,7 +13045,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -12291,7 +13380,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case TypeTableEntryIdPointer:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
if (pointee_val) {
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
copy_const_val(out_val, pointee_val, true);
@@ -12361,8 +13450,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return target_type;
}
case TypeTableEntryIdErrorUnion:
- // see https://github.com/andrewrk/zig/issues/632
- zig_panic("TODO switch on error union");
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
@@ -12887,7 +13974,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
@@ -12975,7 +14062,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
TypeTableEntry *str_type = get_slice_type(ira->codegen, u8_ptr_type);
if (casted_value->value.special == ConstValSpecialStatic) {
- ErrorTableEntry *err = casted_value->value.data.x_pure_err;
+ ErrorTableEntry *err = casted_value->value.data.x_err_set;
if (!err->cached_error_name_val) {
ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name);
err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true);
@@ -13956,6 +15043,15 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
result = container_type->data.structure.src_field_count;
} else if (container_type->id == TypeTableEntryIdUnion) {
result = container_type->data.unionation.src_field_count;
+ } else if (container_type->id == TypeTableEntryIdErrorSet) {
+ if (!resolve_inferred_error_set(ira, container_type, instruction->base.source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (type_is_global_error_set(container_type)) {
+ ir_add_error(ira, &instruction->base, buf_sprintf("global error set member count not available at comptime"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ result = container_type->data.error_set.err_count;
} else {
ir_add_error(ira, &instruction->base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name)));
return ira->codegen->builtin_types.entry_invalid;
@@ -14120,7 +15216,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
@@ -14251,9 +15347,22 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
}
}
+ TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
+ if (!resolve_inferred_error_set(ira, err_set_type, instruction->base.source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ if (!type_is_global_error_set(err_set_type) &&
+ err_set_type->data.error_set.err_count == 0)
+ {
+ assert(err_set_type->data.error_set.infer_fn == nullptr);
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_bool = false;
+ return ira->codegen->builtin_types.entry_bool;
+ }
+
ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
return ira->codegen->builtin_types.entry_bool;
- } else if (type_entry->id == TypeTableEntryIdPureError) {
+ } else if (type_entry->id == TypeTableEntryIdErrorSet) {
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_bool = true;
return ira->codegen->builtin_types.entry_bool;
@@ -14289,13 +15398,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
assert(err);
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- out_val->data.x_pure_err = err;
- return ira->codegen->builtin_types.entry_pure_error;
+ out_val->data.x_err_set = err;
+ return type_entry->data.error_union.err_set_type;
}
}
ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value);
- return ira->codegen->builtin_types.entry_pure_error;
+ return type_entry->data.error_union.err_set_type;
} else {
ir_add_error(ira, value,
buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
@@ -14319,10 +15428,10 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
if (type_is_invalid(type_entry)) {
return ira->codegen->builtin_types.entry_invalid;
} else if (type_entry->id == TypeTableEntryIdErrorUnion) {
- TypeTableEntry *child_type = type_entry->data.error.child_type;
- TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
+ TypeTableEntry *payload_type = type_entry->data.error_union.payload_type;
+ TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- get_abi_alignment(ira->codegen, child_type), 0, 0);
+ get_abi_alignment(ira->codegen, payload_type), 0, 0);
if (instr_is_comptime(value)) {
ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
if (!ptr_val)
@@ -14332,7 +15441,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
ErrorTableEntry *err = err_union_val->data.x_err_union.err;
if (err != nullptr) {
ir_add_error(ira, &instruction->base,
- buf_sprintf("unable to unwrap error '%s'", buf_ptr(&err->name)));
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
return ira->codegen->builtin_types.entry_invalid;
}
@@ -14357,6 +15466,12 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
AstNode *proto_node = instruction->base.source_node;
assert(proto_node->type == NodeTypeFnProto);
+ if (proto_node->data.fn_proto.auto_err_set) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("inferring error set of return type valid only for function definitions"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
FnTypeId fn_type_id = {0};
init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length);
@@ -14482,6 +15597,57 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
}
}
}
+ } else if (switch_type->id == TypeTableEntryIdErrorSet) {
+ if (!resolve_inferred_error_set(ira, switch_type, target_value->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length);
+
+ for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
+ IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
+
+ IrInstruction *start_value = range->start->other;
+ if (type_is_invalid(start_value->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *end_value = range->end->other;
+ if (type_is_invalid(end_value->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ assert(start_value->value.type->id == TypeTableEntryIdErrorSet);
+ uint32_t start_index = start_value->value.data.x_err_set->value;
+
+ assert(end_value->value.type->id == TypeTableEntryIdErrorSet);
+ uint32_t end_index = end_value->value.data.x_err_set->value;
+
+ if (start_index != end_index) {
+ ir_add_error(ira, end_value, buf_sprintf("ranges not allowed when switching on errors"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ AstNode *prev_node = field_prev_uses[start_index];
+ if (prev_node != nullptr) {
+ Buf *err_name = &ira->codegen->errors_by_index.at(start_index)->name;
+ ErrorMsg *msg = ir_add_error(ira, start_value,
+ buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), buf_ptr(err_name)));
+ add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
+ }
+ field_prev_uses[start_index] = start_value->source_node;
+ }
+ if (!instruction->have_else_prong) {
+ for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) {
+ ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i];
+
+ AstNode *prev_node = field_prev_uses[err_entry->value];
+ if (prev_node == nullptr) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name)));
+ }
+ }
+ }
+
+ free(field_prev_uses);
} else if (switch_type->id == TypeTableEntryIdInt) {
RangeSet rs = {0};
for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
@@ -14774,7 +15940,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_panic("TODO buf_write_value_bytes maybe type");
case TypeTableEntryIdErrorUnion:
zig_panic("TODO buf_write_value_bytes error union");
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
zig_panic("TODO buf_write_value_bytes pure error type");
case TypeTableEntryIdEnum:
zig_panic("TODO buf_write_value_bytes enum type");
@@ -14832,7 +15998,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_panic("TODO buf_read_value_bytes maybe type");
case TypeTableEntryIdErrorUnion:
zig_panic("TODO buf_read_value_bytes error union");
- case TypeTableEntryIdPureError:
+ case TypeTableEntryIdErrorSet:
zig_panic("TODO buf_read_value_bytes pure error type");
case TypeTableEntryIdEnum:
zig_panic("TODO buf_read_value_bytes enum type");
@@ -15010,7 +16176,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_invalid;
if (tld_var->extern_lib_name != nullptr) {
- add_link_lib_symbol(ira->codegen, tld_var->extern_lib_name, &var->name);
+ add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node);
}
if (lval.is_ptr) {
@@ -15029,7 +16195,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
assert(fn_entry->type_entry);
if (tld_fn->extern_lib_name != nullptr) {
- add_link_lib_symbol(ira->codegen, tld_fn->extern_lib_name, &fn_entry->symbol_name);
+ add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node);
}
IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
@@ -15443,6 +16609,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
case IrInstructionIdErrorReturnTrace:
return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
+ case IrInstructionIdErrorUnion:
+ return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
}
zig_unreachable();
}
@@ -15628,6 +16796,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdArgType:
case IrInstructionIdTagType:
case IrInstructionIdErrorReturnTrace:
+ case IrInstructionIdErrorUnion:
return false;
case IrInstructionIdAsm:
{
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 8332212d34..f2c0d6a5b4 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -130,6 +130,8 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
return "++";
case IrBinOpArrayMult:
return "**";
+ case IrBinOpMergeErrorSets:
+ return "||";
}
zig_unreachable();
}
@@ -148,8 +150,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
return "*";
case IrUnOpMaybe:
return "?";
- case IrUnOpError:
- return "%";
}
zig_unreachable();
}
@@ -1004,6 +1004,11 @@ static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTr
fprintf(irp->f, "@errorReturnTrace()");
}
+static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
+ ir_print_other_instruction(irp, instruction->err_set);
+ fprintf(irp->f, "!");
+ ir_print_other_instruction(irp, instruction->payload);
+}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
@@ -1322,6 +1327,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdErrorReturnTrace:
ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
break;
+ case IrInstructionIdErrorUnion:
+ ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
diff --git a/src/main.cpp b/src/main.cpp
index 3df16e62b8..eab7f29b10 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -66,6 +66,7 @@ static int usage(const char *arg0) {
" --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"
" --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"
" --library [lib] link against lib\n"
+ " --forbid-library [lib] make it an error to link against lib\n"
" --library-path [dir] add a directory to the library search path\n"
" --linker-script [path] use a custom linker script\n"
" --object [obj] add object file to build\n"
@@ -309,6 +310,7 @@ int main(int argc, char **argv) {
ZigList<const char *> llvm_argv = {0};
ZigList<const char *> lib_dirs = {0};
ZigList<const char *> link_libs = {0};
+ ZigList<const char *> forbidden_link_libs = {0};
ZigList<const char *> frameworks = {0};
int err;
const char *target_arch = nullptr;
@@ -605,6 +607,8 @@ int main(int argc, char **argv) {
lib_dirs.append(argv[i]);
} else if (strcmp(arg, "--library") == 0) {
link_libs.append(argv[i]);
+ } else if (strcmp(arg, "--forbid-library") == 0) {
+ forbidden_link_libs.append(argv[i]);
} else if (strcmp(arg, "--object") == 0) {
objects.append(argv[i]);
} else if (strcmp(arg, "--assembly") == 0) {
@@ -817,6 +821,10 @@ int main(int argc, char **argv) {
LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
link_lib->provided_explicitly = true;
}
+ for (size_t i = 0; i < forbidden_link_libs.length; i += 1) {
+ Buf *forbidden_link_lib = buf_create_from_str(forbidden_link_libs.at(i));
+ codegen_add_forbidden_lib(g, forbidden_link_lib);
+ }
for (size_t i = 0; i < frameworks.length; i += 1) {
codegen_add_framework(g, frameworks.at(i));
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 12293bc61b..b72de374ba 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -221,6 +221,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bo
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory);
static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory);
static AstNode *ast_parse_try_expr(ParseContext *pc, size_t *token_index);
+static AstNode *ast_parse_symbol(ParseContext *pc, size_t *token_index);
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
if (token->id == token_id) {
@@ -240,7 +241,28 @@ static Token *ast_eat_token(ParseContext *pc, size_t *token_index, TokenId token
}
/*
-TypeExpr = PrefixOpExpression | "var"
+ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
+*/
+static AstNode *ast_parse_error_set_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
+ AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, mandatory);
+ if (!prefix_op_expr) {
+ return nullptr;
+ }
+ Token *token = &pc->tokens->at(*token_index);
+ if (token->id == TokenIdBang) {
+ *token_index += 1;
+ AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
+ node->data.bin_op_expr.op1 = prefix_op_expr;
+ node->data.bin_op_expr.bin_op = BinOpTypeErrorUnion;
+ node->data.bin_op_expr.op2 = ast_parse_prefix_op_expr(pc, token_index, true);
+ return node;
+ } else {
+ return prefix_op_expr;
+ }
+}
+
+/*
+TypeExpr = ErrorSetExpr | "var"
*/
static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -249,7 +271,7 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool
*token_index += 1;
return node;
} else {
- return ast_parse_prefix_op_expr(pc, token_index, mandatory);
+ return ast_parse_error_set_expr(pc, token_index, mandatory);
}
}
@@ -651,8 +673,9 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
}
/*
-PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl | ("continue" option(":" Symbol))
+PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl
KeywordLiteral = "true" | "false" | "null" | "undefined" | "error" | "this" | "unreachable"
+ErrorSetDecl = "error" "{" list(Symbol, ",") "}"
*/
static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -716,9 +739,31 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordError) {
- AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
- *token_index += 1;
- return node;
+ Token *next_token = &pc->tokens->at(*token_index + 1);
+ if (next_token->id == TokenIdLBrace) {
+ AstNode *node = ast_create_node(pc, NodeTypeErrorSetDecl, token);
+ *token_index += 2;
+ for (;;) {
+ Token *item_tok = &pc->tokens->at(*token_index);
+ if (item_tok->id == TokenIdRBrace) {
+ *token_index += 1;
+ return node;
+ } else if (item_tok->id == TokenIdSymbol) {
+ AstNode *symbol_node = ast_parse_symbol(pc, token_index);
+ node->data.err_set_decl.decls.append(symbol_node);
+ Token *opt_comma_tok = &pc->tokens->at(*token_index);
+ if (opt_comma_tok->id == TokenIdComma) {
+ *token_index += 1;
+ }
+ } else {
+ ast_invalid_token_error(pc, item_tok);
+ }
+ }
+ } else {
+ AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
+ *token_index += 1;
+ return node;
+ }
} else if (token->id == TokenIdAtSign) {
*token_index += 1;
Token *name_tok = &pc->tokens->at(*token_index);
@@ -950,7 +995,6 @@ static PrefixOp tok_to_prefix_op(Token *token) {
case TokenIdTilde: return PrefixOpBinNot;
case TokenIdStar: return PrefixOpDereference;
case TokenIdMaybe: return PrefixOpMaybe;
- case TokenIdPercent: return PrefixOpError;
case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe;
case TokenIdStarStar: return PrefixOpDereference;
default: return PrefixOpInvalid;
@@ -998,7 +1042,7 @@ static AstNode *ast_parse_addr_of(ParseContext *pc, size_t *token_index) {
/*
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
-PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" | "try"
+PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try"
*/
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -1043,12 +1087,14 @@ static BinOpType tok_to_mult_op(Token *token) {
case TokenIdStarStar: return BinOpTypeArrayMult;
case TokenIdSlash: return BinOpTypeDiv;
case TokenIdPercent: return BinOpTypeMod;
+ case TokenIdBang: return BinOpTypeErrorUnion;
+ case TokenIdBarBar: return BinOpTypeMergeErrorSets;
default: return BinOpTypeInvalid;
}
}
/*
-MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
+MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
*/
static BinOpType ast_parse_mult_op(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -2240,7 +2286,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
}
/*
-FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") TypeExpr
+FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2315,6 +2361,18 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
ast_eat_token(pc, token_index, TokenIdRParen);
next_token = &pc->tokens->at(*token_index);
}
+ if (next_token->id == TokenIdKeywordError) {
+ Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
+ if (maybe_lbrace_tok->id == TokenIdLBrace) {
+ *token_index += 1;
+ node->data.fn_proto.return_type = ast_create_node(pc, NodeTypeErrorType, next_token);
+ return node;
+ }
+ } else if (next_token->id == TokenIdBang) {
+ *token_index += 1;
+ node->data.fn_proto.auto_err_set = true;
+ next_token = &pc->tokens->at(*token_index);
+ }
node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
return node;
@@ -2531,7 +2589,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
Token *colon_token = &pc->tokens->at(*token_index);
if (colon_token->id == TokenIdColon) {
*token_index += 1;
- field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
+ field_node->data.struct_field.type = ast_parse_type_expr(pc, token_index, true);
}
Token *eq_token = &pc->tokens->at(*token_index);
if (eq_token->id == TokenIdEq) {
@@ -2560,26 +2618,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
}
/*
-ErrorValueDecl : "error" "Symbol" ";"
-*/
-static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index) {
- Token *first_token = &pc->tokens->at(*token_index);
-
- if (first_token->id != TokenIdKeywordError) {
- return nullptr;
- }
- *token_index += 1;
-
- Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
- ast_eat_token(pc, token_index, TokenIdSemicolon);
-
- AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
- node->data.error_value_decl.name = token_buf(name_tok);
-
- return node;
-}
-
-/*
TestDecl = "test" String Block
*/
static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index) {
@@ -2611,12 +2649,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
continue;
}
- AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index);
- if (error_value_node) {
- top_level_decls->append(error_value_node);
- continue;
- }
-
AstNode *test_decl_node = ast_parse_test_decl_node(pc, token_index);
if (test_decl_node) {
top_level_decls->append(test_decl_node);
@@ -2744,9 +2776,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.variable_declaration.align_expr, visit, context);
visit_field(&node->data.variable_declaration.section_expr, visit, context);
break;
- case NodeTypeErrorValueDecl:
- // none
- break;
case NodeTypeTestDecl:
visit_field(&node->data.test_decl.body, visit, context);
break;
@@ -2899,5 +2928,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.addr_of_expr.align_expr, visit, context);
visit_field(&node->data.addr_of_expr.op_expr, visit, context);
break;
+ case NodeTypeErrorSetDecl:
+ visit_node_list(&node->data.err_set_decl.decls, visit, context);
+ break;
}
}
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
index f98c0c8344..44d838a723 100644
--- a/src/tokenizer.cpp
+++ b/src/tokenizer.cpp
@@ -195,7 +195,8 @@ enum TokenizeState {
TokenizeStateSawMinusPercent,
TokenizeStateSawAmpersand,
TokenizeStateSawCaret,
- TokenizeStateSawPipe,
+ TokenizeStateSawBar,
+ TokenizeStateSawBarBar,
TokenizeStateLineComment,
TokenizeStateLineString,
TokenizeStateLineStringEnd,
@@ -594,7 +595,7 @@ void tokenize(Buf *buf, Tokenization *out) {
break;
case '|':
begin_token(&t, TokenIdBinOr);
- t.state = TokenizeStateSawPipe;
+ t.state = TokenizeStateSawBar;
break;
case '=':
begin_token(&t, TokenIdEq);
@@ -888,13 +889,17 @@ void tokenize(Buf *buf, Tokenization *out) {
continue;
}
break;
- case TokenizeStateSawPipe:
+ case TokenizeStateSawBar:
switch (c) {
case '=':
set_token_id(&t, t.cur_tok, TokenIdBitOrEq);
end_token(&t);
t.state = TokenizeStateStart;
break;
+ case '|':
+ set_token_id(&t, t.cur_tok, TokenIdBarBar);
+ t.state = TokenizeStateSawBarBar;
+ break;
default:
t.pos -= 1;
end_token(&t);
@@ -902,6 +907,19 @@ void tokenize(Buf *buf, Tokenization *out) {
continue;
}
break;
+ case TokenizeStateSawBarBar:
+ switch (c) {
+ case '=':
+ set_token_id(&t, t.cur_tok, TokenIdBarBarEq);
+ end_token(&t);
+ t.state = TokenizeStateStart;
+ break;
+ default:
+ t.pos -= 1;
+ end_token(&t);
+ t.state = TokenizeStateStart;
+ continue;
+ }
case TokenizeStateSawSlash:
switch (c) {
case '/':
@@ -1428,7 +1446,7 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateSawDash:
case TokenizeStateSawAmpersand:
case TokenizeStateSawCaret:
- case TokenizeStateSawPipe:
+ case TokenizeStateSawBar:
case TokenizeStateSawEq:
case TokenizeStateSawBang:
case TokenizeStateSawLessThan:
@@ -1443,6 +1461,7 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateSawMinusPercent:
case TokenizeStateLineString:
case TokenizeStateLineStringEnd:
+ case TokenizeStateSawBarBar:
end_token(&t);
break;
case TokenizeStateSawDotDot:
@@ -1475,6 +1494,7 @@ const char * token_name(TokenId id) {
case TokenIdArrow: return "->";
case TokenIdAtSign: return "@";
case TokenIdBang: return "!";
+ case TokenIdBarBar: return "||";
case TokenIdBinOr: return "|";
case TokenIdBinXor: return "^";
case TokenIdBitAndEq: return "&=";
@@ -1577,6 +1597,7 @@ const char * token_name(TokenId id) {
case TokenIdTimesEq: return "*=";
case TokenIdTimesPercent: return "*%";
case TokenIdTimesPercentEq: return "*%=";
+ case TokenIdBarBarEq: return "||=";
}
return "(invalid token)";
}
diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp
index 749f72f419..92a3b8de0d 100644
--- a/src/tokenizer.hpp
+++ b/src/tokenizer.hpp
@@ -17,6 +17,8 @@ enum TokenId {
TokenIdArrow,
TokenIdAtSign,
TokenIdBang,
+ TokenIdBarBar,
+ TokenIdBarBarEq,
TokenIdBinOr,
TokenIdBinXor,
TokenIdBitAndEq,
diff --git a/src/util.hpp b/src/util.hpp
index ce6cc09a59..ae33cb84af 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -92,19 +92,22 @@ static inline void safe_memcpy(T *dest, const T *src, size_t count) {
}
template<typename T>
-static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
-#ifdef NDEBUG
+static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
if (!ptr)
zig_panic("allocation failed");
+ if (new_count > old_count) {
+ memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
+ }
return ptr;
-#else
- // manually assign every element to trigger compile error for non-copyable structs
- T *ptr = allocate_nonzero<T>(new_count);
- safe_memcpy(ptr, old, old_count);
- free(old);
+}
+
+template<typename T>
+static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
+ T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
+ if (!ptr)
+ zig_panic("allocation failed");
return ptr;
-#endif
}
template <typename T, size_t n>
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index 81e22187ed..3e92752d9f 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -437,6 +437,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {
return dwarf::DW_TAG_structure_type;
}
+unsigned ZigLLVMTag_DW_enumeration_type(void) {
+ return dwarf::DW_TAG_enumeration_type;
+}
+
unsigned ZigLLVMTag_DW_union_type(void) {
return dwarf::DW_TAG_union_type;
}
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
index 9a67bf7135..4ae25ef6fd 100644
--- a/src/zig_llvm.h
+++ b/src/zig_llvm.h
@@ -133,6 +133,7 @@ ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void);
ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void);
ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void);
+ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void);
ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);