Commit cfb2c67692

Andrew Kelley <superjoe30@gmail.com>
2018-02-02 17:50:19
*WIP* error sets - rewrite "const cast only" function
1 parent 406496c
Changed files (3)
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<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;
@@ -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);
@@ -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<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);
@@ -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) {
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<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
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)));