[m-rev.] for review: improve error message for unresolved overloading

Peter Wang novalazy at gmail.com
Mon Sep 1 11:45:23 AEST 2008


Branches: main

compiler/pred_table.m:
	Improve the error message from `find_matching_pred_id' when it's unable
	to resolve predicate overloading.  Instead of telling the user to
	compile with -V, tell the user the location of the call and which
	predicates were matched.

compiler/intermod.m:
compiler/modes.m:
compiler/post_typecheck.m:
compiler/purity.m:
	Add the context arguments needed for calls to `find_matching_pred_id'.

tests/invalid/Mmakefile:
tests/invalid/unresolved_overloading.err_exp:
tests/invalid/unresolved_overloading.m:
	Add test case.

diff --git a/compiler/intermod.m b/compiler/intermod.m
index 38a41c8..086eda6 100644
--- a/compiler/intermod.m
+++ b/compiler/intermod.m
@@ -884,8 +884,8 @@ qualify_instance_method(ModuleInfo, MethodCallPredId - InstanceMethod0,
         (
             find_func_matching_instance_method(ModuleInfo, InstanceMethodName0,
                 MethodArity, MethodCallTVarSet, MethodCallExistQTVars,
-                MethodCallArgTypes, MethodCallHeadTypeParams, MaybePredId,
-                InstanceMethodName)
+                MethodCallArgTypes, MethodCallHeadTypeParams, MethodContext,
+                MaybePredId, InstanceMethodName)
         ->
             (
                 MaybePredId = yes(PredId),
@@ -909,8 +909,8 @@ qualify_instance_method(ModuleInfo, MethodCallPredId - InstanceMethod0,
         init_markers(Markers),
         resolve_pred_overloading(ModuleInfo, Markers, MethodCallTVarSet,
             MethodCallExistQTVars, MethodCallArgTypes,
-            MethodCallHeadTypeParams, InstanceMethodName0, InstanceMethodName,
-            PredId),
+            MethodCallHeadTypeParams, MethodContext,
+            InstanceMethodName0, InstanceMethodName, PredId),
         PredIds = [PredId | PredIds0],
         InstanceMethodDefn = instance_proc_def_name(InstanceMethodName)
     ;
@@ -935,12 +935,13 @@ qualify_instance_method(ModuleInfo, MethodCallPredId - InstanceMethod0,
     %
 :- pred find_func_matching_instance_method(module_info::in, sym_name::in,
     arity::in, tvarset::in, existq_tvars::in, list(mer_type)::in,
-    head_type_params::in, maybe(pred_id)::out, sym_name::out) is semidet.
+    head_type_params::in, prog_context::in, maybe(pred_id)::out,
+    sym_name::out) is semidet.
 
 find_func_matching_instance_method(ModuleInfo, InstanceMethodName0,
         MethodArity, MethodCallTVarSet, MethodCallExistQTVars,
-        MethodCallArgTypes, MethodCallHeadTypeParams, MaybePredId,
-        InstanceMethodName) :-
+        MethodCallArgTypes, MethodCallHeadTypeParams, MethodContext,
+        MaybePredId, InstanceMethodName) :-
 
     module_info_get_ctor_field_table(ModuleInfo, CtorFieldTable),
     (
@@ -976,7 +977,8 @@ find_func_matching_instance_method(ModuleInfo, InstanceMethodName0,
             MethodArity, PredIds),
         find_matching_pred_id(ModuleInfo, PredIds, MethodCallTVarSet,
             MethodCallExistQTVars, MethodCallArgTypes,
-            MethodCallHeadTypeParams, no, PredId, InstanceMethodFuncName)
+            MethodCallHeadTypeParams, no, MethodContext,
+            PredId, InstanceMethodFuncName)
     ->
         TypeCtors = [],
         MaybePredId = yes(PredId),
@@ -1183,8 +1185,9 @@ resolve_user_special_pred_overloading(ModuleInfo, SpecialId,
     pred_info_get_head_type_params(UnifyPredInfo, HeadTypeParams),
     init_markers(Markers0),
     add_marker(marker_calls_are_fully_qualified, Markers0, Markers),
+    pred_info_get_context(UnifyPredInfo, Context),
     resolve_pred_overloading(ModuleInfo, Markers, TVarSet, ExistQVars,
-        ArgTypes, HeadTypeParams, Pred0, Pred, UserEqPredId),
+        ArgTypes, HeadTypeParams, Context, Pred0, Pred, UserEqPredId),
     add_proc(UserEqPredId, _, !Info).
 
 :- pred should_write_type(module_name::in, type_ctor::in, hlds_type_defn::in)
diff --git a/compiler/modes.m b/compiler/modes.m
index 4e523df..aaf75ed 100644
--- a/compiler/modes.m
+++ b/compiler/modes.m
@@ -3490,7 +3490,7 @@ build_call(CalleeModuleName, CalleePredName, ArgVars, ArgTypes, NonLocals,
     SymName = qualified(CalleeModuleName, CalleePredName),
     get_pred_id_and_proc_id_by_types(is_fully_qualified, SymName, pf_predicate,
         TVarSet, ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo0,
-        CalleePredId, CalleeProcId),
+        Context, CalleePredId, CalleeProcId),
     module_info_pred_proc_info(ModuleInfo0, CalleePredId, CalleeProcId,
         CalleePredInfo, CalleeProcInfo),
 
diff --git a/compiler/post_typecheck.m b/compiler/post_typecheck.m
index 96e20ed..276b43b 100644
--- a/compiler/post_typecheck.m
+++ b/compiler/post_typecheck.m
@@ -96,8 +96,8 @@
     % Handle any unresolved overloading for a predicate call.
     %
 :- pred finally_resolve_pred_overloading(list(prog_var)::in,
-    pred_info::in, module_info::in, sym_name::in, sym_name::out,
-    pred_id::in, pred_id::out) is det.
+    pred_info::in, module_info::in, prog_context::in,
+    sym_name::in, sym_name::out, pred_id::in, pred_id::out) is det.
 
     % Work out whether a var-functor unification is actually a function call.
     % If so, replace the unification goal with a call.
