mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
*WI* error sets - basic support working
This commit is contained in:
parent
cfb2c67692
commit
39d5f44863
13
TODO
13
TODO
@ -1,6 +1,15 @@
|
||||
sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find .. -name "*.zig")
|
||||
sed -i 's/\(\bfn .*) \)%\(.*{\)$/\1!\2/g' $(find . -name "*.zig")
|
||||
|
||||
comptime assert(error{} ! i32 == i32);
|
||||
the literal translation of `%T` to this new code is `error!T`.
|
||||
however this would not take advantage of error sets. It's
|
||||
recommended to generally have all your functions which return possible
|
||||
errors to use error set inference, like this:
|
||||
|
||||
fn foo() !void {
|
||||
|
||||
}
|
||||
|
||||
then you can return void, or any error, and the error set is inferred.
|
||||
|
||||
// TODO this is an explicit cast and should actually coerce the type
|
||||
erorr set casting
|
||||
|
||||
@ -3367,7 +3367,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *so
|
||||
}
|
||||
|
||||
ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
|
||||
ConstCastOnly result = {0};
|
||||
ConstCastOnly result = {};
|
||||
result.id = ConstCastResultIdOk;
|
||||
|
||||
if (expected_type == actual_type)
|
||||
@ -3465,7 +3465,7 @@ ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_t
|
||||
if (result.id == ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdErrSet;
|
||||
}
|
||||
result.data.error_set.errors.append(contained_error_entry);
|
||||
result.data.error_set.missing_errors.append(contained_error_entry);
|
||||
}
|
||||
}
|
||||
free(errors);
|
||||
|
||||
@ -214,6 +214,8 @@ struct ConstCastErrSetMismatch {
|
||||
ZigList<ErrorTableEntry *> missing_errors;
|
||||
};
|
||||
|
||||
struct ConstCastOnly;
|
||||
|
||||
struct ConstCastArg {
|
||||
size_t arg_index;
|
||||
ConstCastOnly *child;
|
||||
@ -238,6 +240,6 @@ struct ConstCastOnly {
|
||||
} data;
|
||||
};
|
||||
|
||||
bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type);
|
||||
ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type);
|
||||
|
||||
#endif
|
||||
|
||||
83
src/ir.cpp
83
src/ir.cpp
@ -6424,12 +6424,23 @@ 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(ira->codegen, expected_type, actual_type)) {
|
||||
ConstCastOnly const_cast_result = types_match_const_cast_only(ira->codegen, expected_type, actual_type);
|
||||
if (const_cast_result.id == ConstCastResultIdOk) {
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
|
||||
// if we got here with error sets, make an error showing the incompatibilities
|
||||
if (expected_typek
|
||||
if (const_cast_result.id == ConstCastResultIdErrSet) {
|
||||
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 < const_cast_result.data.error_set.missing_errors.length; i += 1) {
|
||||
ErrorTableEntry *error_entry = const_cast_result.data.error_set.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) {
|
||||
@ -6508,7 +6519,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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
@ -6527,7 +6538,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(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
@ -6543,7 +6554,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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
@ -6558,7 +6569,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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
@ -6638,7 +6649,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(ira->codegen, expected_type, const_ptr_actual)) {
|
||||
if (types_match_const_cast_only(ira->codegen, expected_type, const_ptr_actual).id == ConstCastResultIdOk) {
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
}
|
||||
@ -6742,20 +6753,31 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
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 (err_set_type == ira->codegen->builtin_types.entry_global_error_set) {
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
}
|
||||
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
|
||||
if (cur_err_set_type == ira->codegen->builtin_types.entry_global_error_set) {
|
||||
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
TypeTableEntry *cur_err_set_type = cur_type->data.error_union.err_set_type;
|
||||
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];
|
||||
errors[error_entry->value] = error_entry;
|
||||
@ -6772,12 +6794,14 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
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;
|
||||
@ -6820,15 +6844,16 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
}
|
||||
// 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 (types_match_const_cast_only(ira->codegen, prev_type, cur_type)) {
|
||||
if (types_match_const_cast_only(ira->codegen, prev_type, cur_type).id == ConstCastResultIdOk) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (types_match_const_cast_only(ira->codegen, cur_type, prev_type)) {
|
||||
if (types_match_const_cast_only(ira->codegen, cur_type, prev_type).id == ConstCastResultIdOk) {
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
}
|
||||
@ -6851,26 +6876,26 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
}
|
||||
|
||||
if (prev_type->id == TypeTableEntryIdErrorUnion &&
|
||||
types_match_const_cast_only(ira->codegen, prev_type->data.error_union.payload_type, cur_type))
|
||||
types_match_const_cast_only(ira->codegen, prev_type->data.error_union.payload_type, cur_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_type->id == TypeTableEntryIdErrorUnion &&
|
||||
types_match_const_cast_only(ira->codegen, cur_type->data.error_union.payload_type, prev_type))
|
||||
types_match_const_cast_only(ira->codegen, cur_type->data.error_union.payload_type, prev_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev_type->id == TypeTableEntryIdMaybe &&
|
||||
types_match_const_cast_only(ira->codegen, prev_type->data.maybe.child_type, cur_type))
|
||||
types_match_const_cast_only(ira->codegen, prev_type->data.maybe.child_type, cur_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur_type->id == TypeTableEntryIdMaybe &&
|
||||
types_match_const_cast_only(ira->codegen, cur_type->data.maybe.child_type, prev_type))
|
||||
types_match_const_cast_only(ira->codegen, cur_type->data.maybe.child_type, prev_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
prev_inst = cur_inst;
|
||||
continue;
|
||||
@ -6908,7 +6933,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(ira->codegen, cur_type->data.array.child_type, prev_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, cur_type->data.array.child_type, prev_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
convert_to_const_slice = true;
|
||||
prev_inst = cur_inst;
|
||||
@ -6917,7 +6942,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(ira->codegen, prev_type->data.array.child_type, cur_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, prev_type->data.array.child_type, cur_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
convert_to_const_slice = true;
|
||||
continue;
|
||||
@ -6927,7 +6952,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
(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(ira->codegen, prev_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
|
||||
cur_type->data.array.child_type))
|
||||
cur_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
convert_to_const_slice = false;
|
||||
continue;
|
||||
@ -6937,7 +6962,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
||||
(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(ira->codegen, cur_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type,
|
||||
prev_type->data.array.child_type))
|
||||
prev_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
prev_inst = cur_inst;
|
||||
convert_to_const_slice = false;
|
||||
@ -8059,7 +8084,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(ira->codegen, wanted_type, actual_type)) {
|
||||
if (types_match_const_cast_only(ira->codegen, wanted_type, actual_type).id == ConstCastResultIdOk) {
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
|
||||
}
|
||||
|
||||
@ -8105,7 +8130,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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
@ -8123,7 +8148,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(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, array_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
@ -8139,7 +8164,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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
|
||||
if (type_is_invalid(cast1->value.type))
|
||||
@ -8162,7 +8187,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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
|
||||
if (type_is_invalid(cast1->value.type))
|
||||
@ -8224,7 +8249,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(ira->codegen, wanted_type->data.maybe.child_type, actual_type)) {
|
||||
if (types_match_const_cast_only(ira->codegen, wanted_type->data.maybe.child_type, actual_type).id == ConstCastResultIdOk) {
|
||||
return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
|
||||
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
|
||||
actual_type->id == TypeTableEntryIdNumLitFloat)
|
||||
@ -8246,7 +8271,7 @@ 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(ira->codegen, wanted_type->data.error_union.payload_type, actual_type)) {
|
||||
if (types_match_const_cast_only(ira->codegen, wanted_type->data.error_union.payload_type, actual_type).id == ConstCastResultIdOk) {
|
||||
return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
|
||||
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
|
||||
actual_type->id == TypeTableEntryIdNumLitFloat)
|
||||
@ -8268,7 +8293,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
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(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type))
|
||||
types_match_const_cast_only(ira->codegen, ptr_type->data.pointer.child_type, actual_type->data.array.child_type).id == ConstCastResultIdOk)
|
||||
{
|
||||
IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
|
||||
if (type_is_invalid(cast1->value.type))
|
||||
@ -8295,7 +8320,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
actual_type->id != TypeTableEntryIdMaybe)
|
||||
{
|
||||
TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
|
||||
if (types_match_const_cast_only(ira->codegen, wanted_child_type, actual_type) ||
|
||||
if (types_match_const_cast_only(ira->codegen, wanted_child_type, actual_type).id == ConstCastResultIdOk ||
|
||||
actual_type->id == TypeTableEntryIdNullLit ||
|
||||
actual_type->id == TypeTableEntryIdNumLitInt ||
|
||||
actual_type->id == TypeTableEntryIdNumLitFloat)
|
||||
@ -8445,7 +8470,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(ira->codegen, wanted_type, const_ptr_actual)) {
|
||||
if (types_match_const_cast_only(ira->codegen, wanted_type, const_ptr_actual).id == ConstCastResultIdOk) {
|
||||
return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
}
|
||||
@ -8473,7 +8498,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
|
||||
ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->value.type, value);
|
||||
switch (result) {
|
||||
case ImplicitCastMatchResultNo:
|
||||
ErrorMsg *msg = ir_add_error(ira, value,
|
||||
ir_add_error(ira, value,
|
||||
buf_sprintf("expected type '%s', found '%s'",
|
||||
buf_ptr(&expected_type->name),
|
||||
buf_ptr(&value->value.type->name)));
|
||||
|
||||
@ -209,8 +209,7 @@ fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, a
|
||||
try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
|
||||
}
|
||||
} else |err| switch (err) {
|
||||
error.EndOfFile, error.PathNotFound => {},
|
||||
else => return err,
|
||||
error.EndOfFile => {},
|
||||
}
|
||||
} else |err| switch (err) {
|
||||
error.MissingDebugInfo, error.InvalidDebugInfo => {
|
||||
|
||||
@ -195,7 +195,7 @@ pub fn formatValue(value: var, context: var, comptime Errors: type, output: fn(@
|
||||
const T = @typeOf(value);
|
||||
switch (@typeId(T)) {
|
||||
builtin.TypeId.Int => {
|
||||
return formatInt(value, 10, false, 0, context, output);
|
||||
return formatInt(value, 10, false, 0, context, Errors, output);
|
||||
},
|
||||
builtin.TypeId.Float => {
|
||||
return formatFloat(value, context, output);
|
||||
@ -290,7 +290,7 @@ pub fn formatFloat(value: var, context: var, comptime Errors: type, output: fn(@
|
||||
|
||||
if (float_decimal.exp != 1) {
|
||||
try output(context, "e");
|
||||
try formatInt(float_decimal.exp - 1, 10, false, 0, context, output);
|
||||
try formatInt(float_decimal.exp - 1, 10, false, 0, context, Errors, output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,12 +336,12 @@ pub fn formatFloatDecimal(value: var, precision: usize, context: var, comptime E
|
||||
|
||||
|
||||
pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
|
||||
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)errors!void) errors!void
|
||||
context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
|
||||
{
|
||||
if (@typeOf(value).is_signed) {
|
||||
return formatIntSigned(value, base, uppercase, width, context, output);
|
||||
return formatIntSigned(value, base, uppercase, width, context, Errors, output);
|
||||
} else {
|
||||
return formatIntUnsigned(value, base, uppercase, width, context, output);
|
||||
return formatIntUnsigned(value, base, uppercase, width, context, Errors, output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,15 +354,15 @@ fn formatIntSigned(value: var, base: u8, uppercase: bool, width: usize,
|
||||
try output(context, (&minus_sign)[0..1]);
|
||||
const new_value = uint(-(value + 1)) + 1;
|
||||
const new_width = if (width == 0) 0 else (width - 1);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
|
||||
} else if (width == 0) {
|
||||
return formatIntUnsigned(uint(value), base, uppercase, width, context, output);
|
||||
return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output);
|
||||
} else {
|
||||
const plus_sign: u8 = '+';
|
||||
try output(context, (&plus_sign)[0..1]);
|
||||
const new_value = uint(value);
|
||||
const new_width = if (width == 0) 0 else (width - 1);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_width, context, output);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,7 +410,7 @@ pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, width:
|
||||
.out_buf = out_buf,
|
||||
.index = 0,
|
||||
};
|
||||
formatInt(value, base, uppercase, width, &context, formatIntCallback) catch unreachable;
|
||||
formatInt(value, base, uppercase, width, &context, error{}, formatIntCallback) catch unreachable;
|
||||
return context.index;
|
||||
}
|
||||
const FormatIntBuf = struct {
|
||||
@ -446,7 +446,14 @@ test "fmt.parseInt" {
|
||||
assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
|
||||
}
|
||||
|
||||
pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) !T {
|
||||
const ParseUnsignedError = error {
|
||||
/// The result cannot fit in the type specified
|
||||
Overflow,
|
||||
/// The input had a byte that was not a digit
|
||||
InvalidCharacter,
|
||||
};
|
||||
|
||||
pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
|
||||
var x: T = 0;
|
||||
|
||||
for (buf) |c| {
|
||||
@ -458,16 +465,16 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) !T {
|
||||
return x;
|
||||
}
|
||||
|
||||
fn charToDigit(c: u8, radix: u8) !u8 {
|
||||
fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
|
||||
const value = switch (c) {
|
||||
'0' ... '9' => c - '0',
|
||||
'A' ... 'Z' => c - 'A' + 10,
|
||||
'a' ... 'z' => c - 'a' + 10,
|
||||
else => return error.InvalidChar,
|
||||
else => return error.InvalidCharacter,
|
||||
};
|
||||
|
||||
if (value >= radix)
|
||||
return error.InvalidChar;
|
||||
return error.InvalidCharacter;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -191,17 +191,17 @@ test "math.max" {
|
||||
assert(max(i32(-1), i32(2)) == 2);
|
||||
}
|
||||
|
||||
pub fn mul(comptime T: type, a: T, b: T) !T {
|
||||
pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
||||
var answer: T = undefined;
|
||||
return if (@mulWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||
}
|
||||
|
||||
pub fn add(comptime T: type, a: T, b: T) !T {
|
||||
pub fn add(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
||||
var answer: T = undefined;
|
||||
return if (@addWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||
}
|
||||
|
||||
pub fn sub(comptime T: type, a: T, b: T) !T {
|
||||
pub fn sub(comptime T: type, a: T, b: T) (error{Overflow}!T) {
|
||||
var answer: T = undefined;
|
||||
return if (@subWithOverflow(T, a, b, &answer)) error.Overflow else answer;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ test "string literal to &const []const u8" {
|
||||
assert(mem.eql(u8, *x, "hello"));
|
||||
}
|
||||
|
||||
test "implicitly cast from T to %?T" {
|
||||
test "implicitly cast from T to error!?T" {
|
||||
castToMaybeTypeError(1);
|
||||
comptime castToMaybeTypeError(1);
|
||||
}
|
||||
@ -83,37 +83,37 @@ const A = struct {
|
||||
};
|
||||
fn castToMaybeTypeError(z: i32) void {
|
||||
const x = i32(1);
|
||||
const y: %?i32 = x;
|
||||
const y: error!?i32 = x;
|
||||
assert(??(try y) == 1);
|
||||
|
||||
const f = z;
|
||||
const g: %?i32 = f;
|
||||
const g: error!?i32 = f;
|
||||
|
||||
const a = A{ .a = z };
|
||||
const b: %?A = a;
|
||||
const b: error!?A = a;
|
||||
assert((??(b catch unreachable)).a == 1);
|
||||
}
|
||||
|
||||
test "implicitly cast from int to %?T" {
|
||||
test "implicitly cast from int to error!?T" {
|
||||
implicitIntLitToMaybe();
|
||||
comptime implicitIntLitToMaybe();
|
||||
}
|
||||
fn implicitIntLitToMaybe() void {
|
||||
const f: ?i32 = 1;
|
||||
const g: %?i32 = 1;
|
||||
const g: error!?i32 = 1;
|
||||
}
|
||||
|
||||
|
||||
test "return null from fn() %?&T" {
|
||||
test "return null from fn() error!?&T" {
|
||||
const a = returnNullFromMaybeTypeErrorRef();
|
||||
const b = returnNullLitFromMaybeTypeErrorRef();
|
||||
assert((try a) == null and (try b) == null);
|
||||
}
|
||||
fn returnNullFromMaybeTypeErrorRef() !?&A {
|
||||
fn returnNullFromMaybeTypeErrorRef() error!?&A {
|
||||
const a: ?&A = null;
|
||||
return a;
|
||||
}
|
||||
fn returnNullLitFromMaybeTypeErrorRef() !?&A {
|
||||
fn returnNullLitFromMaybeTypeErrorRef() error!?&A {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ fn castToMaybeSlice() ?[]const u8 {
|
||||
}
|
||||
|
||||
|
||||
test "implicitly cast from [0]T to %[]T" {
|
||||
test "implicitly cast from [0]T to error![]T" {
|
||||
testCastZeroArrayToErrSliceMut();
|
||||
comptime testCastZeroArrayToErrSliceMut();
|
||||
}
|
||||
@ -169,11 +169,11 @@ fn testCastZeroArrayToErrSliceMut() void {
|
||||
assert((gimmeErrOrSlice() catch unreachable).len == 0);
|
||||
}
|
||||
|
||||
fn gimmeErrOrSlice() ![]u8 {
|
||||
fn gimmeErrOrSlice() error![]u8 {
|
||||
return []u8{};
|
||||
}
|
||||
|
||||
test "peer type resolution: [0]u8, []const u8, and %[]u8" {
|
||||
test "peer type resolution: [0]u8, []const u8, and error![]u8" {
|
||||
{
|
||||
var data = "hi";
|
||||
const slice = data[0..];
|
||||
@ -187,7 +187,7 @@ test "peer type resolution: [0]u8, []const u8, and %[]u8" {
|
||||
assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
|
||||
}
|
||||
}
|
||||
fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) ![]u8 {
|
||||
fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) error![]u8 {
|
||||
if (a) {
|
||||
return []u8{};
|
||||
}
|
||||
@ -229,7 +229,7 @@ fn foo(args: ...) void {
|
||||
|
||||
|
||||
test "peer type resolution: error and [N]T" {
|
||||
// TODO: implicit %T to %U where T can implicitly cast to U
|
||||
// TODO: implicit error!T to error!U where T can implicitly cast to U
|
||||
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
|
||||
//comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
|
||||
|
||||
@ -237,13 +237,13 @@ test "peer type resolution: error and [N]T" {
|
||||
comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
|
||||
}
|
||||
|
||||
//fn testPeerErrorAndArray(x: u8) ![]const u8 {
|
||||
//fn testPeerErrorAndArray(x: u8) error![]const u8 {
|
||||
// return switch (x) {
|
||||
// 0x00 => "OK",
|
||||
// else => error.BadValue,
|
||||
// };
|
||||
//}
|
||||
fn testPeerErrorAndArray2(x: u8) ![]const u8 {
|
||||
fn testPeerErrorAndArray2(x: u8) error![]const u8 {
|
||||
return switch (x) {
|
||||
0x00 => "OK",
|
||||
0x01 => "OKK",
|
||||
|
||||
@ -6,7 +6,7 @@ const ET = union(enum) {
|
||||
SINT: i32,
|
||||
UINT: u32,
|
||||
|
||||
pub fn print(a: &const ET, buf: []u8) !usize {
|
||||
pub fn print(a: &const ET, buf: []u8) error!usize {
|
||||
return switch (*a) {
|
||||
ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
|
||||
ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0),
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
|
||||
pub fn foo() !i32 {
|
||||
pub fn foo() error!i32 {
|
||||
const x = try bar();
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
pub fn bar() !i32 {
|
||||
pub fn bar() error!i32 {
|
||||
return 13;
|
||||
}
|
||||
|
||||
pub fn baz() !i32 {
|
||||
pub fn baz() error!i32 {
|
||||
const y = foo() catch 1234;
|
||||
return y + 1;
|
||||
}
|
||||
@ -50,7 +50,7 @@ test "error binary operator" {
|
||||
assert(a == 3);
|
||||
assert(b == 10);
|
||||
}
|
||||
fn errBinaryOperatorG(x: bool) !isize {
|
||||
fn errBinaryOperatorG(x: bool) error!isize {
|
||||
return if (x) error.ItBroke else isize(10);
|
||||
}
|
||||
|
||||
@ -59,18 +59,18 @@ test "unwrap simple value from error" {
|
||||
const i = unwrapSimpleValueFromErrorDo() catch unreachable;
|
||||
assert(i == 13);
|
||||
}
|
||||
fn unwrapSimpleValueFromErrorDo() %isize { return 13; }
|
||||
fn unwrapSimpleValueFromErrorDo() error!isize { return 13; }
|
||||
|
||||
|
||||
test "error return in assignment" {
|
||||
doErrReturnInAssignment() catch unreachable;
|
||||
}
|
||||
|
||||
fn doErrReturnInAssignment() !void {
|
||||
fn doErrReturnInAssignment() error!void {
|
||||
var x : i32 = undefined;
|
||||
x = try makeANonErr();
|
||||
}
|
||||
|
||||
fn makeANonErr() !i32 {
|
||||
fn makeANonErr() error!i32 {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ fn foo(id: u64) !i32 {
|
||||
};
|
||||
}
|
||||
|
||||
fn getErrInt() %i32 { return 0; }
|
||||
fn getErrInt() error!i32 { return 0; }
|
||||
|
||||
test "ir block deps" {
|
||||
assert((foo(1) catch unreachable) == 0);
|
||||
|
||||
@ -262,7 +262,7 @@ test "generic malloc free" {
|
||||
memFree(u8, a);
|
||||
}
|
||||
const some_mem : [100]u8 = undefined;
|
||||
fn memAlloc(comptime T: type, n: usize) ![]T {
|
||||
fn memAlloc(comptime T: type, n: usize) error![]T {
|
||||
return @ptrCast(&T, &some_mem[0])[0..n];
|
||||
}
|
||||
fn memFree(comptime T: type, memory: []T) void { }
|
||||
@ -419,7 +419,7 @@ test "cast slice to u8 slice" {
|
||||
test "pointer to void return type" {
|
||||
testPointerToVoidReturnType() catch unreachable;
|
||||
}
|
||||
fn testPointerToVoidReturnType() !void {
|
||||
fn testPointerToVoidReturnType() error!void {
|
||||
const a = testPointerToVoidReturnType2();
|
||||
return *a;
|
||||
}
|
||||
@ -475,8 +475,8 @@ test "@typeId" {
|
||||
assert(@typeId(@typeOf(undefined)) == Tid.UndefinedLiteral);
|
||||
assert(@typeId(@typeOf(null)) == Tid.NullLiteral);
|
||||
assert(@typeId(?i32) == Tid.Nullable);
|
||||
assert(@typeId(%i32) == Tid.ErrorUnion);
|
||||
assert(@typeId(error) == Tid.Error);
|
||||
assert(@typeId(error!i32) == Tid.ErrorUnion);
|
||||
assert(@typeId(error) == Tid.ErrorSet);
|
||||
assert(@typeId(AnEnum) == Tid.Enum);
|
||||
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
|
||||
assert(@typeId(AUnionEnum) == Tid.Union);
|
||||
|
||||
@ -5,7 +5,7 @@ test "reflection: array, pointer, nullable, error union type child" {
|
||||
comptime {
|
||||
assert(([10]u8).Child == u8);
|
||||
assert((&u8).Child == u8);
|
||||
assert((%u8).Child == u8);
|
||||
assert((error!u8).Payload == u8);
|
||||
assert((?u8).Child == u8);
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ fn switchWithUnreachable(x: i32) i32 {
|
||||
return 10;
|
||||
}
|
||||
|
||||
fn return_a_number() !i32 {
|
||||
fn return_a_number() error!i32 {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
|
||||
|
||||
var read_count: u64 = 0;
|
||||
|
||||
fn readOnce() !u64 {
|
||||
fn readOnce() error!u64 {
|
||||
read_count += 1;
|
||||
return read_count;
|
||||
}
|
||||
@ -12,7 +12,7 @@ const FormValue = union(enum) {
|
||||
Other: bool,
|
||||
};
|
||||
|
||||
fn doThing(form_id: u64) !FormValue {
|
||||
fn doThing(form_id: u64) error!FormValue {
|
||||
return switch (form_id) {
|
||||
17 => FormValue { .Address = try readOnce() },
|
||||
else => error.InvalidDebugInfo,
|
||||
|
||||
@ -17,7 +17,7 @@ fn tryOnErrorUnionImpl() void {
|
||||
assert(x == 11);
|
||||
}
|
||||
|
||||
fn returnsTen() !i32 {
|
||||
fn returnsTen() error!i32 {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ test "try without vars" {
|
||||
assert(result2 == 1);
|
||||
}
|
||||
|
||||
fn failIfTrue(ok: bool) !void {
|
||||
fn failIfTrue(ok: bool) error!void {
|
||||
if (ok) {
|
||||
return error.ItBroke;
|
||||
} else {
|
||||
|
||||
@ -13,7 +13,7 @@ const Agg = struct {
|
||||
const v1 = Value { .Int = 1234 };
|
||||
const v2 = Value { .Array = []u8{3} ** 9 };
|
||||
|
||||
const err = (%Agg)(Agg {
|
||||
const err = (error!Agg)(Agg {
|
||||
.val1 = v1,
|
||||
.val2 = v2,
|
||||
});
|
||||
|
||||
@ -50,7 +50,7 @@ fn runContinueAndBreakTest() void {
|
||||
test "return with implicit cast from while loop" {
|
||||
returnWithImplicitCastFromWhileLoopTest() catch unreachable;
|
||||
}
|
||||
fn returnWithImplicitCastFromWhileLoopTest() !void {
|
||||
fn returnWithImplicitCastFromWhileLoopTest() error!void {
|
||||
while (true) {
|
||||
return;
|
||||
}
|
||||
@ -116,7 +116,7 @@ test "while with error union condition" {
|
||||
}
|
||||
|
||||
var numbers_left: i32 = undefined;
|
||||
fn getNumberOrErr() !i32 {
|
||||
fn getNumberOrErr() error!i32 {
|
||||
return if (numbers_left == 0)
|
||||
error.OutOfNumbers
|
||||
else x: {
|
||||
@ -204,7 +204,7 @@ fn testContinueOuter() void {
|
||||
|
||||
fn returnNull() ?i32 { return null; }
|
||||
fn returnMaybe(x: i32) ?i32 { return x; }
|
||||
fn returnError() %i32 { return error.YouWantedAnError; }
|
||||
fn returnSuccess(x: i32) %i32 { return x; }
|
||||
fn returnError() error!i32 { return error.YouWantedAnError; }
|
||||
fn returnSuccess(x: i32) error!i32 { return x; }
|
||||
fn returnFalse() bool { return false; }
|
||||
fn returnTrue() bool { return true; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user