Skip to content

Commit

Permalink
*WIP* error sets - rewrite "const cast only" function
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed Feb 2, 2018
1 parent 406496c commit cfb2c67
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 55 deletions.
136 changes: 86 additions & 50 deletions src/analyze.cpp
Expand Up @@ -3366,9 +3366,12 @@ 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(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
ConstCastOnly types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
ConstCastOnly result = {0};
result.id = ConstCastResultIdOk;

if (expected_type == actual_type)
return true;
return result;

// pointer const
if (expected_type->id == TypeTableEntryIdPointer &&
Expand All @@ -3379,15 +3382,18 @@ bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, Type
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(g, expected_type->data.pointer.child_type,
actual_type->data.pointer.child_type);
ConstCastOnly child = types_match_const_cast_only(g, expected_type->data.pointer.child_type, actual_type->data.pointer.child_type);
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 (expected_type->id == TypeTableEntryIdStruct &&
actual_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_slice &&
actual_type->data.structure.is_slice)
if (expected_type->id == TypeTableEntryIdStruct && actual_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_slice && actual_type->data.structure.is_slice)
{
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;
Expand All @@ -3397,43 +3403,54 @@ bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, Type
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(g, expected_ptr_type->data.pointer.child_type,
ConstCastOnly child = types_match_const_cast_only(g, expected_ptr_type->data.pointer.child_type,
actual_ptr_type->data.pointer.child_type);
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)
{
return types_match_const_cast_only(g,
expected_type->data.maybe.child_type,
actual_type->data.maybe.child_type);
if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) {
ConstCastOnly child = types_match_const_cast_only(g, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type);
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)
{
return types_match_const_cast_only(g,
expected_type->data.error_union.payload_type,
actual_type->data.error_union.payload_type) &&
types_match_const_cast_only(g,
expected_type->data.error_union.err_set_type,
actual_type->data.error_union.err_set_type);
if (expected_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdErrorUnion) {
ConstCastOnly payload_child = types_match_const_cast_only(g, expected_type->data.error_union.payload_type, actual_type->data.error_union.payload_type);
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(g, expected_type->data.error_union.err_set_type, actual_type->data.error_union.err_set_type);
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)
{
if (expected_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdErrorSet) {
TypeTableEntry *contained_set = actual_type;
TypeTableEntry *container_set = expected_type;

if (container_set == g->builtin_types.entry_global_error_set ||
container_set->data.error_set.infer_fn != nullptr)
{
return true;
if (container_set == g->builtin_types.entry_global_error_set || container_set->data.error_set.infer_fn != nullptr) {
return result;
}

ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);
Expand All @@ -3445,42 +3462,54 @@ bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, Type
ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i];
ErrorTableEntry *error_entry = errors[contained_error_entry->value];
if (error_entry == nullptr) {
return false;
if (result.id == ConstCastResultIdOk) {
result.id = ConstCastResultIdErrSet;
}
result.data.error_set.errors.append(contained_error_entry);
}
}
free(errors);
return true;
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) {
return false;
result.id = ConstCastResultIdFnAlign;
return result;
}
if (expected_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) {
return false;
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) {
return false;
result.id = ConstCastResultIdFnVarArgs;
return result;
}
if (expected_type->data.fn.is_generic != actual_type->data.fn.is_generic) {
return false;
result.id = ConstCastResultIdFnIsGeneric;
return result;
}
if (!expected_type->data.fn.is_generic &&
actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
!types_match_const_cast_only(g,
expected_type->data.fn.fn_type_id.return_type,
actual_type->data.fn.fn_type_id.return_type))
actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable)
{
return false;
ConstCastOnly child = types_match_const_cast_only(g, expected_type->data.fn.fn_type_id.return_type, actual_type->data.fn.fn_type_id.return_type);
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) {
return false;
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) {
return false;
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);
Expand All @@ -3489,19 +3518,26 @@ bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, Type
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(g, actual_param_info->type, expected_param_info->type)) {
return false;
ConstCastOnly arg_child = types_match_const_cast_only(g, actual_param_info->type, expected_param_info->type);
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) {
return false;
result.id = ConstCastResultIdFnArgNoAlias;
result.data.arg_no_alias.arg_index = i;
return result;
}
}
return true;
return result;
}


return false;
result.id = ConstCastResultIdType;
return result;
}

Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
Expand Down
51 changes: 50 additions & 1 deletion src/analyze.hpp
Expand Up @@ -46,7 +46,6 @@ bool type_has_bits(TypeTableEntry *type_entry);
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);


bool types_match_const_cast_only(CodeGen *g, 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);
Expand Down Expand Up @@ -191,4 +190,54 @@ void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);

TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);

enum ConstCastResultId {
ConstCastResultIdOk,
ConstCastResultIdErrSet,
ConstCastResultIdPointerChild,
ConstCastResultIdSliceChild,
ConstCastResultIdNullableChild,
ConstCastResultIdErrorUnionPayload,
ConstCastResultIdErrorUnionErrorSet,
ConstCastResultIdFnAlign,
ConstCastResultIdFnCC,
ConstCastResultIdFnVarArgs,
ConstCastResultIdFnIsGeneric,
ConstCastResultIdFnReturnType,
ConstCastResultIdFnArgCount,
ConstCastResultIdFnGenericArgCount,
ConstCastResultIdFnArg,
ConstCastResultIdFnArgNoAlias,
ConstCastResultIdType,
};

struct ConstCastErrSetMismatch {
ZigList<ErrorTableEntry *> missing_errors;
};

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;
};

bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, TypeTableEntry *actual_type);

#endif
10 changes: 6 additions & 4 deletions src/ir.cpp
Expand Up @@ -6428,6 +6428,9 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
return ImplicitCastMatchResultYes;
}

// if we got here with error sets, make an error showing the incompatibilities
if (expected_typek

// implicit conversion from anything to var
if (expected_type->id == TypeTableEntryIdVar) {
return ImplicitCastMatchResultYes;
Expand Down Expand Up @@ -6801,9 +6804,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
errors[error_entry->value] = error_entry;
}
continue;
}
if (prev_type->id == TypeTableEntryIdErrorUnion) {
// check if the cur type error set must be a subset
} else {
// 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];
Expand Down Expand Up @@ -8471,7 +8473,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:
ir_add_error(ira, value,
ErrorMsg *msg = ir_add_error(ira, value,
buf_sprintf("expected type '%s', found '%s'",
buf_ptr(&expected_type->name),
buf_ptr(&value->value.type->name)));
Expand Down

0 comments on commit cfb2c67

Please sign in to comment.