@@ -424,8 +424,8 @@ var_and_type_to_pieces(VarSet, TVarSet, Var - Type) =
 
 %-----------------------------------------------------------------------------%
 
-finally_resolve_pred_overloading(Args0, CallerPredInfo, ModuleInfo, !PredName,
-        !PredId) :-
+finally_resolve_pred_overloading(Args0, CallerPredInfo, ModuleInfo, Context,
+        !PredName, !PredId) :-
     % In the case of a call to an overloaded predicate, typecheck.m
     % does not figure out the correct pred_id. We must do that here.
 
@@ -440,7 +440,7 @@ finally_resolve_pred_overloading(Args0, CallerPredInfo, ModuleInfo, !PredName,
         clauses_info_get_vartypes(ClausesInfo, VarTypes),
         map.apply_to_list(Args0, VarTypes, ArgTypes),
         resolve_pred_overloading(ModuleInfo, Markers, TVarSet, ExistQVars,
-            ArgTypes, HeadTypeParams, !PredName, !:PredId)
+            ArgTypes, HeadTypeParams, Context, !PredName, !:PredId)
     ;
         !:PredName = get_qualified_pred_name(ModuleInfo, !.PredId)
     ).
@@ -988,9 +988,10 @@ resolve_unify_functor(X0, ConsId0, ArgVars0, Mode0, Unification0, UnifyContext,
         GoalPath = goal_info_get_goal_path(GoalInfo0),
         ConstraintSearch =
             search_hlds_constraint_list(ConstraintMap, unproven, GoalPath),
+        Context = goal_info_get_context(GoalInfo0),
         find_matching_pred_id(ModuleInfo, PredIds, TVarSet, ExistQTVars,
-            ArgTypes, HeadTypeParams, yes(ConstraintSearch), PredId,
-            QualifiedFuncName)
+            ArgTypes, HeadTypeParams, yes(ConstraintSearch), Context,
+            PredId, QualifiedFuncName)
     ->
         % Convert function calls into predicate calls:
         % replace `X = f(A, B, C)' with `f(A, B, C, X)'.
@@ -1021,9 +1022,10 @@ resolve_unify_functor(X0, ConsId0, ArgVars0, Mode0, Unification0, UnifyContext,
         pred_info_get_exist_quant_tvars(!.PredInfo, ExistQVars),
         pred_info_get_head_type_params(!.PredInfo, HeadTypeParams),
         pred_info_get_markers(!.PredInfo, Markers),
+        Context = goal_info_get_context(GoalInfo0),
         get_pred_id_by_types(calls_are_fully_qualified(Markers), Name,
             PredOrFunc, TVarSet, ExistQVars, AllArgTypes, HeadTypeParams,
-            ModuleInfo, PredId)
+            ModuleInfo, Context, PredId)
     ->
         module_info_pred_info(ModuleInfo, PredId, PredInfo),
         ProcIds = pred_info_procids(PredInfo),
