[m-rev.] for review: Fix bug with typechecking of coercions.
Peter Wang
novalazy at gmail.com
Mon Jul 1 16:52:44 AEST 2024
Fix a problem where the order that the coercions are typechecked
can cause type variables to be bound differently.
For example, assuming citrus =< fruit:
X = [] : list(T),
coerce(X) = _ : list(fruit),
coerce(X) = _ : list(citrus)
T could end up bound to either 'fruit' or 'citrus' depending on which
coercion is checked first, due to unification of the type variable in
the coerce argument type, and the target type of the coercion.
This is clearly wrong. Moreover, there is no reason that 'fruit' and
'citrus' are the only possibilities for T; there could be another
subtype for 'fruit' as well.
The fix here is to delay checking of any coercion until its argument
type is resolved, and to reject any coercion whose argument type
remains unresolved.
compiler/type_assign.m:
Add status for coercion that could not be satisfied due to an
unresolved type. Rename an existing constructor.
Fix a comment.
compiler/typecheck_clauses.m:
When checking coerce constraints after typechecking a clause,
keep delaying any coercions with a non-ground "from" type.
This prevents the problem, which is that a type variable in the
"from" type of a coercion is unified with a type from the "to" type,
affecting coercions processed later which also would bind the same
type variable.
If we cannot make progress on a set of delayed coercions, then mark
all those coercions as unsatisfiable due to the argument type being
unresolved.
compiler/typecheck.m:
Generate errors for coercions with unresolved types.
compiler/typecheck_errors.m:
Add predicate for reporting coercions with unresolved types.
Add "error:" prefix to invalid coercion errors.
tests/invalid/coerce_ambig.m
Delete out-of-date comments.
tests/invalid/coerce_ambig.err_exp
tests/invalid/coerce_infer.err_exp
tests/invalid/coerce_non_du.err_exp
tests/invalid/coerce_type_error.err_exp
tests/invalid/coerce_unify_tvars.err_exp
tests/invalid/coerce_void.err_exp
Update expected outputs.
diff --git a/compiler/type_assign.m b/compiler/type_assign.m
index 8faac5965..6788de0c6 100644
--- a/compiler/type_assign.m
+++ b/compiler/type_assign.m
@@ -58,7 +58,7 @@
:- type coerce_constraint
---> coerce_constraint(
- % One or both sides should be a type_variable.
+ % One or both sides should contain a type variable.
coerce_from :: mer_type,
coerce_to :: mer_type,
coerce_context :: prog_context,
@@ -67,7 +67,8 @@
:- type coerce_constraint_status
---> need_to_check
- ; unsatisfiable
+ ; unsatisfiable_invalid
+ ; unsatisfiable_unresolved
; satisfied_but_redundant.
:- pred type_assign_get_var_types(type_assign::in,
diff --git a/compiler/typecheck.m b/compiler/typecheck.m
index 74ed33ad8..73750e2b4 100644
--- a/compiler/typecheck.m
+++ b/compiler/typecheck.m
@@ -1065,9 +1065,13 @@ report_coercion(TypeAssign, Coercion, !Info) :-
Status = need_to_check,
unexpected($pred, "need to check")
;
- Status = unsatisfiable,
+ Status = unsatisfiable_invalid,
Spec = report_invalid_coerce_from_to(ClauseContext, Context, TVarSet,
FromType, ToType)
+ ;
+ Status = unsatisfiable_unresolved,
+ Spec = report_unresolved_coerce_from_to(ClauseContext, Context,
+ TVarSet, FromType, ToType)
;
Status = satisfied_but_redundant,
Spec = report_redundant_coerce(ClauseContext, Context, TVarSet,
diff --git a/compiler/typecheck_clauses.m b/compiler/typecheck_clauses.m
index f9cb66972..c7a7d1b8c 100644
--- a/compiler/typecheck_clauses.m
+++ b/compiler/typecheck_clauses.m
@@ -95,7 +95,6 @@
:- import_module parse_tree.vartypes.
:- import_module assoc_list.
-:- import_module bool.
:- import_module int.
:- import_module io.
:- import_module map.
@@ -1799,7 +1798,7 @@ typecheck_coerce_2(Context, FromVar, ToVar, TypeAssign0,
)
else
Coercion = coerce_constraint(FromType, ToType, Context,
- unsatisfiable),
+ unsatisfiable_invalid),
add_coerce_constraint(Coercion, TypeAssign0, TypeAssign)
),
!:TypeAssignSet = [TypeAssign | !.TypeAssignSet]
@@ -2503,8 +2502,8 @@ compare_types_corresponding(TypeTable, TVarSet, Comparison,
%---------------------------------------------------------------------------%
- % Remove satisfied coerce constraints from each type assignment,
- % then drop any type assignments with unsatisfied coerce constraints
+ % Check coerce constraints in each type assignment to see if they can be
+ % satisfied. Drop any type assignments with unsatisfied coerce constraints
% if there is at least one type assignment that does satisfy coerce
% constraints.
%
@@ -2534,65 +2533,112 @@ type_assign_prune_coerce_constraints(TypeTable, !TypeAssign) :-
Coercions0 = []
;
Coercions0 = [_ | _],
- check_pending_coerce_constraints(TypeTable, Coercions0, Coercions,
- !TypeAssign),
+ check_pending_coerce_constraints_to_fixpoint(TypeTable,
+ Coercions0, Coercions, !TypeAssign),
type_assign_set_coerce_constraints(Coercions, !TypeAssign)
).
-:- pred check_pending_coerce_constraints(type_table::in,
+:- pred check_pending_coerce_constraints_to_fixpoint(type_table::in,
list(coerce_constraint)::in, list(coerce_constraint)::out,
type_assign::in, type_assign::out) is det.
-check_pending_coerce_constraints(_TypeTable, [], [], !TypeAssign).
-check_pending_coerce_constraints(TypeTable, [Coercion0 | Coercions0],
- KeepCoercions, !TypeAssign) :-
+check_pending_coerce_constraints_to_fixpoint(TypeTable, Coercions0, Coercions,
+ !TypeAssign) :-
+ check_pending_coerce_constraints_loop(TypeTable, Coercions0,
+ KeepCoercions, DelayedCoercions, !TypeAssign),
+ ( if
+ KeepCoercions = [],
+ list.length(Coercions0) = list.length(DelayedCoercions) : int
+ then
+ % All coerce constraints were delayed; give up.
+ list.map(set_coerce_constraint_to_unresolved,
+ DelayedCoercions, Coercions)
+ else
+ check_pending_coerce_constraints_to_fixpoint(TypeTable,
+ DelayedCoercions, Coercions2, !TypeAssign),
+ Coercions = KeepCoercions ++ Coercions2
+ ).
+
+:- pred check_pending_coerce_constraints_loop(type_table::in,
+ list(coerce_constraint)::in, list(coerce_constraint)::out,
+ list(coerce_constraint)::out, type_assign::in, type_assign::out) is det.
+
+check_pending_coerce_constraints_loop(_TypeTable, [], [], [], !TypeAssign).
+check_pending_coerce_constraints_loop(TypeTable, [Coercion0 | Coercions0],
+ KeepCoercions, DelayedCoercions, !TypeAssign) :-
+ check_coerce_constraint_if_ready(TypeTable, Coercion0, CheckResult,
+ !TypeAssign),
+ (
+ CheckResult = prune,
+ check_pending_coerce_constraints_loop(TypeTable, Coercions0,
+ KeepCoercions, DelayedCoercions, !TypeAssign)
+ ;
+ CheckResult = keep(Coercion),
+ check_pending_coerce_constraints_loop(TypeTable, Coercions0,
+ TailKeepCoercions, DelayedCoercions, !TypeAssign),
+ KeepCoercions = [Coercion | TailKeepCoercions]
+ ;
+ CheckResult = delay,
+ check_pending_coerce_constraints_loop(TypeTable, Coercions0,
+ KeepCoercions, TailDelayedCoercions, !TypeAssign),
+ DelayedCoercions = [Coercion0 | TailDelayedCoercions]
+ ).
+
+:- type check_coerce_constraint_action
+ ---> prune
+ ; keep(coerce_constraint)
+ ; delay.
+
+:- pred check_coerce_constraint_if_ready(type_table::in, coerce_constraint::in,
+ check_coerce_constraint_action::out, type_assign::in, type_assign::out)
+ is det.
+
+check_coerce_constraint_if_ready(TypeTable, Coercion0, Action, !TypeAssign) :-
Coercion0 = coerce_constraint(FromType0, ToType0, Context, Status0),
(
Status0 = need_to_check,
TypeAssign0 = !.TypeAssign,
- type_assign_get_type_bindings(TypeAssign0, TypeBindings0),
type_assign_get_typevarset(TypeAssign0, TVarSet),
+ type_assign_get_existq_tvars(TypeAssign0, ExistQTVars),
+ type_assign_get_type_bindings(TypeAssign0, TypeBindings0),
apply_rec_subst_to_type(TypeBindings0, FromType0, FromType),
apply_rec_subst_to_type(TypeBindings0, ToType0, ToType),
- ( if
- typecheck_coerce_between_types(TypeTable, TVarSet,
- FromType, ToType, TypeAssign0, TypeAssign1)
- then
- type_assign_get_type_bindings(TypeAssign1, TypeBindings1),
- ( if is_same_type_after_subst(TypeBindings1, FromType, ToType) then
- Keep = yes,
- Coercion = coerce_constraint(FromType, ToType, Context,
- satisfied_but_redundant)
+ ( if type_is_ground_except_vars(FromType, ExistQTVars) then
+ ( if
+ typecheck_coerce_between_types(TypeTable, TVarSet,
+ FromType, ToType, TypeAssign0, TypeAssign1)
+ then
+ type_assign_get_type_bindings(TypeAssign1, TypeBindings1),
+ ( if is_same_type_after_subst(TypeBindings1, FromType, ToType) then
+ Coercion = coerce_constraint(FromType, ToType, Context,
+ satisfied_but_redundant),
+ Action = keep(Coercion)
+ else
+ Action = prune
+ ),
+ !:TypeAssign = TypeAssign1
else
- Keep = no,
- Coercion = Coercion0
- ),
- % XXX This biases the typechecker to type bindings made by coerce
- % constraints that happen to be processed earlier.
- !:TypeAssign = TypeAssign1
+ Coercion = coerce_constraint(FromType0, ToType0, Context,
+ unsatisfiable_invalid),
+ Action = keep(Coercion)
+ )
else
- Keep = yes,
- Coercion = coerce_constraint(FromType0, ToType0, Context,
- unsatisfiable)
+ Action = delay
)
;
- ( Status0 = unsatisfiable
+ ( Status0 = unsatisfiable_invalid
+ ; Status0 = unsatisfiable_unresolved
; Status0 = satisfied_but_redundant
),
- Keep = yes,
- Coercion = Coercion0
- ),
- (
- Keep = yes,
- check_pending_coerce_constraints(TypeTable, Coercions0,
- TailKeepCoercions, !TypeAssign),
- KeepCoercions = [Coercion | TailKeepCoercions]
- ;
- Keep = no,
- check_pending_coerce_constraints(TypeTable, Coercions0,
- KeepCoercions, !TypeAssign)
+ Action = keep(Coercion0)
).
+:- pred set_coerce_constraint_to_unresolved(coerce_constraint::in,
+ coerce_constraint::out) is det.
+
+set_coerce_constraint_to_unresolved(!Coercion) :-
+ !Coercion ^ coerce_status := unsatisfiable_unresolved.
+
:- pred type_assign_has_only_satisfied_coerce_constraints(type_assign::in)
is semidet.
@@ -2605,12 +2651,10 @@ type_assign_has_only_satisfied_coerce_constraints(TypeAssign) :-
coerce_constraint_is_satisfied(Coercion) :-
Coercion = coerce_constraint(_FromType, _ToType, _Context, Status),
require_complete_switch [Status]
- (
- Status = need_to_check, fail
- ;
- Status = unsatisfiable, fail
- ;
- Status = satisfied_but_redundant
+ ( Status = need_to_check, fail
+ ; Status = unsatisfiable_invalid, fail
+ ; Status = unsatisfiable_unresolved, fail
+ ; Status = satisfied_but_redundant
).
%---------------------------------------------------------------------------%
diff --git a/compiler/typecheck_errors.m b/compiler/typecheck_errors.m
index 035e3671a..c8234e550 100644
--- a/compiler/typecheck_errors.m
+++ b/compiler/typecheck_errors.m
@@ -44,6 +44,9 @@
:- func report_invalid_coerce_from_to(type_error_clause_context, prog_context,
tvarset, mer_type, mer_type) = error_spec.
+:- func report_unresolved_coerce_from_to(type_error_clause_context,
+ prog_context, tvarset, mer_type, mer_type) = error_spec.
+
:- func report_redundant_coerce(type_error_clause_context, prog_context,
tvarset, mer_type) = error_spec.
@@ -280,10 +283,11 @@ report_invalid_coerce_from_to(ClauseContext, Context, TVarSet,
% XXX TYPECHECK_ERRORS
% This code can generate some less-than-helpful diagnostics.
%
- % - For tests/invalid/coerce_infer.m and some others, it says that
+ % - For tests/invalid/coerce_unify_tvars.m and some others, it says that
% you cannot coerce from one anonymous type variable to another.
%
% Is there something we can report that would be more helpful?
+ % In most cases, we report that the coerced argument type is unresolved.
InClauseForPieces = in_clause_for_pieces(ClauseContext),
FromTypeStr = mercury_type_to_string(TVarSet, print_num_only, FromType),
ToTypeStr = mercury_type_to_string(TVarSet, print_num_only, ToType),
@@ -347,13 +351,25 @@ report_invalid_coerce_from_to(ClauseContext, Context, TVarSet,
)
)
),
- ErrorPieces = [words("cannot coerce from")] ++
+ ErrorPieces = [words("error: cannot coerce from")] ++
color_as_inconsistent([quote(FromTypeStr)]) ++ [words("to")] ++
color_as_inconsistent([quote(ToTypeStr), suffix(".")]) ++ [nl] ++
CausePieces ++ [nl],
Spec = spec($pred, severity_error, phase_type_check, Context,
InClauseForPieces ++ ErrorPieces).
+report_unresolved_coerce_from_to(ClauseContext, Context, TVarSet,
+ FromType, ToType) = Spec :-
+ InClauseForPieces = in_clause_for_pieces(ClauseContext),
+ FromTypeStr = mercury_type_to_string(TVarSet, print_num_only, FromType),
+ ToTypeStr = mercury_type_to_string(TVarSet, print_num_only, ToType),
+ ErrorPieces = [words("error: cannot coerce from")] ++
+ [quote(FromTypeStr), words("to"), quote(ToTypeStr), suffix("."), nl] ++
+ [words("The type of the coerced argument is")] ++
+ color_as_incorrect([words("unresolved.")]) ++ [nl],
+ Spec = spec($pred, severity_error, phase_type_check, Context,
+ InClauseForPieces ++ ErrorPieces).
+
report_redundant_coerce(ClauseContext, Context, TVarSet, FromType) = Spec :-
InClauseForPieces = in_clause_for_pieces(ClauseContext),
FromTypeStr = mercury_type_to_string(TVarSet, print_num_only, FromType),
diff --git a/tests/invalid/coerce_ambig.err_exp b/tests/invalid/coerce_ambig.err_exp
index 43b3df14e..55ac78b04 100644
--- a/tests/invalid/coerce_ambig.err_exp
+++ b/tests/invalid/coerce_ambig.err_exp
@@ -10,12 +10,16 @@ coerce_ambig.m:036: The following variables have ambiguous types:
coerce_ambig.m:036: The variable [38;5;87m`X'[39;49m can have either of the following types:
coerce_ambig.m:036: [38;5;226mcoerce_ambig.another_fruit,[39;49m
coerce_ambig.m:036: [38;5;226mcoerce_ambig.fruit.[39;49m
-coerce_ambig.m:044: In clause for predicate `ambig3'/1:
-coerce_ambig.m:044: warning: type conversion from
-coerce_ambig.m:044: `coerce_ambig.list(coerce_ambig.fruit)' to the same type
-coerce_ambig.m:044: is [38;5;203mredundant.[39;49m
-coerce_ambig.m:053: In clause for predicate `ambig4'/0:
-coerce_ambig.m:053: warning: type conversion from
-coerce_ambig.m:053: `coerce_ambig.list(coerce_ambig.fruit)' to the same type
-coerce_ambig.m:053: is [38;5;203mredundant.[39;49m
+coerce_ambig.m:043: In clause for predicate `ambig3'/1:
+coerce_ambig.m:043: error: cannot coerce from `coerce_ambig.list(V_1)' to
+coerce_ambig.m:043: `coerce_ambig.list(coerce_ambig.fruit)'.
+coerce_ambig.m:043: The type of the coerced argument is [38;5;203munresolved.[39;49m
+coerce_ambig.m:049: In clause for predicate `ambig4'/0:
+coerce_ambig.m:049: error: cannot coerce from `coerce_ambig.list(V_1)' to
+coerce_ambig.m:049: `coerce_ambig.list(coerce_ambig.citrus)'.
+coerce_ambig.m:049: The type of the coerced argument is [38;5;203munresolved.[39;49m
+coerce_ambig.m:050: In clause for predicate `ambig4'/0:
+coerce_ambig.m:050: error: cannot coerce from `coerce_ambig.list(V_1)' to
+coerce_ambig.m:050: `coerce_ambig.list(coerce_ambig.fruit)'.
+coerce_ambig.m:050: The type of the coerced argument is [38;5;203munresolved.[39;49m
For more information, recompile with `-E'.
diff --git a/tests/invalid/coerce_ambig.m b/tests/invalid/coerce_ambig.m
index 342f658d5..636b6b9f7 100644
--- a/tests/invalid/coerce_ambig.m
+++ b/tests/invalid/coerce_ambig.m
@@ -40,14 +40,11 @@ ambig2 :-
:- pred ambig3(list(fruit)::out) is det.
ambig3(Xs) :-
- % Not ambiguous after we unify list(_T) with list(fruit).
Xs = coerce([]).
:- pred ambig4 is det.
ambig4 :-
- % XXX The compiler wrongly picks X : list(fruit) or X : list(citrus)
- % when it has no reason to reject the other possibility.
X = [],
coerce(X) = _ : list(citrus),
coerce(X) = _ : list(fruit).
diff --git a/tests/invalid/coerce_infer.err_exp b/tests/invalid/coerce_infer.err_exp
index 92ee16f6b..e3e6331cb 100644
--- a/tests/invalid/coerce_infer.err_exp
+++ b/tests/invalid/coerce_infer.err_exp
@@ -1,4 +1,3 @@
coerce_infer.m:026: In clause for function `f'/1:
-coerce_infer.m:026: cannot coerce from [38;5;171m`V_1'[39;49m to [38;5;171m`V_2'.[39;49m
-coerce_infer.m:026: You can only coerce from one discriminated union type to
-coerce_infer.m:026: another, and `V_1' and `V_2' are [38;5;203mtype variables.[39;49m
+coerce_infer.m:026: error: cannot coerce from `V_1' to `V_2'.
+coerce_infer.m:026: The type of the coerced argument is [38;5;203munresolved.[39;49m
diff --git a/tests/invalid/coerce_non_du.err_exp b/tests/invalid/coerce_non_du.err_exp
index 121755890..8830a182c 100644
--- a/tests/invalid/coerce_non_du.err_exp
+++ b/tests/invalid/coerce_non_du.err_exp
@@ -1,21 +1,22 @@
coerce_non_du.m:015: In clause for function `f1'/1:
-coerce_non_du.m:015: cannot coerce from [38;5;171m`int'[39;49m to [38;5;171m`int'.[39;49m
+coerce_non_du.m:015: error: cannot coerce from [38;5;171m`int'[39;49m to [38;5;171m`int'.[39;49m
coerce_non_du.m:015: You can only coerce from one discriminated union type to
coerce_non_du.m:015: another, and `int' is a [38;5;203mbuiltin type.[39;49m
coerce_non_du.m:019: In clause for function `f2'/1:
-coerce_non_du.m:019: cannot coerce from [38;5;171m`float'[39;49m to [38;5;171m`float'.[39;49m
+coerce_non_du.m:019: error: cannot coerce from [38;5;171m`float'[39;49m to [38;5;171m`float'.[39;49m
coerce_non_du.m:019: You can only coerce from one discriminated union type to
coerce_non_du.m:019: another, and `float' is a [38;5;203mbuiltin type.[39;49m
coerce_non_du.m:023: In clause for function `f3'/1:
-coerce_non_du.m:023: cannot coerce from [38;5;171m`{}'[39;49m to [38;5;171m`{}'.[39;49m
+coerce_non_du.m:023: error: cannot coerce from [38;5;171m`{}'[39;49m to [38;5;171m`{}'.[39;49m
coerce_non_du.m:023: You can only coerce from one discriminated union type to
coerce_non_du.m:023: another, and `{}' is a [38;5;203mtuple type.[39;49m
coerce_non_du.m:027: In clause for function `f4'/1:
-coerce_non_du.m:027: cannot coerce from [38;5;171m`((func int) = int)'[39;49m to
+coerce_non_du.m:027: error: cannot coerce from [38;5;171m`((func int) = int)'[39;49m to
coerce_non_du.m:027: [38;5;171m`((func int) = int)'.[39;49m
coerce_non_du.m:027: You can only coerce from one discriminated union type to
coerce_non_du.m:027: another, and `((func int) = int)' is a [38;5;203mfunction type.[39;49m
coerce_non_du.m:031: In clause for function `f5'/1:
-coerce_non_du.m:031: cannot coerce from [38;5;171m`pred(int, int)'[39;49m to [38;5;171m`pred(int, int)'.[39;49m
+coerce_non_du.m:031: error: cannot coerce from [38;5;171m`pred(int, int)'[39;49m to
+coerce_non_du.m:031: [38;5;171m`pred(int, int)'.[39;49m
coerce_non_du.m:031: You can only coerce from one discriminated union type to
coerce_non_du.m:031: another, and `pred(int, int)' is a [38;5;203mpredicate type.[39;49m
diff --git a/tests/invalid/coerce_type_error.err_exp b/tests/invalid/coerce_type_error.err_exp
index d873b9772..ff670e9ae 100644
--- a/tests/invalid/coerce_type_error.err_exp
+++ b/tests/invalid/coerce_type_error.err_exp
@@ -1,22 +1,23 @@
coerce_type_error.m:045: In clause for predicate `bad_unrelated'/2:
-coerce_type_error.m:045: cannot coerce from
+coerce_type_error.m:045: error: cannot coerce from
coerce_type_error.m:045: [38;5;171m`coerce_type_error.orange_non_fruit'[39;49m to
coerce_type_error.m:045: [38;5;171m`coerce_type_error.citrus'.[39;49m
coerce_type_error.m:070: In clause for predicate `bad_phantom'/2:
-coerce_type_error.m:070: cannot coerce from [38;5;171m`coerce_type_error.phantom(int)'[39;49m
-coerce_type_error.m:070: to [38;5;171m`coerce_type_error.phantom(float)'.[39;49m
+coerce_type_error.m:070: error: cannot coerce from
+coerce_type_error.m:070: [38;5;171m`coerce_type_error.phantom(int)'[39;49m to
+coerce_type_error.m:070: [38;5;171m`coerce_type_error.phantom(float)'.[39;49m
coerce_type_error.m:091: In clause for predicate `bad_higher_order'/2:
-coerce_type_error.m:091: cannot coerce from
+coerce_type_error.m:091: error: cannot coerce from
coerce_type_error.m:091: [38;5;171m`coerce_type_error.wrap_ho(coerce_type_error.citrus)'[39;49m
coerce_type_error.m:091: to
coerce_type_error.m:091: [38;5;171m`coerce_type_error.wrap_ho(coerce_type_error.fruit)'.[39;49m
coerce_type_error.m:106: In clause for predicate `bad_foreign_type'/2:
-coerce_type_error.m:106: cannot coerce from
+coerce_type_error.m:106: error: cannot coerce from
coerce_type_error.m:106: [38;5;171m`coerce_type_error.wrap_ft(coerce_type_error.citrus)'[39;49m
coerce_type_error.m:106: to
coerce_type_error.m:106: [38;5;171m`coerce_type_error.wrap_ft(coerce_type_error.fruit)'.[39;49m
coerce_type_error.m:118: In clause for predicate `bad_abs_type'/2:
-coerce_type_error.m:118: cannot coerce from
+coerce_type_error.m:118: error: cannot coerce from
coerce_type_error.m:118: [38;5;171m`coerce_type_error.wrap_abs(coerce_type_error.citrus)'[39;49m
coerce_type_error.m:118: to
coerce_type_error.m:118: [38;5;171m`coerce_type_error.wrap_abs(coerce_type_error.fruit)'.[39;49m
diff --git a/tests/invalid/coerce_unify_tvars.err_exp b/tests/invalid/coerce_unify_tvars.err_exp
index 8ed2f6d26..8d5379f57 100644
--- a/tests/invalid/coerce_unify_tvars.err_exp
+++ b/tests/invalid/coerce_unify_tvars.err_exp
@@ -1,3 +1,3 @@
coerce_unify_tvars.m:063: In clause for predicate `head_type_params'/2:
-coerce_unify_tvars.m:063: cannot coerce from [38;5;171m`list.list(V_1)'[39;49m to
+coerce_unify_tvars.m:063: error: cannot coerce from [38;5;171m`list.list(V_1)'[39;49m to
coerce_unify_tvars.m:063: [38;5;171m`list.list(V_2)'.[39;49m
diff --git a/tests/invalid/coerce_void.err_exp b/tests/invalid/coerce_void.err_exp
index 021789c65..d096ed158 100644
--- a/tests/invalid/coerce_void.err_exp
+++ b/tests/invalid/coerce_void.err_exp
@@ -1,10 +1,4 @@
-coerce_void.m:010: Warning: [38;5;203munresolved polymorphism[39;49m in predicate [38;5;87m`main'/2.[39;49m
-coerce_void.m:010: The variables with unbound types were:
-coerce_void.m:010: [38;5;87m`List':[39;49m [38;5;203mlist.list(T),[39;49m
-coerce_void.m:010: [38;5;87m`V_8': [39;49m [38;5;203mlist.list(T).[39;49m
-coerce_void.m:010: The unbound type variable [38;5;203m`T'[39;49m will be implicitly bound to
-coerce_void.m:010: the builtin type `void'.
coerce_void.m:019: In clause for predicate `main'/2:
-coerce_void.m:019: warning: type conversion from `list.list(V_1)' to the same
-coerce_void.m:019: type is [38;5;203mredundant.[39;49m
-For more information, recompile with `-E'.
+coerce_void.m:019: error: cannot coerce from `list.list(V_2)' to
+coerce_void.m:019: `list.list(V_1)'.
+coerce_void.m:019: The type of the coerced argument is [38;5;203munresolved.[39;49m
--
2.44.0
More information about the reviews
mailing list