diff --git a/compiler/type_assign.m b/compiler/type_assign.m index 04c4e1e36..309d618e3 100644 --- a/compiler/type_assign.m +++ b/compiler/type_assign.m @@ -20,6 +20,7 @@ :- import_module hlds. :- import_module hlds.hlds_class. :- import_module hlds.hlds_cons. +:- import_module hlds.hlds_data. :- import_module hlds.hlds_pred. :- import_module parse_tree. :- import_module parse_tree.prog_data. @@ -125,12 +126,24 @@ maybe_from_type :: maybe(mer_type), maybe_to_type :: maybe(mer_type) ) - ; incompatible_types( + ; different_type_categories( + dtc_type_table :: type_table, % The two types have different principal function symbols. - it_from_type :: mer_type, - it_to_type :: mer_type + dtc_from_type :: mer_type, + dtc_to_type :: mer_type + ) + ; different_builtin_types( + % Both types are builtin types, but different builtin types. + dbit_from_type :: builtin_type, + dbti_to_type :: builtin_type + ) + ; different_tuple_arities( + % Both types are tuple types, but with different arities. + dta_from_type :: arity, + dta_to_type :: arity ) ; cannot_unify_type_vars( + % One or both of these will be a type_variable. cutv_from_type :: mer_type, cutv_to_type :: mer_type ) diff --git a/compiler/typecheck_coerce.m b/compiler/typecheck_coerce.m index fbf2e6994..3d656e2a6 100644 --- a/compiler/typecheck_coerce.m +++ b/compiler/typecheck_coerce.m @@ -436,100 +436,19 @@ typecheck_coerce_between_types(TypeTable, TVarSet, FromType, ToType, %---------------------------------------------------------------------------% -:- type maybe_du_type - ---> is_du_type(du_type_info) - % The type is a du type, with the given info. - ; is_not_du_type(string). - % The type is not a du type. The string describes - % what kind of type it is. The description allows code - % that generates diagnostics to add the article "a" in front - % of these pieces, and the plural suffix "s" after them. - -:- type du_type_info - ---> du_type_info(type_ctor, list(mer_type), - hlds_type_defn, type_body_du). - % This du type has the given type_ctor and argument types. - % The last two arguments give the whole, and the du body part, - % of the definition of the type_ctor. - - % If the given type is du type, return the empty list. Otherwise, - % return a description of what kind of non-du type it is. - % -:- pred classify_is_du_type(type_table::in, mer_type::in, - maybe_du_type::out) is det. - -classify_is_du_type(TypeTable, Type, MaybeDuType) :- - ( - Type = type_variable(_, _), - MaybeDuType = is_not_du_type("type variable") - ; - Type = defined_type(SymName, ArgTypes, _Kind), - list.length(ArgTypes, Arity), - TypeCtor = type_ctor(SymName, Arity), - ( if search_type_ctor_defn(TypeTable, TypeCtor, TypeDefn) then - get_type_defn_body(TypeDefn, TypeBody), - ( - TypeBody = hlds_du_type(TypeBodyDu), - DuType = du_type_info(TypeCtor, ArgTypes, - TypeDefn, TypeBodyDu), - MaybeDuType = is_du_type(DuType) - ; - TypeBody = hlds_eqv_type(_), - MaybeDuType = is_not_du_type("equivalence type") - ; - TypeBody = hlds_foreign_type(_), - MaybeDuType = is_not_du_type("foreign type") - ; - TypeBody = hlds_solver_type(_), - MaybeDuType = is_not_du_type("solver type") - ; - TypeBody = hlds_abstract_type(_), - MaybeDuType = is_not_du_type("abstract type") - ) - else - MaybeDuType = is_not_du_type("unknown type") - ) - ; - Type = builtin_type(_), - MaybeDuType = is_not_du_type("builtin type") - ; - Type = tuple_type(_, _), - % XXX This code preserves old behavior, but it prevents programs - % from coercing one tuple type to another, even if the tuple's - % argument types are coerceable. - MaybeDuType = is_not_du_type("tuple type") - ; - Type = higher_order_type(PorF, _, _, _), - ( - PorF = pf_function, - MaybeDuType = is_not_du_type("function type") - ; - PorF = pf_predicate, - MaybeDuType = is_not_du_type("predicate type") - ) - ; - Type = apply_n_type(_, _, _), - MaybeDuType = is_not_du_type("function type") - ; - Type = kinded_type(SubType, _), - classify_is_du_type(TypeTable, SubType, MaybeDuType) - ). - -%---------------------% - :- pred compute_base_type_of_du_type(type_table::in, tvarset::in, du_type_info::in, du_type_info::out) is det. -compute_base_type_of_du_type(TypeTable, TVarSet, DuTypeInfo, BaseTypeInfo) :- +compute_base_type_of_du_type(TypeTable, TVarSet, DuTypeInfo, BaseDuTypeInfo) :- DuTypeInfo = du_type_info(TypeCtor, ArgTypes, TypeDefn, TypeBodyDu), MaybeSuperType = TypeBodyDu ^ du_type_supertype, ( MaybeSuperType = not_a_subtype, - BaseTypeInfo = DuTypeInfo + BaseDuTypeInfo = DuTypeInfo ; MaybeSuperType = subtype_of(SuperType0), - get_supertype_of_subtype(TVarSet, TypeCtor, ArgTypes, - TypeDefn, SuperType0, SuperType), + get_supertype_of_subtype(TVarSet, TypeCtor, ArgTypes, TypeDefn, + SuperType0, SuperType), classify_is_du_type(TypeTable, SuperType, MaybeSuperDuType), % The invocations of add_du_ctors_check_subtype_check_foreign_type % in make_hlds_passes.m should have already checked that @@ -543,7 +462,7 @@ compute_base_type_of_du_type(TypeTable, TVarSet, DuTypeInfo, BaseTypeInfo) :- unexpected($pred, "MaybeSuperDuType != is_du_type") ), compute_base_type_of_du_type(TypeTable, TVarSet, - SuperDuTypeInfo, BaseTypeInfo) + SuperDuTypeInfo, BaseDuTypeInfo) ). %---------------------------------------------------------------------------% @@ -765,7 +684,7 @@ are_actual_param_type_pairs_as_related_as_needed(TypeTable, TVarSet, else % FromArgTypes and ToArgTypes are the actual types bound to TypeParams % in the from-type and to-type of the coercion respectively. - % If their length do not match, then some earlier compiler pass + % If their lengths do not match, then some earlier compiler pass % screwed up really badly. unexpected($pred, "length mismatch") ). @@ -776,9 +695,9 @@ are_actual_param_type_pairs_as_related_as_needed(TypeTable, TVarSet, list(coerce_fail)::in, list(coerce_fail)::out) is det. are_actual_param_type_pair_as_related_as_needed(TypeTable, TVarSet, - InvariantTVars, TypeVar, FromType, ToType, + InvariantTVars, TypeParam, FromType, ToType, !TypeAssign, !CoerceFails) :- - ( if set.contains(InvariantTVars, TypeVar) then + ( if set.contains(InvariantTVars, TypeParam) then types_compare_as_given(TypeTable, TVarSet, compare_equal, FromType, ToType, !TypeAssign, !CoerceFails) else @@ -840,11 +759,16 @@ types_compare_as_given_nonvar(TypeTable, TVarSet, Comparison, TypeA, TypeB, !TypeAssign, !CoerceFails) :- require_complete_switch [TypeA] ( - TypeA = builtin_type(BuiltinType), - ( if TypeB = builtin_type(BuiltinType) then + TypeA = builtin_type(BuiltinTypeA), + ( if TypeB = builtin_type(BuiltinTypeA) then true else - CoerceFail = incompatible_types(TypeA, TypeB), + ( if TypeB = builtin_type(BuiltinTypeB) then + CoerceFail = + different_builtin_types(BuiltinTypeA, BuiltinTypeB) + else + CoerceFail = different_type_categories(TypeTable, TypeA, TypeB) + ), !:CoerceFails = [CoerceFail | !.CoerceFails] ) ; @@ -877,23 +801,32 @@ types_compare_as_given_nonvar(TypeTable, TVarSet, Comparison, % is either % - not a du type definition, or % - it is a du type, but not a subtype type definition. - % XXX We should return a differnt fail for each. - CoerceFail = incompatible_types(TypeA, TypeB), + % XXX We should return a different fail for each. + CoerceFail = different_type_categories(TypeTable, + TypeA, TypeB), !:CoerceFails = [CoerceFail | !.CoerceFails] ) ) ) else - CoerceFail = incompatible_types(TypeA, TypeB), + CoerceFail = different_type_categories(TypeTable, TypeA, TypeB), !:CoerceFails = [CoerceFail | !.CoerceFails] ) ; TypeA = tuple_type(ArgTypesA, Kind), ( if TypeB = tuple_type(ArgTypesB, Kind) then - corresponding_types_compare_as_given(TypeTable, TVarSet, - Comparison, ArgTypesA, ArgTypesB, !TypeAssign, !CoerceFails) + list.length(ArgTypesA, NumArgTypesA), + list.length(ArgTypesB, NumArgTypesB), + ( if NumArgTypesA = NumArgTypesB then + corresponding_types_compare_as_given(TypeTable, TVarSet, + Comparison, ArgTypesA, ArgTypesB, !TypeAssign, !CoerceFails) + else + CoerceFail = + different_tuple_arities(NumArgTypesA, NumArgTypesB), + !:CoerceFails = [CoerceFail | !.CoerceFails] + ) else - CoerceFail = incompatible_types(TypeA, TypeB), + CoerceFail = different_type_categories(TypeTable, TypeA, TypeB), !:CoerceFails = [CoerceFail | !.CoerceFails] ) ; @@ -907,7 +840,7 @@ types_compare_as_given_nonvar(TypeTable, TVarSet, Comparison, corresponding_types_compare_as_given(TypeTable, TVarSet, SubComparison, ArgTypesA, ArgTypesB, !TypeAssign, !CoerceFails) else - CoerceFail = incompatible_types(TypeA, TypeB), + CoerceFail = different_type_categories(TypeTable, TypeA, TypeB), !:CoerceFails = [CoerceFail | !.CoerceFails] ) ; @@ -923,7 +856,7 @@ types_compare_as_given_nonvar(TypeTable, TVarSet, Comparison, types_compare_as_given(TypeTable, TVarSet, Comparison, TypeA1, TypeB1, !TypeAssign, !CoerceFails) else - CoerceFail = incompatible_types(TypeA, TypeB), + CoerceFail = different_type_categories(TypeTable, TypeA, TypeB), !:CoerceFails = [CoerceFail | !.CoerceFails] ) ). diff --git a/compiler/typecheck_errors.m b/compiler/typecheck_errors.m index 7a577ccc3..dcc16916a 100644 --- a/compiler/typecheck_errors.m +++ b/compiler/typecheck_errors.m @@ -45,12 +45,16 @@ :- implementation. :- import_module check_hlds.typecheck_error_util. +:- import_module check_hlds.typecheck_util. :- import_module hlds. :- import_module hlds.hlds_class. +:- import_module hlds.hlds_data. :- import_module hlds.hlds_module. :- import_module hlds.hlds_pred. :- import_module libs. :- import_module libs.options. +:- import_module mdbcomp. +:- import_module mdbcomp.sym_name. :- import_module parse_tree.parse_tree_out_term. :- import_module parse_tree.parse_tree_out_type. :- import_module parse_tree.prog_type_subst. @@ -208,18 +212,43 @@ report_invalid_coerce_from_to(ClauseContext, Context, FromVar, TVarSet, describe_coerce_fail(TVarSet, Fail) = Pieces :- % XXX Generate descriptions for ALL kinds of coerce failures. ( - Fail = different_base_types(_FromType, _FromBaseTypeCtor, - _ToType, _ToBaseTypeCtor), - Pieces = [] + Fail = different_base_types(FromType, FromBaseTypeCtor, + ToType, ToBaseTypeCtor), + Pieces = describe_coerce_fail_different_base_types(TVarSet, + FromType, FromBaseTypeCtor, ToType, ToBaseTypeCtor) ; Fail = unknown_or_nonground_type(_, _, _), + % We can and do generate this kind of coerce_fail during typechecking, + % but as of 2026 jul 26, I (zs) cannot + % + % - either construct a test case in which one of these coerce_fails + % survives the final prune coerce constraints pass, + % + % - or construct a correctness argument for the proposition that + % these coerce_fails *cannot* survive the final prune coerce + % constraints pass. + % + % In the absence of the former, which could serve as motivating + % example, I cannot design a good error message, and in the absence + % of the latter, I cannot replace the next line with a call to + % "unexpected". Pieces = [] ; - Fail = incompatible_types(_, _), - Pieces = [] + Fail = different_type_categories(TypeTable, FromType, ToType), + Pieces = describe_coerce_fail_different_type_categories(TypeTable, + FromType, ToType) ; - Fail = cannot_unify_type_vars(_, _), - Pieces = [] + Fail = different_builtin_types(FromBuiltinType, ToBuiltinType), + Pieces = describe_coerce_fail_different_builtin_types(TVarSet, + FromBuiltinType, ToBuiltinType) + ; + Fail = different_tuple_arities(FromArity, ToArity), + Pieces = describe_coerce_fail_different_tuple_arities( + FromArity, ToArity) + ; + Fail = cannot_unify_type_vars(FromType, ToType), + Pieces = describe_coerce_fail_cannot_unify_type_vars(TVarSet, + FromType, ToType) ; Fail = non_du_type_ctor(FromType, FromTypeDesc, ToType, ToTypeDesc), Pieces = describe_coerce_fail_non_du_type_ctor(TVarSet, @@ -229,6 +258,139 @@ describe_coerce_fail(TVarSet, Fail) = Pieces :- Pieces = [] ). +:- func describe_coerce_fail_different_base_types(tvarset, + mer_type, type_ctor, mer_type, type_ctor) = list(format_piece). + +describe_coerce_fail_different_base_types(_TVarSet, + _FromType, FromBaseTypeCtor, _ToType, ToBaseTypeCtor) = Pieces :- + FromBaseTypeCtor = type_ctor(FromSymName, _), + ToBaseTypeCtor = type_ctor(ToSymName, _), + % Print the module qualifiers on the type_ctors only if it is relevant. + ( if + FromSymName = qualified(ModuleName, _), + ToSymName = qualified(ModuleName, _) + then + FromBaseCtorPiece = unqual_type_ctor(FromBaseTypeCtor), + ToBaseCtorPiece = unqual_type_ctor(ToBaseTypeCtor) + else + FromBaseCtorPiece = qual_type_ctor(FromBaseTypeCtor), + ToBaseCtorPiece = qual_type_ctor(ToBaseTypeCtor) + ), + Pieces = [words("The base type constructor of the coerce-from type is")] ++ + color_as_inconsistent([FromBaseCtorPiece, suffix(",")]) ++ + [words("while for the coerce-to type it is")] ++ + color_as_inconsistent([ToBaseCtorPiece, suffix(".")]) ++ + [nl]. +% XXX A possible alternative wording. + % FromTypeStr = mercury_type_to_string(TVarSet, print_num_only, FromType), + % ToTypeStr = mercury_type_to_string(TVarSet, print_num_only, ToType), +% Pieces = [words("You can coerce"), +% words("from one discriminated union type to another"), +% words("only if they have the same base type constructor,"), +% words("meaning that following the chain of supertypes from both"), +% % XXX Should this be included? +% % words("the from-type and the to-type"), +% words("ends up at the same type constructor."), +% words("In this case, the base type constructor of the from-type")] ++ +% color_as_subject([words(FromTypeStr)]) ++ +% [words("is")] ++ +% color_as_inconsistent([FromBaseCtorPiece, suffix(",")]) ++ +% [words("while the base type constructor of the to-type")] ++ +% color_as_subject([words(ToTypeStr)]) ++ +% [words("is")] ++ +% color_as_inconsistent([ToBaseCtorPiece, suffix(".")]) ++ +% [nl]. + +:- func describe_coerce_fail_different_type_categories(type_table, + mer_type, mer_type) = list(format_piece). + +describe_coerce_fail_different_type_categories(TypeTable, + FromType, ToType) = Pieces :- + classify_is_du_type(TypeTable, FromType, FromMaybeDuType), + classify_is_du_type(TypeTable, ToType, ToMaybeDuType), + ( + FromMaybeDuType = is_not_du_type(FromTypeDesc), + ToMaybeDuType = is_not_du_type(ToTypeDesc), + Pieces = + color_as_subject( + [upper_case_next, words(FromTypeDesc), suffix("s")]) ++ + [words("and")] ++ + color_as_subject([words(ToTypeDesc), suffix("s")]) ++ + [words("cannot be either coerced from, or coerced to."), nl] + ; + FromMaybeDuType = is_not_du_type(FromTypeDesc), + ToMaybeDuType = is_du_type(_), + Pieces = + color_as_subject( + [upper_case_next, words(FromTypeDesc), suffix("s")]) ++ + [words("cannot be either coerced from, or coerced to."), nl] + ; + FromMaybeDuType = is_du_type(_), + ToMaybeDuType = is_not_du_type(ToTypeDesc), + Pieces = + color_as_subject( + [upper_case_next, words(ToTypeDesc), suffix("s")]) ++ + [words("cannot be either coerced from, or coerced to."), nl] + ; + FromMaybeDuType = is_du_type(_), + ToMaybeDuType = is_du_type(_), + % We should generate a different coerce_fail for the situation + % in which we now generate this one. + Pieces = [] + ). + +:- func describe_coerce_fail_different_builtin_types(tvarset, + builtin_type, builtin_type) = list(format_piece). + +describe_coerce_fail_different_builtin_types(TVarSet, + FromBuiltinType, ToBuiltinType) = Pieces :- + FromType = builtin_type(FromBuiltinType), + ToType = builtin_type(ToBuiltinType), + FromTypeStr = mercury_type_to_string(TVarSet, print_num_only, FromType), + ToTypeStr = mercury_type_to_string(TVarSet, print_num_only, ToType), + Pieces = [words("Builtin types such as")] ++ + color_as_subject([words(FromTypeStr)]) ++ [words("and")] ++ + color_as_subject([words(ToTypeStr)]) ++ + [words("cannot be either coerced from, or coerced to."), nl]. + +:- func describe_coerce_fail_different_tuple_arities(arity, arity) + = list(format_piece). + +describe_coerce_fail_different_tuple_arities(FromArity, ToArity) = Pieces :- + Pieces = [words("You cannot coerce from a tuple type of")] ++ + color_as_inconsistent([words("arity"), int_fixed(FromArity)]) ++ + [words("to a tuple type of")] ++ + color_as_inconsistent([words("arity"), int_fixed(ToArity), + suffix(".")]) ++ + [nl]. + +:- func describe_coerce_fail_cannot_unify_type_vars(tvarset, + mer_type, mer_type) = list(format_piece). + +describe_coerce_fail_cannot_unify_type_vars(TVarSet, FromType, ToType) + = Pieces :- + FromTypeStr = mercury_type_to_string(TVarSet, print_name_only, FromType), + ToTypeStr = mercury_type_to_string(TVarSet, print_name_only, ToType), + ( if FromType = type_variable(_, _) then + ( if ToType = type_variable(_, _) then + TypeVarOrVarsStr = "Type variables", + TVarPieces = color_as_subject([fixed(FromTypeStr)]) ++ + [words("and")] ++ color_as_subject([fixed(ToTypeStr)]) + else + TypeVarOrVarsStr = "Type variable", + TVarPieces = color_as_subject([fixed(FromTypeStr)]) + ) + else + ( if ToType = type_variable(_, _) then + TypeVarOrVarsStr = "Type variable", + TVarPieces = color_as_subject([fixed(ToTypeStr)]) + else + unexpected($pred, "neither FromType nor ToType is a variable") + ) + ), + Pieces = [words(TypeVarOrVarsStr), words("such as")] ++ TVarPieces ++ + [words("cannot be either coerced from, or coerced to."), nl]. + :- func describe_coerce_fail_non_du_type_ctor(tvarset, mer_type, string, mer_type, string) = list(format_piece). diff --git a/compiler/typecheck_util.m b/compiler/typecheck_util.m index e72725355..2c9383f6a 100644 --- a/compiler/typecheck_util.m +++ b/compiler/typecheck_util.m @@ -19,6 +19,7 @@ :- import_module check_hlds.type_assign. :- import_module hlds. :- import_module hlds.hlds_class. +:- import_module hlds.hlds_data. :- import_module parse_tree. :- import_module parse_tree.prog_data. @@ -80,6 +81,34 @@ :- pred general_higher_order_func_type(purity::in, int::in, tvarset::out, mer_type::out, list(mer_type)::out, mer_type::out) is det. +%---------------------------------------------------------------------------% + +:- type maybe_du_type + ---> is_du_type(du_type_info) + % The type is a du type, with the given info. + ; is_not_du_type(string). + % The type is not a du type. The string describes + % what kind of type it is. The description allows code + % that generates diagnostics to add the article "a" in front + % of these pieces, and the plural suffix "s" after them. + +:- type du_type_info + ---> du_type_info(type_ctor, list(mer_type), + hlds_type_defn, type_body_du). + % This du type has the given type_ctor and argument types. + % The last two arguments give the whole, and the du body part, + % of the definition of the type_ctor. + + % If the given type is a du type, return its du_type_info. + % Otherwise, return a description of what kind of non-du type it is. + % + % This predicate is called from both typecheck_coerce.m, and + % typecheck_errors.m (which constructs diagnostics for the errors + % discovered by typecheck_coerce.m.) + % +:- pred classify_is_du_type(type_table::in, mer_type::in, + maybe_du_type::out) is det. + %---------------------------------------------------------------------------% %---------------------------------------------------------------------------% @@ -185,6 +214,66 @@ general_higher_order_func_type(Purity, Arity, RetType = type_variable(RetTypeVar, kind_star), construct_higher_order_func_type(Purity, ArgTypes, RetType, FuncType). +%---------------------------------------------------------------------------% + +classify_is_du_type(TypeTable, Type, MaybeDuType) :- + ( + Type = type_variable(_, _), + MaybeDuType = is_not_du_type("type variable") + ; + Type = defined_type(SymName, ArgTypes, _Kind), + list.length(ArgTypes, Arity), + TypeCtor = type_ctor(SymName, Arity), + ( if search_type_ctor_defn(TypeTable, TypeCtor, TypeDefn) then + get_type_defn_body(TypeDefn, TypeBody), + ( + TypeBody = hlds_du_type(TypeBodyDu), + DuType = du_type_info(TypeCtor, ArgTypes, + TypeDefn, TypeBodyDu), + MaybeDuType = is_du_type(DuType) + ; + TypeBody = hlds_eqv_type(_), + MaybeDuType = is_not_du_type("equivalence type") + ; + TypeBody = hlds_foreign_type(_), + MaybeDuType = is_not_du_type("foreign type") + ; + TypeBody = hlds_solver_type(_), + MaybeDuType = is_not_du_type("solver type") + ; + TypeBody = hlds_abstract_type(_), + MaybeDuType = is_not_du_type("abstract type") + ) + else + MaybeDuType = is_not_du_type("unknown type") + ) + ; + Type = builtin_type(_), + MaybeDuType = is_not_du_type("builtin type") + ; + Type = tuple_type(_, _), + % XXX This code preserves old behavior, but it prevents programs + % from coercing one tuple type to another, even if the tuple's + % argument types are coerceable. + MaybeDuType = is_not_du_type("tuple type") + ; + Type = higher_order_type(PorF, _, _, _), + ( + PorF = pf_function, + MaybeDuType = is_not_du_type("function type") + ; + PorF = pf_predicate, + MaybeDuType = is_not_du_type("predicate type") + ) + ; + Type = apply_n_type(_, _, _), + MaybeDuType = is_not_du_type("function type") + ; + Type = kinded_type(SubType, _), + classify_is_du_type(TypeTable, SubType, MaybeDuType) + ). + + %---------------------------------------------------------------------------% :- end_module check_hlds.typecheck_util. %---------------------------------------------------------------------------% diff --git a/tests/invalid/coerce_type_error.err_exp b/tests/invalid/coerce_type_error.err_exp index 809f612d7..0e4ee85e7 100644 --- a/tests/invalid/coerce_type_error.err_exp +++ b/tests/invalid/coerce_type_error.err_exp @@ -2,10 +2,15 @@ coerce_type_error.m:045: In clause for predicate `bad_unrelated'/2: coerce_type_error.m:045: error: cannot coerce `X' from coerce_type_error.m:045: `coerce_type_error.orange_non_fruit' to coerce_type_error.m:045: `coerce_type_error.citrus'. +coerce_type_error.m:045: The base type constructor of the coerce-from type is +coerce_type_error.m:045: `orange_non_fruit'/0, while for the coerce-to type +coerce_type_error.m:045: it is `fruit'/0. coerce_type_error.m:070: In clause for predicate `bad_phantom'/2: coerce_type_error.m:070: error: cannot coerce `X' from coerce_type_error.m:070: `coerce_type_error.phantom(int)' to coerce_type_error.m:070: `coerce_type_error.phantom(float)'. +coerce_type_error.m:070: Builtin types such as float and int cannot be either +coerce_type_error.m:070: coerced from, or coerced to. coerce_type_error.m:091: In clause for predicate `bad_higher_order'/2: coerce_type_error.m:091: error: cannot coerce `X' from coerce_type_error.m:091: `coerce_type_error.wrap_ho(coerce_type_error.citrus)' diff --git a/tests/invalid/coerce_unify_tvars.err_exp b/tests/invalid/coerce_unify_tvars.err_exp index 7e3294902..ef2d295c2 100644 --- a/tests/invalid/coerce_unify_tvars.err_exp +++ b/tests/invalid/coerce_unify_tvars.err_exp @@ -1,3 +1,5 @@ coerce_unify_tvars.m:063: In clause for predicate `head_type_params'/2: coerce_unify_tvars.m:063: error: cannot coerce `X' from `list.list(V_1)' to coerce_unify_tvars.m:063: `list.list(V_2)'. +coerce_unify_tvars.m:063: Type variables such as T2 and T1 cannot be either +coerce_unify_tvars.m:063: coerced from, or coerced to.