diff --git a/compiler/pred_table.m b/compiler/pred_table.m
index f4669ac..e7bf311 100644
--- a/compiler/pred_table.m
+++ b/compiler/pred_table.m
@@ -31,6 +31,7 @@
 :- implementation.
 
 :- import_module libs.compiler_util.
+:- import_module parse_tree.error_util.
 :- import_module parse_tree.prog_out.
 :- import_module parse_tree.prog_type.
 
@@ -253,7 +254,7 @@
     % 
 :- pred resolve_pred_overloading(module_info::in, pred_markers::in,
     tvarset::in, existq_tvars::in, list(mer_type)::in, head_type_params::in,
-    sym_name::in, sym_name::out, pred_id::out) is det.
+    prog_context::in, sym_name::in, sym_name::out, pred_id::out) is det.
 
     % Find a predicate or function from the list of pred_ids which matches the
     % given name and argument types.  If the constraint_search argument is
@@ -264,7 +265,7 @@
 :- pred find_matching_pred_id(module_info::in, list(pred_id)::in,
     tvarset::in, existq_tvars::in, list(mer_type)::in, head_type_params::in,
     maybe(constraint_search)::in(maybe(constraint_search)),
-    pred_id::out, sym_name::out) is semidet.
+    prog_context::in, pred_id::out, sym_name::out) is semidet.
 
     % A means to check that the required constraints are available, without
     % knowing in advance how many are required.
@@ -277,14 +278,16 @@
     %
 :- pred get_pred_id_and_proc_id_by_types(is_fully_qualified::in, sym_name::in,
     pred_or_func::in, tvarset::in, existq_tvars::in, list(mer_type)::in,
-    head_type_params::in, module_info::in, pred_id::out, proc_id::out) is det.
+    head_type_params::in, module_info::in, prog_context::in,
+    pred_id::out, proc_id::out) is det.
 
     % Get the pred_id matching a higher-order term with
     % the given argument types, failing if none is found.
     %
 :- pred get_pred_id_by_types(is_fully_qualified::in, sym_name::in,
     pred_or_func::in, tvarset::in, existq_tvars::in, list(mer_type)::in,
-    head_type_params::in, module_info::in, pred_id::out) is semidet.
+    head_type_params::in, module_info::in, prog_context::in, pred_id::out)
+    is semidet.
 
     % Given a pred_id, return the single proc_id, aborting
     % if there are no modes or more than one mode.
