[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