[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