diff --git a/src/analyze.cpp b/src/analyze.cpp index 36aac9b29e..ac504a3ea5 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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 && @@ -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(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; @@ -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(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(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(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(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(g->errors_by_index.length); @@ -3445,11 +3462,14 @@ 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 @@ -3457,30 +3477,39 @@ bool types_match_const_cast_only(CodeGen *g, TypeTableEntry *expected_type, Type 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(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); @@ -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(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) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 9af259b10d..551b892791 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -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); @@ -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 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 diff --git a/src/ir.cpp b/src/ir.cpp index d2b2c4fc82..00bde702d2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -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; @@ -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]; @@ -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)));