mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
compiler/typecheck_error_unify.m:
As above.
compiler/hlds_error_util.m:
compiler/typecheck_error_util.m:
Export operations that are now needed by typecheck_error_unify.m.
To make this possible, carve some of those operations out of
other operations.
tests/invalid/ho_type_arity_bug.err_exp:
tests/invalid/missing_closure_arg.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid_nodepend/errors_2.err_exp:
tests/invalid_purity/impure_func_t5.err_exp:
tests/invalid_purity/impure_pred_t1.err_exp:
Expect the updated diagnostics.
939 lines
38 KiB
Mathematica
939 lines
38 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2007, 2009-2012 The University of Melbourne.
|
|
% Copyright (C) 2014-2017, 2019-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: hlds_error_util.m.
|
|
% Main author: zs.
|
|
%
|
|
% This module contains code that can be helpful in the generation or
|
|
% formatting of error messages. It builds upon parse_tree.error_spec,
|
|
% and extends it with predicates that access HLDS data structures.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module hlds.hlds_error_util.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_markers.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module libs.
|
|
:- import_module libs.maybe_util.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.parse_tree_out_info.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.var_db.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module pair.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Predicates to convert predicate and procedure names to strings.
|
|
%
|
|
|
|
:- type should_module_qualify
|
|
---> should_module_qualify
|
|
; should_not_module_qualify.
|
|
|
|
% describe_qual_pred_name(ModuleInfo, PredId) = Spec:
|
|
% describe_unqual_pred_name(ModuleInfo, PredId) = Spec:
|
|
% describe_one_pred_name(ModuleInfo, MaybeColor, Qual, SuffixPieces,
|
|
% PredId) = Spec:
|
|
%
|
|
% Return a description of the given predicate or function. This
|
|
% description will have one of the forms
|
|
%
|
|
% predicate `symname'/arity
|
|
% function `symname'/arity
|
|
%
|
|
% in both cases followed by SuffixPieces.
|
|
%
|
|
% The Qual parameter governs whether the sym_name will contain
|
|
% its full module qualification, or none.
|
|
%
|
|
% If MaybeColor is yes(Color), then the initial "predicate" or "function"
|
|
% will not be in that color, but the`symname'/arity part, *and*
|
|
% the SuffixPieces, will be. (The reason for taking SuffixPieces
|
|
% as an argument is specifically intended to make this possible
|
|
% without redundant switches between colors.)
|
|
%
|
|
% For describe_qual_pred_name/describe_unqual_pred_name, MaybeColor
|
|
% is implicitly "no", SuffixPieces is [], and the value of Qual is
|
|
% given in the predicate name.
|
|
%
|
|
:- func describe_qual_pred_name(module_info, pred_id) = list(format_piece).
|
|
:- func describe_unqual_pred_name(module_info, pred_id) = list(format_piece).
|
|
:- func describe_one_pred_name(module_info, maybe(color_name),
|
|
should_module_qualify, list(format_piece), pred_id) = list(format_piece).
|
|
|
|
% describe_one_pred_info_name(MaybeColor, Qual, SuffixPieces, PredInfo)
|
|
% = Spec:
|
|
%
|
|
% Does the same job as describe_one_pred_name, except for letting the
|
|
% caller do the lookup of the pred_info.
|
|
%
|
|
:- func describe_one_pred_info_name(maybe(color_name), should_module_qualify,
|
|
list(format_piece), pred_info) = list(format_piece).
|
|
|
|
% describe_several_pred_names(ModuleInfo, MaybeColor, Qual, PredIds)
|
|
% = Spec:
|
|
%
|
|
% Invoke describe_one_pred_name on each of the given PredIds,
|
|
% and return the results of those invocations joined togther in a list
|
|
% with the final pair of predicate descriptions separated by "and".
|
|
% We pass the given MaybeColor and Qual, and [] as SuffixPieces,
|
|
% to each call to describe_one_pred_name. This is because it does not
|
|
% make sense to add the same suffix to the description of every pred.
|
|
% (Though it may make sense to add it to the last one.)
|
|
%
|
|
:- func describe_several_pred_names(module_info, maybe(color_name),
|
|
should_module_qualify, list(pred_id)) = list(format_piece).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% describe_one_proc_name_maybe_argmodes(ModuleInfo, Lang, MaybeColor,
|
|
% Qual, SuffixPieces, PredProcId) = Spec:
|
|
%
|
|
% Return a description of the given procedure.
|
|
%
|
|
% If the procedure is the only procedure in its predicate or function,
|
|
% the description will just a description of the predicate or function
|
|
% as constructed by describe_one_pred_name.
|
|
%
|
|
% If the procedure is NOT the only procedure in its predicate or function,
|
|
% then description will consist of the name of the predicate or function
|
|
% (module qualified if Qual is should_module_qualify), followed by
|
|
% the modes of its arguments. The result will look like one of these:
|
|
%
|
|
% `name(in, in, out)'
|
|
% `name(in, in) = out'
|
|
%
|
|
:- func describe_one_proc_name_maybe_argmodes(module_info, output_lang,
|
|
maybe(color_name), should_module_qualify, list(format_piece), pred_proc_id)
|
|
= list(format_piece).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% describe_qual_proc_name(ModuleInfo, PredProcId) = Spec:
|
|
% describe_unqual_proc_name(ModuleInfo, PredProcId) = Spec:
|
|
% describe_one_proc_name(ModuleInfo, MaybeColor, Qual, SuffixPieces,
|
|
% PredProcId) = Spec:
|
|
%
|
|
% Return a description of the given procedure. These descriptions
|
|
% will consist of a description of the predicate or function to which
|
|
% the procedure belongs (as constructed by describe_one_pred_name),
|
|
% followed by a suffix of the form "mode N".
|
|
%
|
|
:- func describe_qual_proc_name(module_info, pred_proc_id)
|
|
= list(format_piece).
|
|
:- func describe_unqual_proc_name(module_info, pred_proc_id)
|
|
= list(format_piece).
|
|
:- func describe_one_proc_name(module_info, maybe(color_name),
|
|
should_module_qualify, pred_proc_id) = list(format_piece).
|
|
|
|
% describe_several_proc_names(ModuleInfo, MaybeColor, Qual, PredProcIds)
|
|
% = Spec:
|
|
%
|
|
% Do the same job for procedures as describe_several_pred_names does
|
|
% for predicates and functions.
|
|
%
|
|
:- func describe_several_proc_names(module_info, maybe(color_name),
|
|
should_module_qualify, list(pred_proc_id)) = list(format_piece).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% describe_one_call_site(ModuleInfo, MaybeColor, Qual, Site) = Pieces:
|
|
%
|
|
% Return a description of a call site, which a pair consisting of the
|
|
% id of the callee, and the context of the call. The description
|
|
% will consist of the description of the callee as returned by
|
|
% describe_one_proc_name, followed by test of the form
|
|
% "at filename:linenumber".
|
|
%
|
|
:- func describe_one_call_site(module_info, maybe(color_name),
|
|
should_module_qualify, pair(pred_proc_id, prog_context))
|
|
= list(format_piece).
|
|
|
|
% describe_several_call_sites(ModuleInfo, MaybeColor, Qual, Sites)
|
|
% = Pieces:
|
|
%
|
|
% Invoke describe_one_call_site on each call site, and join the
|
|
% resulting descriptions together with commas and a final "and".
|
|
%
|
|
:- func describe_several_call_sites(module_info, maybe(color_name),
|
|
should_module_qualify, assoc_list(pred_proc_id, prog_context))
|
|
= list(format_piece).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type last_context_word
|
|
---> lcw_none
|
|
; lcw_call
|
|
; lcw_result
|
|
; lcw_argument
|
|
; lcw_element.
|
|
|
|
% unify_context_to_pieces generates a message such as
|
|
% foo.m:123: in argument 3 of functor `foo/5':
|
|
% foo.m:123: in unification of `X' and `blah':
|
|
% based on the unify_context and prog_context.
|
|
%
|
|
:- pred unify_context_to_pieces(unify_context::in, last_context_word::out,
|
|
list(format_piece)::in, list(format_piece)::out) is det.
|
|
|
|
% unify_context_first_to_pieces is the same as above, except that
|
|
% it also takes and returns a flag which specifies whether this is the
|
|
% start of a sentence. If the first argument is `is_first', then it means
|
|
% this is the first line of an error message, so the message starts with
|
|
% a capital letter, e.g.
|
|
% foo.m:123: In argument 3 of functor `foo/5':
|
|
% foo.m:123: in unification of `X' and `blah':
|
|
% The flag returned as the second argument will be `is_not_first'
|
|
% unless nothing was generated, in which case it will be the same
|
|
% as the first argument.
|
|
%
|
|
:- pred unify_context_first_to_pieces(is_first::in, is_first::out,
|
|
unify_context::in, last_context_word::out,
|
|
list(format_piece)::in, list(format_piece)::out) is det.
|
|
|
|
% Succeed iff the given cons_id either *does* represent list.[|],
|
|
% or (before typechecking has finished) *may* represent list.[|].
|
|
%
|
|
:- pred cons_id_may_be_list_cons(cons_id::in) is semidet.
|
|
|
|
:- func argument_to_pieces(unify_sub_context) = list(format_piece).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% When a higher order call uses either P(A, B, C) or C = F(A, B) syntax,
|
|
% we normally identify the call as being to "the predicate P" or to
|
|
% "the function F". However, there is a category of errors for which
|
|
% this is inappropriate: when the error is calling a function-valued
|
|
% variable as if it were a predicate, and vice versa. In such cases,
|
|
% we don't want the description of the error's context to say e.g.
|
|
% "in the call to the predicate P", and the description of the error
|
|
% itself to say "P is a function, but should be a predicate".
|
|
% Code that wants to report such errors should call the functions below
|
|
% with do_not_print_ho_var_name; pretty much all other callers should
|
|
% pass print_ho_var_name.
|
|
:- type maybe_print_ho_var_name
|
|
---> do_not_print_ho_var_name
|
|
; print_ho_var_name.
|
|
|
|
:- func call_id_to_pieces(maybe_print_ho_var_name, call_id) =
|
|
list(format_piece).
|
|
|
|
% generic_call_to_pieces(PrintHoVarName, VarNameSrc, GenericCall) = Pieces:
|
|
%
|
|
% Return a description of GenericCall as Pieces.
|
|
%
|
|
% For a description of the semantics of PrintHoVarName, see the
|
|
% definition of its type above.
|
|
%
|
|
% We use VarNameSrc for describing the callee of higher order calls.
|
|
% The type of this argument is var_name_source because we use this
|
|
% function both during the type analysis pass (which occurs before
|
|
% we construct var_tables, since it actually constructs var_tables),
|
|
% and during mode and determinism analysis, which do use var_tables.
|
|
%
|
|
:- func generic_call_to_pieces(maybe_print_ho_var_name, var_name_source,
|
|
generic_call) = list(format_piece).
|
|
|
|
% This variant of generic_call_to_string returns a string that
|
|
% specifically describes the *callee* of the call, not the call
|
|
% as a whole.
|
|
%
|
|
:- func generic_callee_to_pieces(maybe_print_ho_var_name, var_name_source,
|
|
generic_call) = list(format_piece).
|
|
|
|
% Generate a message of the form "argument %i of call to pred_or_func
|
|
% `foo/n'". The pred_markers argument is used to tell if the calling
|
|
% predicate is a type class method implementation; if so, we omit the
|
|
% "call to" part, since the user didn't write any explicit call.
|
|
%
|
|
:- func call_arg_id_to_pieces(maybe_print_ho_var_name, call_id, int,
|
|
pred_markers) = list(format_piece).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Return the arities that the given pred_ids have.
|
|
%
|
|
:- pred find_pred_arities(pred_id_table::in, list(pred_id)::in,
|
|
list(pred_form_arity)::out) is det.
|
|
:- pred find_user_arities(pred_id_table::in, list(pred_id)::in,
|
|
list(user_arity)::out) is det.
|
|
|
|
% Return the arities that the given pred_ids have,
|
|
% other than the given arity.
|
|
%
|
|
:- pred find_pred_arities_other_than(pred_id_table::in, list(pred_id)::in,
|
|
pred_form_arity::in, list(pred_form_arity)::out) is det.
|
|
:- pred find_user_arities_other_than(pred_id_table::in, list(pred_id)::in,
|
|
user_arity::in, list(user_arity)::out) is det.
|
|
|
|
:- func project_user_arity_int(user_arity) = int.
|
|
|
|
:- func project_pred_form_arity_int(pred_form_arity) = int.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds.hlds_out.
|
|
:- import_module hlds.hlds_out.hlds_out_util.
|
|
:- import_module hlds.pred_name.
|
|
:- import_module hlds.special_pred.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.parse_tree_out_cons_id.
|
|
:- import_module parse_tree.parse_tree_out_inst.
|
|
:- import_module parse_tree.parse_tree_out_misc.
|
|
:- import_module parse_tree.prog_mode.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module string.
|
|
:- import_module term_context.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
describe_qual_pred_name(ModuleInfo, PredId) =
|
|
describe_one_pred_name(ModuleInfo, no, should_module_qualify,
|
|
[], PredId).
|
|
|
|
describe_unqual_pred_name(ModuleInfo, PredId) =
|
|
describe_one_pred_name(ModuleInfo, no, should_not_module_qualify,
|
|
[], PredId).
|
|
|
|
describe_one_pred_name(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
SuffixPieces, PredId) = Pieces :-
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
Pieces = describe_one_pred_info_name(MaybeColor, ShouldModuleQualify,
|
|
SuffixPieces, PredInfo).
|
|
|
|
describe_one_pred_info_name(MaybeColor, ShouldModuleQualify, SuffixPieces,
|
|
PredInfo) = Pieces :-
|
|
% NOTE The code of this predicate duplicates the functionality of
|
|
% hlds_out.write_pred_id. Changes here should be made there as well.
|
|
%
|
|
% XXX This predicate should subcontract its work to pred_name.m.
|
|
PredName = pred_info_name(PredInfo),
|
|
ModuleName = pred_info_module(PredInfo),
|
|
pred_info_get_orig_arity(PredInfo, PredFormArity),
|
|
pred_info_get_markers(PredInfo, Markers),
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
( if Origin = origin_compiler(made_for_uci(SpecialId, TypeCtor)) then
|
|
special_pred_description(SpecialId, Descr),
|
|
TypeCtor = type_ctor(TypeSymName, TypeArity),
|
|
(
|
|
ShouldModuleQualify = should_module_qualify,
|
|
TypeSymNamePiece = qual_sym_name(TypeSymName)
|
|
;
|
|
ShouldModuleQualify = should_not_module_qualify,
|
|
TypeSymNamePiece = unqual_sym_name(TypeSymName)
|
|
),
|
|
( if TypeArity = 0 then
|
|
Pieces0 = [words(Descr), words("for type"), TypeSymNamePiece]
|
|
else
|
|
Pieces0 = [words(Descr), words("for type constructor"),
|
|
TypeSymNamePiece]
|
|
),
|
|
Pieces = maybe_color_pieces(MaybeColor, Pieces0 ++ SuffixPieces)
|
|
else if Origin = origin_user(user_made_class_method(_, PFNA)) then
|
|
PFNA = pred_pf_name_arity(PredOrFunc, SymName, UserArity),
|
|
UserArity = user_arity(UserArityInt),
|
|
SNA = sym_name_arity(SymName, UserArityInt),
|
|
(
|
|
ShouldModuleQualify = should_module_qualify,
|
|
SNAPiece = qual_sym_name_arity(SNA)
|
|
;
|
|
ShouldModuleQualify = should_not_module_qualify,
|
|
SNAPiece = unqual_sym_name_arity(SNA)
|
|
),
|
|
Pieces = [words("typeclass method"), p_or_f(PredOrFunc)] ++
|
|
maybe_color_pieces(MaybeColor, [SNAPiece] ++ SuffixPieces)
|
|
else if Origin = origin_user(user_made_instance_method(PFNA, _)) then
|
|
PFNA = pred_pf_name_arity(PredOrFunc, SymName, UserArity),
|
|
UserArity = user_arity(UserArityInt),
|
|
SNA = sym_name_arity(SymName, UserArityInt),
|
|
(
|
|
ShouldModuleQualify = should_module_qualify,
|
|
SNAPiece = qual_sym_name_arity(SNA)
|
|
;
|
|
ShouldModuleQualify = should_not_module_qualify,
|
|
SNAPiece = unqual_sym_name_arity(SNA)
|
|
),
|
|
Pieces = [words("instance method"), p_or_f(PredOrFunc)] ++
|
|
maybe_color_pieces(MaybeColor, [SNAPiece] ++ SuffixPieces)
|
|
else if marker_is_present(Markers, marker_class_instance_method) then
|
|
Pieces0 = [words("type class method implementation")] ++ SuffixPieces,
|
|
Pieces = maybe_color_pieces(MaybeColor, Pieces0)
|
|
else if pred_info_is_promise(PredInfo, PromiseType) then
|
|
Pieces0 = [quote(promise_to_string(PromiseType)),
|
|
words("declaration")] ++ SuffixPieces,
|
|
Pieces = maybe_color_pieces(MaybeColor, Pieces0)
|
|
else
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
( if marker_is_present(Markers, marker_class_method) then
|
|
PrefixPieces =
|
|
[words("type class"), p_or_f(PredOrFunc), words("method")]
|
|
else
|
|
PrefixPieces = [p_or_f(PredOrFunc)]
|
|
),
|
|
SymName = qualified(ModuleName, PredName),
|
|
user_arity_pred_form_arity(PredOrFunc,
|
|
user_arity(UserArityInt), PredFormArity),
|
|
SNA = sym_name_arity(SymName, UserArityInt),
|
|
(
|
|
ShouldModuleQualify = should_module_qualify,
|
|
SNAPiece = qual_sym_name_arity(SNA)
|
|
;
|
|
ShouldModuleQualify = should_not_module_qualify,
|
|
SNAPiece = unqual_sym_name_arity(SNA)
|
|
),
|
|
Pieces = PrefixPieces ++
|
|
maybe_color_pieces(MaybeColor, [SNAPiece] ++ SuffixPieces)
|
|
).
|
|
|
|
describe_several_pred_names(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
PredIds) = Pieces :-
|
|
SuffixPieces = [],
|
|
PiecesList = list.map(
|
|
describe_one_pred_name(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
SuffixPieces),
|
|
PredIds),
|
|
Pieces = pieces_list_to_pieces("and", PiecesList).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
describe_one_proc_name_maybe_argmodes(ModuleInfo, Lang, MaybeColor,
|
|
ShouldModuleQualify, SuffixPieces, PredProcId) = Pieces :-
|
|
module_info_pred_proc_info(ModuleInfo, PredProcId, PredInfo, ProcInfo),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
ModuleName = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
pred_info_get_proc_table(PredInfo, ProcTable),
|
|
map.count(ProcTable, NumProcs),
|
|
( if NumProcs > 1 then
|
|
pred_info_get_orig_arity(PredInfo, PredFormArity),
|
|
proc_info_get_argmodes(ProcInfo, ArgModes0),
|
|
NumExtraArgs = num_extra_args(PredFormArity, ArgModes0),
|
|
% We need to strip off the extra type_info arguments inserted at the
|
|
% front by polymorphism.m - we only want the last `PredFormArity'
|
|
% of them.
|
|
list.det_drop(NumExtraArgs, ArgModes0, ArgModes),
|
|
strip_module_names_from_mode_list(strip_builtin_module_name,
|
|
set_default_func, ArgModes, StrippedArgModes),
|
|
proc_info_get_inst_varset(ProcInfo, InstVarSet),
|
|
(
|
|
PredOrFunc = pf_predicate,
|
|
ArgModesStr = arg_modes_to_string(Lang, InstVarSet,
|
|
StrippedArgModes)
|
|
;
|
|
PredOrFunc = pf_function,
|
|
pred_args_to_func_args(StrippedArgModes,
|
|
FuncArgModes, FuncRetMode),
|
|
ArgModesStr =
|
|
arg_modes_to_string(Lang, InstVarSet, FuncArgModes) ++ " = " ++
|
|
mercury_mode_to_string(Lang, InstVarSet, FuncRetMode)
|
|
),
|
|
MaybeModuleNameDotStr =
|
|
maybe_module_qualification(ModuleName, ShouldModuleQualify),
|
|
% The absence or presence of a distinguished return value argument
|
|
% tells the reader whether we are reporting the name of a predicate
|
|
% or a function; no need to specify that same info in a word as well.
|
|
string.append_list([
|
|
"`",
|
|
MaybeModuleNameDotStr,
|
|
PredName,
|
|
ArgModesStr,
|
|
"'"], Descr),
|
|
Pieces = maybe_color_pieces(MaybeColor, [words(Descr)] ++ SuffixPieces)
|
|
else
|
|
% The Pieces we now return identifies a predicate or a function,
|
|
% not a procedure per se. We *could* add a prefix such as
|
|
% "the only mode of" in front of Pieces to fix this category error, but
|
|
%
|
|
% - even for novices, such a prefix would help only the first few
|
|
% times they see such a diagnostic, after which it will become
|
|
% superfluous, and
|
|
%
|
|
% - for non-novices and ex-novices, such a prefix will be clutter
|
|
% that hurts more than it helps.
|
|
Pieces = describe_one_pred_info_name(MaybeColor, ShouldModuleQualify,
|
|
SuffixPieces, PredInfo)
|
|
).
|
|
|
|
:- func maybe_module_qualification(module_name, should_module_qualify)
|
|
= string.
|
|
|
|
maybe_module_qualification(ModuleName, ShouldModuleQualify)
|
|
= MaybeModuleNameDotStr :-
|
|
(
|
|
ShouldModuleQualify = should_module_qualify,
|
|
MaybeModuleNameDotStr = sym_name_to_string(ModuleName) ++ "."
|
|
;
|
|
ShouldModuleQualify = should_not_module_qualify,
|
|
MaybeModuleNameDotStr = ""
|
|
).
|
|
|
|
:- func arg_modes_to_string(output_lang, inst_varset, list(mer_mode)) = string.
|
|
|
|
arg_modes_to_string(Lang, InstVarSet, ArgModes0) = Str :-
|
|
(
|
|
ArgModes0 = [],
|
|
Str = ""
|
|
;
|
|
ArgModes0 = [_ | _],
|
|
ArgModes = list.map(simplify_std_from_to_mode, ArgModes0),
|
|
ArgsStr = mercury_mode_list_to_string(Lang, InstVarSet, ArgModes),
|
|
Str = "(" ++ ArgsStr ++ ")"
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
describe_qual_proc_name(ModuleInfo, PredProcId) =
|
|
describe_one_proc_name(ModuleInfo, no, should_module_qualify,
|
|
PredProcId).
|
|
|
|
describe_unqual_proc_name(ModuleInfo, PredProcId) =
|
|
describe_one_proc_name(ModuleInfo, no, should_not_module_qualify,
|
|
PredProcId).
|
|
|
|
describe_one_proc_name(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
PredProcId) = Pieces :-
|
|
SuffixPieces = [],
|
|
PredProcId = proc(PredId, ProcId),
|
|
PredPieces = describe_one_pred_name(ModuleInfo, MaybeColor,
|
|
ShouldModuleQualify, SuffixPieces, PredId),
|
|
proc_id_to_int(ProcId, ProcIdInt),
|
|
Pieces = PredPieces ++ [words("mode"), int_fixed(ProcIdInt)].
|
|
|
|
describe_several_proc_names(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
PPIds) = Pieces :-
|
|
PiecesList = list.map(
|
|
describe_one_proc_name(ModuleInfo, MaybeColor, ShouldModuleQualify),
|
|
PPIds),
|
|
Pieces = pieces_list_to_pieces("and", PiecesList).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
describe_one_call_site(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
PPId - Context) = Pieces :-
|
|
ProcNamePieces = describe_one_proc_name(ModuleInfo, MaybeColor,
|
|
ShouldModuleQualify, PPId),
|
|
Context = context(FileName, LineNumber),
|
|
string.int_to_string(LineNumber, LineNumberStr),
|
|
Pieces = ProcNamePieces ++
|
|
[words("at"), fixed(FileName ++ ":" ++ LineNumberStr)].
|
|
|
|
describe_several_call_sites(ModuleInfo, MaybeColor, ShouldModuleQualify,
|
|
Sites) = Pieces :-
|
|
PiecesList = list.map(
|
|
describe_one_call_site(ModuleInfo, MaybeColor, ShouldModuleQualify),
|
|
Sites),
|
|
Pieces = pieces_list_to_pieces("and", PiecesList).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out the contexts of unifications.
|
|
%
|
|
|
|
unify_context_to_pieces(UnifyContext, LastContextWord, !Pieces) :-
|
|
unify_context_first_to_pieces(is_not_first, _, UnifyContext,
|
|
LastContextWord, !Pieces).
|
|
|
|
unify_context_first_to_pieces(!First, UnifyContext, LastContextWord,
|
|
!Pieces) :-
|
|
UnifyContext = unify_context(MainContext, BottomUpSubContexts),
|
|
list.reverse(BottomUpSubContexts, TopDownSubContexts),
|
|
unify_main_context_to_pieces(!First, MainContext,
|
|
LastContextWord0, !Pieces),
|
|
unify_sub_contexts_to_pieces(!First, TopDownSubContexts,
|
|
LastContextWord0, LastContextWord, !Pieces).
|
|
|
|
:- pred unify_main_context_to_pieces(is_first::in, is_first::out,
|
|
unify_main_context::in, last_context_word::out,
|
|
list(format_piece)::in, list(format_piece)::out) is det.
|
|
|
|
unify_main_context_to_pieces(!First, MainContext, LastContextWord, !Pieces) :-
|
|
(
|
|
MainContext = umc_explicit,
|
|
LastContextWord = lcw_none
|
|
;
|
|
MainContext = umc_head(ArgNum),
|
|
LastContextWord = lcw_argument,
|
|
ArgNumStr = int_to_string(ArgNum),
|
|
!:Pieces = !.Pieces ++ start_in_message_to_pieces(!.First) ++
|
|
[words("argument"), fixed(ArgNumStr), words("of clause head:"),
|
|
nl],
|
|
!:First = is_not_first
|
|
;
|
|
MainContext = umc_head_result,
|
|
LastContextWord = lcw_result,
|
|
!:Pieces = !.Pieces ++ start_in_message_to_pieces(!.First) ++
|
|
[words("function result term of clause head:"), nl],
|
|
!:First = is_not_first
|
|
;
|
|
MainContext = umc_call(CallId, ArgNum),
|
|
LastContextWord = lcw_call,
|
|
% The markers argument below is used only for type class method
|
|
% implementations defined using the named syntax rather than
|
|
% the clause syntax, and the bodies of such procedures should
|
|
% only contain a single call, so we shouldn't get unifications
|
|
% nested inside calls. Hence we can safely initialize the
|
|
% markers to empty here. (Anyway the worst possible consequence
|
|
% is slightly sub-optimal text for an error message.)
|
|
init_markers(Markers),
|
|
ArgIdPieces = call_arg_id_to_pieces(print_ho_var_name, CallId,
|
|
ArgNum, Markers),
|
|
!:Pieces = !.Pieces ++ start_in_message_to_pieces(!.First) ++
|
|
ArgIdPieces ++ [suffix(":"), nl],
|
|
!:First = is_not_first
|
|
;
|
|
MainContext = umc_implicit(Source),
|
|
LastContextWord = lcw_none,
|
|
string.format("implicit %s unification:", [s(Source)], Msg),
|
|
!:Pieces = !.Pieces ++ start_in_message_to_pieces(!.First) ++
|
|
[words(Msg), nl],
|
|
!:First = is_not_first
|
|
).
|
|
|
|
:- pred unify_sub_contexts_to_pieces(is_first::in, is_first::out,
|
|
list(unify_sub_context)::in, last_context_word::in, last_context_word::out,
|
|
list(format_piece)::in, list(format_piece)::out) is det.
|
|
|
|
unify_sub_contexts_to_pieces(!First, [], !LastContextWord, !Pieces).
|
|
unify_sub_contexts_to_pieces(!First, [SubContext | SubContexts],
|
|
_, !:LastContextWord, !Pieces) :-
|
|
( if
|
|
contexts_describe_list_element([SubContext | SubContexts],
|
|
0, ElementNum, AfterContexts)
|
|
then
|
|
HeadPieces = element_to_pieces(ElementNum),
|
|
!:LastContextWord = lcw_element,
|
|
NextContexts = AfterContexts
|
|
else
|
|
HeadPieces = argument_to_pieces(SubContext),
|
|
!:LastContextWord = lcw_argument,
|
|
NextContexts = SubContexts
|
|
),
|
|
!:Pieces = !.Pieces ++ start_in_message_to_pieces(!.First) ++
|
|
HeadPieces ++ [suffix(":"), nl],
|
|
!:First = is_not_first,
|
|
unify_sub_contexts_to_pieces(!First, NextContexts,
|
|
!LastContextWord, !Pieces).
|
|
|
|
:- pred contexts_describe_list_element(list(unify_sub_context)::in,
|
|
int::in, int::out, list(unify_sub_context)::out) is semidet.
|
|
|
|
contexts_describe_list_element([SubContext | SubContexts],
|
|
NumElementsBefore, ElementNum, AfterContexts) :-
|
|
SubContext = unify_sub_context(ConsId, ArgNum),
|
|
cons_id_may_be_list_cons(ConsId),
|
|
(
|
|
ArgNum = 1,
|
|
% If there were zero elements before this element,
|
|
% then this is element #1.
|
|
ElementNum = NumElementsBefore + 1,
|
|
AfterContexts = SubContexts
|
|
;
|
|
ArgNum = 2,
|
|
contexts_describe_list_element(SubContexts,
|
|
NumElementsBefore + 1, ElementNum, AfterContexts)
|
|
).
|
|
|
|
cons_id_may_be_list_cons(ConsId) :-
|
|
ConsId = du_data_ctor(DuCtor),
|
|
DuCtor = du_ctor(DuCtorSymName, 2, _TypeCtor),
|
|
% We ignore _TypeCtor since it may not have been set yet.
|
|
(
|
|
DuCtorSymName = unqualified("[|]")
|
|
;
|
|
DuCtorSymName = qualified(ModuleSymName, "[|]"),
|
|
is_std_lib_module_name(ModuleSymName, "list")
|
|
).
|
|
|
|
argument_to_pieces(SubContext) = Pieces :-
|
|
SubContext = unify_sub_context(ConsId, ArgNum),
|
|
ArgNumStr = int_to_string(ArgNum),
|
|
% XXX Using cons_id_and_arity_to_string here results in the
|
|
% quotes being in the wrong place.
|
|
ConsIdStr = cons_id_and_arity_to_string(ConsId),
|
|
Pieces = [words("argument"), fixed(ArgNumStr),
|
|
words("of functor"), quote(ConsIdStr)].
|
|
|
|
:- func element_to_pieces(int) = list(format_piece).
|
|
|
|
element_to_pieces(ElementNum) = Pieces :-
|
|
ElementNumStr = int_to_string(ElementNum),
|
|
Pieces = [words("list element"), prefix("#"), fixed(ElementNumStr)].
|
|
|
|
:- func start_in_message_to_pieces(is_first) = list(format_piece).
|
|
|
|
start_in_message_to_pieces(First) = Pieces :-
|
|
(
|
|
First = is_first,
|
|
% It is possible for First to be yes and !.Pieces to be nonempty,
|
|
% since !.Pieces may contain stuff from before the unify context.
|
|
Pieces = [words("In")]
|
|
;
|
|
First = is_not_first,
|
|
Pieces = [words("in")]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out ids of calls.
|
|
%
|
|
|
|
call_id_to_pieces(_PrintHoVarName, plain_call_id(PFSNA)) =
|
|
[qual_pf_sym_name_pred_form_arity(PFSNA)].
|
|
call_id_to_pieces(PrintHoVarName, generic_call_id(VarNameSrc, GenericCall)) =
|
|
generic_call_to_pieces(PrintHoVarName, VarNameSrc, GenericCall).
|
|
|
|
generic_call_to_pieces(PrintHoVarName, VarNameSrc, GenericCall) = Pieces :-
|
|
(
|
|
GenericCall = higher_order(Var, Purity, PredOrFunc, _, Syntax),
|
|
(
|
|
Syntax = hos_var,
|
|
(
|
|
PrintHoVarName = do_not_print_ho_var_name,
|
|
Pieces = [words("the higher order"), p_or_f(PredOrFunc),
|
|
words("call")]
|
|
;
|
|
PrintHoVarName = print_ho_var_name,
|
|
lookup_var_name_in_source(VarNameSrc, Var, VarName),
|
|
Pieces = [words("the higher order call to the"),
|
|
p_or_f(PredOrFunc), words("variable"), quote(VarName)]
|
|
)
|
|
;
|
|
Syntax = hos_call_or_apply,
|
|
(
|
|
PredOrFunc = pf_predicate,
|
|
Pieces = [words("the call to the"), quote("call"),
|
|
words("builtin predicate")]
|
|
;
|
|
PredOrFunc = pf_function,
|
|
ApplyFuncName = apply_func_name(Purity),
|
|
Pieces = [words("the call to the"), quote(ApplyFuncName),
|
|
words("builtin function")]
|
|
)
|
|
)
|
|
;
|
|
GenericCall = class_method(_TCI, _MethodNum, _ClassId, MethodId),
|
|
Pieces = [qual_pf_sym_name_pred_form_arity(MethodId)]
|
|
;
|
|
GenericCall = event_call(EventName),
|
|
Pieces = [words("event"), words(EventName)]
|
|
;
|
|
GenericCall = cast(CastType),
|
|
Pieces = [words(cast_type_to_string(CastType))]
|
|
).
|
|
|
|
generic_callee_to_pieces(PrintHoVarName, VarNameSrc, GenericCall) = Pieces :-
|
|
(
|
|
GenericCall = higher_order(Var, Purity, PredOrFunc, _, Syntax),
|
|
(
|
|
Syntax = hos_var,
|
|
(
|
|
PrintHoVarName = do_not_print_ho_var_name,
|
|
Pieces = [words("the higher order"), p_or_f(PredOrFunc),
|
|
words("variable")]
|
|
;
|
|
PrintHoVarName = print_ho_var_name,
|
|
lookup_var_name_in_source(VarNameSrc, Var, VarName),
|
|
Pieces = [words("the higher order"), p_or_f(PredOrFunc),
|
|
words("variable"), quote(VarName)]
|
|
)
|
|
;
|
|
Syntax = hos_call_or_apply,
|
|
(
|
|
PredOrFunc = pf_predicate,
|
|
Pieces = [words("the predicate argument of the"),
|
|
quote("call"), words("builtin predicate")]
|
|
;
|
|
PredOrFunc = pf_function,
|
|
Pieces = [words("the function argument of the"),
|
|
quote(apply_func_name(Purity)), words("builtin function")]
|
|
)
|
|
)
|
|
;
|
|
GenericCall = class_method(_TCI, _MethodNum, _ClassId, MethodId),
|
|
Pieces = [qual_pf_sym_name_pred_form_arity(MethodId)]
|
|
;
|
|
GenericCall = event_call(EventName),
|
|
Pieces = [words("event"), words(EventName)]
|
|
;
|
|
GenericCall = cast(CastType),
|
|
Pieces = [words(cast_type_to_string(CastType))]
|
|
).
|
|
|
|
:- func apply_func_name(purity) = string.
|
|
|
|
apply_func_name(purity_pure) = "apply".
|
|
apply_func_name(purity_semipure) = "semipure_apply".
|
|
apply_func_name(purity_impure) = "impure_apply".
|
|
|
|
call_arg_id_to_pieces(PrintHoVarName, CallId, ArgNum, PredMarkers) = Pieces :-
|
|
( if ArgNum =< 0 then
|
|
% Argument numbers that are less than or equal to zero
|
|
% are used for the type_info and typeclass_info arguments
|
|
% that are introduced by polymorphism.m.
|
|
% I think argument zero might also be used in some other cases
|
|
% when we just don't have any information about which argument it is.
|
|
% For both of these, we just say "in call to"
|
|
% rather than "in argument N of call to".
|
|
ArgNumPieces = []
|
|
else
|
|
ArgNumPieces = arg_number_to_pieces(CallId, ArgNum) ++ [words("of")]
|
|
),
|
|
( if
|
|
(
|
|
% The text printed for generic calls other than
|
|
% `class_method' does not need the "call to"
|
|
% prefix ("in call to higher-order call" is redundant,
|
|
% it's much better to just say "in higher-order call").
|
|
CallId = generic_call_id(_, GenericCallId),
|
|
not GenericCallId = class_method(_, _, _, _)
|
|
;
|
|
% For calls from type class instance implementations
|
|
% that were defined using the named syntax rather
|
|
% than the clause syntax, we also omit the "call to",
|
|
% since in that case there was no explicit call in
|
|
% the user's source code.
|
|
marker_is_present(PredMarkers, marker_named_class_instance_method)
|
|
)
|
|
then
|
|
CallToPieces = []
|
|
else
|
|
CallToPieces = [words("call to")]
|
|
),
|
|
CallIdPieces = call_id_to_pieces(PrintHoVarName, CallId),
|
|
Pieces = ArgNumPieces ++ CallToPieces ++ CallIdPieces.
|
|
|
|
:- func arg_number_to_pieces(call_id, int) = list(format_piece).
|
|
|
|
arg_number_to_pieces(CallId, ArgNum) = Pieces :-
|
|
(
|
|
CallId = plain_call_id(PFSymNameArity),
|
|
PFSymNameArity = pf_sym_name_arity(PredOrFunc, _, PredFormArity),
|
|
PredFormArity = pred_form_arity(Arity),
|
|
( if
|
|
PredOrFunc = pf_function,
|
|
Arity = ArgNum
|
|
then
|
|
Pieces = [words("the return value")]
|
|
else
|
|
Pieces = [words("argument"), int_fixed(ArgNum)]
|
|
)
|
|
;
|
|
CallId = generic_call_id(_VarNameSrc, GenericCall),
|
|
(
|
|
GenericCall = higher_order(_Var, _Purity, PredOrFunc,
|
|
PredFormArity, Syntax),
|
|
PredFormArity = pred_form_arity(PredFormArityInt),
|
|
( if
|
|
PredOrFunc = pf_function,
|
|
ArgNum = PredFormArityInt
|
|
then
|
|
Pieces = [words("the return value")]
|
|
else
|
|
(
|
|
Syntax = hos_var,
|
|
( if ArgNum = 1 then
|
|
Pieces = [words("the"), p_or_f(PredOrFunc),
|
|
words("term")]
|
|
else
|
|
Pieces = [words("argument"), int_fixed(ArgNum - 1)]
|
|
)
|
|
;
|
|
Syntax = hos_call_or_apply,
|
|
Pieces = [words("argument"), int_fixed(ArgNum)]
|
|
)
|
|
)
|
|
;
|
|
( GenericCall = class_method(_, _, _, _)
|
|
; GenericCall = event_call(_)
|
|
; GenericCall = cast(unsafe_type_cast)
|
|
; GenericCall = cast(unsafe_type_inst_cast)
|
|
; GenericCall = cast(equiv_type_cast)
|
|
; GenericCall = cast(exists_cast)
|
|
),
|
|
Pieces = [words("argument"), int_fixed(ArgNum)]
|
|
;
|
|
GenericCall = cast(subtype_coerce),
|
|
( if ArgNum = 2 then
|
|
Pieces = [words("the result")]
|
|
else
|
|
Pieces = [words("the argument")]
|
|
)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
find_pred_arities(PredTable, PredIds, PredFormArities) :-
|
|
gather_pred_form_arities(PredTable, PredIds, [], PredFormArities0),
|
|
list.sort_and_remove_dups(PredFormArities0, PredFormArities).
|
|
|
|
find_user_arities(PredTable, PredIds, UserArities) :-
|
|
gather_user_arities(PredTable, PredIds, [], UserArities0),
|
|
list.sort_and_remove_dups(UserArities0, UserArities).
|
|
|
|
find_pred_arities_other_than(PredTable, PredIds, Arity, OtherArities) :-
|
|
find_pred_arities(PredTable, PredIds, AllArities),
|
|
list.delete_all(AllArities, Arity, OtherArities).
|
|
|
|
find_user_arities_other_than(PredTable, PredIds, Arity, OtherArities) :-
|
|
find_user_arities(PredTable, PredIds, AllArities),
|
|
list.delete_all(AllArities, Arity, OtherArities).
|
|
|
|
%---------------------%
|
|
|
|
:- pred gather_pred_form_arities(pred_id_table::in, list(pred_id)::in,
|
|
list(pred_form_arity)::in, list(pred_form_arity)::out) is det.
|
|
|
|
gather_pred_form_arities(_, [], !PredFormArities).
|
|
gather_pred_form_arities(PredTable, [PredId | PredIds], !PredFormArities) :-
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
pred_info_get_orig_arity(PredInfo, PredFormArity),
|
|
!:PredFormArities = [PredFormArity | !.PredFormArities],
|
|
gather_pred_form_arities(PredTable, PredIds, !PredFormArities).
|
|
|
|
:- pred gather_user_arities(pred_id_table::in, list(pred_id)::in,
|
|
list(user_arity)::in, list(user_arity)::out) is det.
|
|
|
|
gather_user_arities(_, [], !UserArities).
|
|
gather_user_arities(PredTable, [PredId | PredIds], !UserArities) :-
|
|
map.lookup(PredTable, PredId, PredInfo),
|
|
UserArity = pred_info_user_arity(PredInfo),
|
|
!:UserArities = [UserArity | !.UserArities],
|
|
gather_user_arities(PredTable, PredIds, !UserArities).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
project_user_arity_int(user_arity(A)) = A.
|
|
|
|
project_pred_form_arity_int(pred_form_arity(A)) = A.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module hlds.hlds_error_util.
|
|
%---------------------------------------------------------------------------%
|