@@ -956,7 +959,7 @@ insert_into_mna_index(Name, Arity, PredId, Module, !MNA_Index) :-
 %-----------------------------------------------------------------------------%
 
 resolve_pred_overloading(ModuleInfo, CallerMarkers, TVarSet, ExistQTVars,
-        ArgTypes, HeadTypeParams, PredName0, PredName, PredId) :-
+        ArgTypes, HeadTypeParams, Context, PredName0, PredName, PredId) :-
     % Note: calls to preds declared in `.opt' files should always be
     % module qualified, so they should not be considered
     % when resolving overloading.
@@ -975,7 +978,7 @@ resolve_pred_overloading(ModuleInfo, CallerMarkers, TVarSet, ExistQTVars,
     % which subsume the actual argument/return types of this function call.
     (
         find_matching_pred_id(ModuleInfo, PredIds, TVarSet, ExistQTVars,
-            ArgTypes, HeadTypeParams, no, PredId1, PredName1)
+            ArgTypes, HeadTypeParams, no, Context, PredId1, PredName1)
     ->
         PredId = PredId1,
         PredName = PredName1
@@ -985,9 +988,9 @@ resolve_pred_overloading(ModuleInfo, CallerMarkers, TVarSet, ExistQTVars,
         unexpected(this_file, "type error in pred call: no matching pred")
     ).
 
-find_matching_pred_id(ModuleInfo, [PredId | PredIds],
-        TVarSet, ExistQTVars, ArgTypes, HeadTypeParams,
-        MaybeConstraintSearch, ThePredId, PredName) :-
+find_matching_pred_id(ModuleInfo, [PredId | PredIds], TVarSet, ExistQTVars,
+        ArgTypes, HeadTypeParams, MaybeConstraintSearch, Context,
+        ThePredId, PredName) :-
     (
         % Lookup the argument types of the candidate predicate
         % (or the argument types + return type of the candidate function).
@@ -1020,22 +1023,31 @@ find_matching_pred_id(ModuleInfo, [PredId | PredIds],
         PredName = qualified(Module, PName),
         (
             find_matching_pred_id(ModuleInfo, PredIds, TVarSet, ExistQTVars,
-                ArgTypes, HeadTypeParams, MaybeConstraintSearch, _OtherPredId,
-                _)
+                ArgTypes, HeadTypeParams, MaybeConstraintSearch, Context,
+                OtherPredId, _OtherPredName)
         ->
-            % XXX this should report an error properly, not
-            % via error/1
-            unexpected(this_file, "Type error in predicate call: " ++
-                "unresolvable predicate overloading. " ++
-                "You need to use an explicit module qualifier. " ++
-                "Compile with -V to find out where.")
+            module_info_pred_info(ModuleInfo, OtherPredId, OtherPredInfo),
+            pred_info_get_call_id(PredInfo, PredCallId),
+            pred_info_get_call_id(OtherPredInfo, OtherPredCallId),
+            % XXX this is not very nice
+            trace [io(!IO)] (
+                Pieces = [
+                    words("Error: unresolved predicate overloading, matched"),
+                    simple_call(PredCallId), words("and"),
+                    simple_call(OtherPredCallId), suffix("."),
+                    words("You need to use an explicit module qualifier."),
+                    nl],
+                write_error_pieces(Context, 0, Pieces, !IO)
+            ),
+            unexpected(this_file,
+                "find_matching_pred_id: unresolvable predicate overloading")
         ;
             ThePredId = PredId
         )
     ;
         find_matching_pred_id(ModuleInfo, PredIds, TVarSet, ExistQTVars,
-            ArgTypes, HeadTypeParams, MaybeConstraintSearch, ThePredId,
-            PredName)
+            ArgTypes, HeadTypeParams, MaybeConstraintSearch, Context,
+            ThePredId, PredName)
     ).
 
     % Check that the universal constraints proven in the caller match the
@@ -1060,7 +1072,7 @@ univ_constraints_match([ProvenConstraint | ProvenConstraints],
     univ_constraints_match(ProvenConstraints, CalleeConstraints).
 
 get_pred_id_by_types(IsFullyQualified, SymName, PredOrFunc, TVarSet,
-        ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo, PredId) :-
+        ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo, Context, PredId) :-
     module_info_get_predicate_table(ModuleInfo, PredicateTable),
     list.length(ArgTypes, Arity),
     (
@@ -1068,7 +1080,7 @@ get_pred_id_by_types(IsFullyQualified, SymName, PredOrFunc, TVarSet,
             PredOrFunc, SymName, Arity, PredIds),
         % Resolve overloading using the argument types.
         find_matching_pred_id(ModuleInfo, PredIds, TVarSet, ExistQTVars,
-            ArgTypes, HeadTypeParams, no, PredId0, _PredName)
+            ArgTypes, HeadTypeParams, no, Context, PredId0, _PredName)
     ->
         PredId = PredId0
     ;
@@ -1077,11 +1089,12 @@ get_pred_id_by_types(IsFullyQualified, SymName, PredOrFunc, TVarSet,
     ).
 
 get_pred_id_and_proc_id_by_types(IsFullyQualified, SymName, PredOrFunc,
-        TVarSet, ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo, PredId,
-        ProcId) :-
+        TVarSet, ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo, Context,
+        PredId, ProcId) :-
     (
         get_pred_id_by_types(IsFullyQualified, SymName, PredOrFunc, TVarSet,
-            ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo, PredId0)
+            ExistQTVars, ArgTypes, HeadTypeParams, ModuleInfo, Context,
+            PredId0)
     ->
         PredId = PredId0
     ;
diff --git a/compiler/purity.m b/compiler/purity.m
index 39b09b3..99b8ad4 100644
--- a/compiler/purity.m
+++ b/compiler/purity.m
@@ -541,10 +541,11 @@ compute_expr_purity(GoalExpr0, GoalExpr, GoalInfo, Purity, ContainsTrace,
         RunPostTypecheck = !.Info ^ pi_run_post_typecheck,
         PredInfo = !.Info ^ pi_pred_info,
         ModuleInfo = !.Info ^ pi_module_info,
+        CallContext = goal_info_get_context(GoalInfo),
         (
             RunPostTypecheck = run_post_typecheck,
             finally_resolve_pred_overloading(ArgVars, PredInfo, ModuleInfo,
-                SymName0, SymName, PredId0, PredId),
+                CallContext, SymName0, SymName, PredId0, PredId),
             (
                 % Convert any calls to private_builtin.unsafe_type_cast
                 % into unsafe_type_cast generic calls.
@@ -564,7 +565,6 @@ compute_expr_purity(GoalExpr0, GoalExpr, GoalInfo, Purity, ContainsTrace,
             GoalExpr = GoalExpr0
         ),
         DeclaredPurity = goal_info_get_purity(GoalInfo),
-        CallContext = goal_info_get_context(GoalInfo),
         perform_goal_purity_checks(CallContext, PredId,
             DeclaredPurity, ActualPurity, !Info),
         Purity = ActualPurity,
@@ -929,6 +929,7 @@ check_higher_order_purity(GoalInfo, ConsId, Var, Args, ActualPurity, !Info) :-
     % variable's type.
     VarTypes = !.Info ^ pi_vartypes,
     map.lookup(VarTypes, Var, TypeOfVar),
+    Context = goal_info_get_context(GoalInfo),
     (
         ConsId = cons(PName, _),
         type_is_higher_order_details(TypeOfVar, TypePurity, PredOrFunc,
@@ -945,7 +946,7 @@ check_higher_order_purity(GoalInfo, ConsId, Var, Args, ActualPurity, !Info) :-
         (
             get_pred_id_by_types(calls_are_fully_qualified(CallerMarkers),
                 PName, PredOrFunc, TVarSet, ExistQTVars, PredArgTypes,
-                HeadTypeParams, ModuleInfo, CalleePredId)
+                HeadTypeParams, ModuleInfo, Context, CalleePredId)
         ->
             module_info_pred_info(ModuleInfo, CalleePredId, CalleePredInfo),
             pred_info_get_purity(CalleePredInfo, CalleePurity),
@@ -970,7 +971,6 @@ check_higher_order_purity(GoalInfo, ConsId, Var, Args, ActualPurity, !Info) :-
         DeclaredPurity \= purity_pure,
         !.Info ^ pi_implicit_purity = dont_make_implicit_promises
     ->
-        Context = goal_info_get_context(GoalInfo),
         Spec = impure_unification_expr_error(Context, DeclaredPurity),
         purity_info_add_message(Spec, !Info)
     ;
diff --git a/tests/invalid/Mmakefile b/tests/invalid/Mmakefile
index 2e3f29c..e31f26b 100644
--- a/tests/invalid/Mmakefile
+++ b/tests/invalid/Mmakefile
@@ -23,7 +23,8 @@ MULTIMODULE_PROGS= \
 	test_nested \
 	transitive_import \
 	transitive_import_class \
-	undef_mod_qual
+	undef_mod_qual \
+	unresolved_overloading
 
 SINGLEMODULE= \
 	actual_expected \
diff --git a/tests/invalid/unresolved_overloading.err_exp b/tests/invalid/unresolved_overloading.err_exp
new file mode 100644
index 0000000..0fcc92d
--- /dev/null
+++ b/tests/invalid/unresolved_overloading.err_exp
@@ -0,0 +1,8 @@
+unresolved_overloading.m:021: Error: unresolved predicate overloading, matched
+unresolved_overloading.m:021:   predicate
+unresolved_overloading.m:021:   `unresolved_overloading.sub.loud_and_annoying'/3
+unresolved_overloading.m:021:   and predicate
+unresolved_overloading.m:021:   `unresolved_overloading.loud_and_annoying'/3.
+unresolved_overloading.m:021:   You need to use an explicit module qualifier.
+Uncaught Mercury exception:
+Software Error: pred_table.m: Unexpected: find_matching_pred_id: unresolvable predicate overloading
diff --git a/tests/invalid/unresolved_overloading.m b/tests/invalid/unresolved_overloading.m
new file mode 100644
index 0000000..8988066
--- /dev/null
+++ b/tests/invalid/unresolved_overloading.m
@@ -0,0 +1,52 @@
+% Test that the compiler gives a half decent error message when it's unable to
+% resolve predicate overloading in this module.
+
+:- module unresolved_overloading.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module unresolved_overloading.sub.
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+    loud_and_annoying(gibbon, !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- typeclass gibbon(T) where [].
+
+:- type gibbon ---> gibbon.
+:- instance gibbon(gibbon) where [].
+
+:- pred loud_and_annoying(T::in, io::di, io::uo) is det <= gibbon(T).
+
+loud_and_annoying(_, !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- module unresolved_overloading.sub.
+:- interface.
+
+:- import_module io.
+
+:- typeclass howler_monkey(T) where [].
+
+:- pred loud_and_annoying(T::in, io::di, io::uo) is det <= howler_monkey(T).
+
+:- implementation.
+
+loud_and_annoying(_, !IO).
+
+:- end_module unresolved_overloading.sub.
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et

--------------------------------------------------------------------------
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