[m-rev.] for review: improve typeclass constraints error messages
Peter Wang
novalazy at gmail.com
Wed Aug 19 12:56:35 AEST 2009
On 2009-08-18, Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
>
> One suggestion:
>
> It might be nicer to say what the goals are, for example instead of
>
> a goal here, and
> a goal here.
>
> this:
> the call to foo/4, and
> the unification between `X' and `Y'.
>
>
> The diff looks fine otherwise.
That sounds like too much work so I attempted it only for some calls.
Committed with these changes.
diff --git a/compiler/post_typecheck.m b/compiler/post_typecheck.m
index 94eac3e..7d00e4f 100644
--- a/compiler/post_typecheck.m
+++ b/compiler/post_typecheck.m
@@ -373,9 +373,10 @@ report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, Constraints,
"The constraint is due to:",
"The constraints are due to:"),
ContextMsgStart = error_msg(yes(Context), do_not_treat_as_first, 0,
- [always([fixed(DueTo)])]),
- Contexts = find_constraint_contexts(PredInfo, Constraints),
- ContextMsgs = constraint_contexts_to_error_msgs(Contexts),
+ [always([words(DueTo)])]),
+ ConstrainedGoals = find_constrained_goals(PredInfo, Constraints),
+ ContextMsgs = constrained_goals_to_error_msgs(ModuleInfo,
+ ConstrainedGoals),
Spec = error_spec(severity_error, phase_type_check,
[Msg, ContextMsgStart | ContextMsgs]),
@@ -390,12 +391,12 @@ constraint_to_error_piece(TVarset, Constraint) =
% A prog_constraint cannot contain context information (see the comment on
% the type definition). However, a constraint_id happens to contain a
% goal_path so we can look up a constraint_id for a prog_constraint, then
- % use the goal_path to reach the goal to get the context.
+ % use the goal_path to reach the goal.
%
-:- func find_constraint_contexts(pred_info, list(prog_constraint))
- = list(prog_context).
+:- func find_constrained_goals(pred_info, list(prog_constraint))
+ = list(hlds_goal).
-find_constraint_contexts(PredInfo, Constraints) = Contexts :-
+find_constrained_goals(PredInfo, Constraints) = Goals :-
pred_info_get_clauses_info(PredInfo, ClausesInfo),
clauses_info_clauses_only(ClausesInfo, Clauses),
@@ -405,38 +406,80 @@ find_constraint_contexts(PredInfo, Constraints) = Contexts :-
ConstraintIds = set.union_list(ConstraintIdSets),
% This could be more efficient.
- FindContexts = (pred(Context::out) is nondet :-
+ FindGoals = (pred(Goal::out) is nondet :-
set.member(ConstraintId, ConstraintIds),
ConstraintId = constraint_id(_, ConstraintGoalPath, _),
- promise_equivalent_solutions [Context] (
+ promise_equivalent_solutions [Goal] (
list.member(Clause, Clauses),
goal_contains_goal(Clause ^ clause_body, Goal),
Goal = hlds_goal(_, GoalInfo),
GoalPath = goal_info_get_goal_path(GoalInfo),
- GoalPath = ConstraintGoalPath,
- Context = goal_info_get_context(GoalInfo)
+ GoalPath = ConstraintGoalPath
)
),
- solutions(FindContexts, Contexts).
+ solutions(FindGoals, Goals).
-:- func constraint_contexts_to_error_msgs(list(prog_context))
+:- func constrained_goals_to_error_msgs(module_info, list(hlds_goal))
= list(error_msg).
-constraint_contexts_to_error_msgs([]) = [].
-constraint_contexts_to_error_msgs([Context | Contexts]) = [Msg | Msgs] :-
+constrained_goals_to_error_msgs(_, []) = [].
+constrained_goals_to_error_msgs(ModuleInfo, [Goal | Goals]) = [Msg | Msgs] :-
(
- Contexts = [_, _ | _],
- Words = "a goal here,"
+ Goals = [_, _ | _],
+ Words = describe_constrained_goal(ModuleInfo, Goal),
+ Suffix = suffix(",")
;
- Contexts = [_],
- Words = "a goal here, and"
+ Goals = [_],
+ Words = describe_constrained_goal(ModuleInfo, Goal),
+ Suffix = suffix(", and")
;
- Contexts = [],
- Words = "a goal here."
+ Goals = [],
+ Words = describe_constrained_goal(ModuleInfo, Goal),
+ Suffix = suffix(".")
),
+ Goal = hlds_goal(_, GoalInfo),
+ Context = goal_info_get_context(GoalInfo),
Msg = error_msg(yes(Context), do_not_treat_as_first, 1,
- [always([fixed(Words)])]),
- Msgs = constraint_contexts_to_error_msgs(Contexts).
+ [always(Words ++ [Suffix])]),
+ Msgs = constrained_goals_to_error_msgs(ModuleInfo, Goals).
+
+:- func describe_constrained_goal(module_info, hlds_goal)
+ = list(format_component).
+
+describe_constrained_goal(ModuleInfo, Goal) = Pieces :-
+ Goal = hlds_goal(GoalExpr, _),
+ (
+ (
+ GoalExpr = plain_call(PredId, _, _, _, _, _),
+ CallPieces = describe_one_pred_name(ModuleInfo,
+ should_module_qualify, PredId)
+ ;
+ GoalExpr = generic_call(GenericCall, _, _, _),
+ GenericCall = class_method(_, _, _, SimpleCallId),
+ CallPieces = [simple_call(SimpleCallId)]
+ ;
+ GoalExpr = call_foreign_proc(_, PredId, _, _, _, _, _),
+ CallPieces = describe_one_pred_name(ModuleInfo,
+ should_module_qualify, PredId)
+ ),
+ Pieces = [words("the call to") | CallPieces]
+ ;
+ GoalExpr = generic_call(higher_order(_, _, _, _), _, _, _),
+ Pieces = [words("a higher-order call here")]
+ ;
+ ( GoalExpr = generic_call(event_call(_), _, _, _)
+ ; GoalExpr = generic_call(cast(_), _, _, _)
+ ; GoalExpr = unify(_, _, _, _, _)
+ ; GoalExpr = conj(_, _)
+ ; GoalExpr = disj(_)
+ ; GoalExpr = switch(_, _, _)
+ ; GoalExpr = negation(_)
+ ; GoalExpr = scope(_, _)
+ ; GoalExpr = if_then_else(_, _, _, _)
+ ; GoalExpr = shorthand(_)
+ ),
+ Pieces = [words("a goal here")]
+ ).
%-----------------------------------------------------------------------------%
diff --git a/tests/invalid/typeclass_test_8.err_exp b/tests/invalid/typeclass_test_8.err_exp
index d610001..cb58178 100644
--- a/tests/invalid/typeclass_test_8.err_exp
+++ b/tests/invalid/typeclass_test_8.err_exp
@@ -14,5 +14,7 @@ typeclass_test_8.m:004: In predicate `main'/2:
typeclass_test_8.m:004: type error: unsatisfied typeclass constraint:
typeclass_test_8.m:004: `typeclass_test_8.fooable(T)'
typeclass_test_8.m:004: The constraint is due to:
-typeclass_test_8.m:013: a goal here, and
-typeclass_test_8.m:014: a goal here.
+typeclass_test_8.m:013: the call to type class predicate method
+typeclass_test_8.m:013: `typeclass_test_8.foo'/1, and
+typeclass_test_8.m:014: the call to type class predicate method
+typeclass_test_8.m:014: `typeclass_test_8.bar'/1.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list