mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 18:03:36 +00:00
Class and instance definitions both contain lists of methods,
predicates and/or functions, that each have one or more procedures.
Until now, we represented the methods in class and instance definitions
as lists of nothing more than pred_proc_ids. This fact complicated
several operations,
- partly because there was no simple way to tell which procedures
were part of the same predicate or function, and
- partly because the order of the list is important (we identify
each method procedure in our equivalent of vtables with a number,
which is simply the procedure's position in this list), but there was
absolutely no information about recorded about this.
This diff therefore replaces the lists of pred_proc_ids with lists of
method_infos. Each method_info contains
- the method procedure number, i.e. the vtable index,
- the pred_or_func, sym_name and user arity of the predicate or function
that the method procedure is a part of, to make it simple to test
whether two method_infos represent different modes of the same predicate
or function, or not,
- the original pred_proc_id of the method procedure, which never changes,
and
- the current pred_proc_id, which program transformations *can* change.
compiler/hlds_class.m:
Make the change above in the representations of class and instance
definitions.
Put the fields of both types into a better order, by putting
related fields next to each other.
Put a notag wrapper around method procedure numbers to prevent
accidentally mixing them up with plain integers.
Add some utility functions.
compiler/prog_data.m:
Replace three fields containing pred_or_func, sym_name and arity
in the parse tree representation of instance methods with just one,
which contains all three pieces of info. This makes it easier to operate
on them as a unit.
Change the representation of methods defined by clauses from a list
of clauses to a cord of clauses, since this supports constant-time
append.
compiler/hlds_goal.m:
Switch from plain ints to the new notag representation of method
procedure numbers in method call goals.
compiler/add_class.m:
Simplify the code for adding new classes to the HLDS.
Give some predicates better names.
compiler/check_typeclass.m:
Significantly simplify the code for that generates the pred_infos and
proc_infos implementing all the methods of an instances definition,
and construct lists of method_infos instead of lists of pred_proc_ids.
Give some predicates better names.
Some error messages about problems in instance definitions started with
In instance declaration for class/arity:
while others started with
In instance declaration for class(module_a.foo, module_b.bar):
Replace both with
In instance declaration for class(foo, bar):
because it contains more useful information than the first, and less
non-useful information than the second. Improve the wording of some
error messages.
Factor out some common code.
compiler/prog_mode.m:
compiler/prog_type.m:
compiler/prog_util.m:
Generalize the existing predicates for stripping "builtin.m" module
qualifiers from sym_names, cons_ids, insts, types and modes
to allow also the stripping of *all* module qualifiers. This capability
is now used when we print an instance's type vector as a context
for diagnostics about problems inside instance definitions.
compiler/add_pred.m:
Add a mechanism for returning the pred_id of a newly created pred_info,
whether or not it was declared using a predmode declaration. This
capability is now needed by add_class.m.
Move the code creating an error message into its own function, and export
that function for add_class.m.
compiler/polymorphism_type_info.m:
Fix some comment rot.
compiler/base_typeclass_info.m:
compiler/call_gen.m:
compiler/dead_proc_elim.m:
compiler/deep_profiling.m:
compiler/direct_arg_in_out.m:
compiler/error_msg_inst.m:
compiler/float_regs.m:
compiler/get_dependencies.m:
compiler/higher_order.m:
compiler/hlds_error_util.m:
compiler/hlds_out_goal.m:
compiler/hlds_out_typeclass_table.m:
compiler/instance_method_clauses.m:
compiler/intermod.m:
compiler/make_hlds_error.m:
compiler/ml_call_gen.m:
compiler/mode_errors.m:
compiler/modes.m:
compiler/module_qual.qualify_items.m:
compiler/old_type_constraints.m:
compiler/parse_class.m:
compiler/parse_tree_out.m:
compiler/parse_tree_out_inst.m:
compiler/polymorphism_post_copy.m:
compiler/polymorphism_type_class_info.m:
compiler/prog_item.m:
compiler/prog_rep.m:
compiler/recompilation.usage.m:
compiler/state_var.m:
compiler/type_class_info.m:
compiler/typecheck_debug.m:
compiler/typecheck_error_type_assign.m:
compiler/typecheck_errors.m:
compiler/typecheck_msgs.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Conform to the changes above.
tests/invalid/bug476.err_exp:
tests/invalid/tc_err1.err_exp:
tests/invalid/tc_err2.err_exp:
tests/invalid/typeclass_bogus_method.err_exp:
tests/invalid/typeclass_missing_mode.err_exp:
tests/invalid/typeclass_missing_mode_2.err_exp:
tests/invalid/typeclass_mode.err_exp:
tests/invalid/typeclass_mode_2.err_exp:
tests/invalid/typeclass_mode_3.err_exp:
tests/invalid/typeclass_mode_4.err_exp:
tests/invalid/typeclass_test_10.err_exp:
tests/invalid/typeclass_test_3.err_exp:
tests/invalid/typeclass_test_4.err_exp:
tests/invalid/typeclass_test_5.err_exp:
tests/invalid/typeclass_test_9.err_exp:
Expect the updated wording of some error messages.
344 lines
14 KiB
Mathematica
344 lines
14 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-2006, 2008 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: make_hlds_error.m.
|
|
%
|
|
% Utility predicates for writing out warning and error messages when
|
|
% building the HLDS. Error messages specific to a given submodule of
|
|
% make_hlds.m are in that specific submodule; this module is for error messages
|
|
% that are either needed by more than one submodule of make_hlds.m, or are
|
|
% needed outside make_hlds.m.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module hlds.make_hlds_error.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.status.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Report that an instance of the kind of entity described by the first
|
|
% argument has more than one definition. The instance is specified
|
|
% by the second and third arguments, and the current and previous
|
|
% definitions are located at the two contexts given.
|
|
%
|
|
% If the format_piece list is not empty, it is added to the end
|
|
% of the message we generate for the first context.
|
|
%
|
|
:- pred report_multiply_defined(string::in, sym_name::in, user_arity::in,
|
|
prog_context::in, prog_context::in, list(format_piece)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
:- pred report_undefined_pred_or_func_error(maybe(pred_or_func)::in,
|
|
sym_name::in, user_arity::in, list(user_arity)::in, prog_context::in,
|
|
list(format_piece)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
:- pred report_undeclared_mode_error(module_info::in,
|
|
pred_id::in, pred_info::in, prog_varset::in, list(mer_mode)::in,
|
|
list(format_piece)::in, prog_context::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
:- pred maybe_report_undefined_pred_error(module_info::in,
|
|
pred_or_func::in, sym_name::in, pred_form_arity::in, pred_status::in,
|
|
maybe_class_method::in, prog_context::in, list(format_piece)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.mode_errors.
|
|
:- import_module hlds.hlds_error_util.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.parse_tree_out_info.
|
|
:- import_module parse_tree.parse_tree_out_pred_decl.
|
|
:- import_module parse_tree.prog_mode.
|
|
:- import_module parse_tree.prog_out.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module bool.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
report_multiply_defined(EntityKind, SymName, UserArity, Context, OrigContext,
|
|
ExtraPieces, !Specs) :-
|
|
% The flattening of source item blocks by modules.m puts
|
|
% all items in a given section together. Since the original
|
|
% source code may have had the contents of the different sections
|
|
% intermingled, this may change the relative order of items.
|
|
% Put them back in the original order for this error message.
|
|
compare(CmpRes, OrigContext, Context),
|
|
(
|
|
( CmpRes = (<)
|
|
; CmpRes = (=)
|
|
),
|
|
FirstContext = OrigContext,
|
|
SecondContext = Context
|
|
;
|
|
CmpRes = (>),
|
|
FirstContext = Context,
|
|
SecondContext = OrigContext
|
|
),
|
|
|
|
UserArity = user_arity(UserArityInt),
|
|
SNA = sym_name_arity(SymName, UserArityInt),
|
|
SecondDeclPieces = [words("Error:"), fixed(EntityKind),
|
|
qual_sym_name_arity(SNA), words("multiply defined."), nl],
|
|
FirstDeclPieces = [words("Here is the previous definition of"),
|
|
fixed(EntityKind), qual_sym_name_arity(SNA), suffix("."), nl],
|
|
SecondDeclMsg = simplest_msg(SecondContext, SecondDeclPieces),
|
|
FirstDeclMsg = simplest_msg(FirstContext, FirstDeclPieces),
|
|
(
|
|
ExtraPieces = [],
|
|
ExtraMsgs = []
|
|
;
|
|
ExtraPieces = [_ | _],
|
|
ExtraMsgs = [simplest_msg(SecondContext, ExtraPieces)]
|
|
),
|
|
Spec = error_spec($pred, severity_error, phase_parse_tree_to_hlds,
|
|
[SecondDeclMsg, FirstDeclMsg | ExtraMsgs]),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
report_undefined_pred_or_func_error(MaybePorF, SymName,
|
|
UserArity, OtherUserArities, Context, DescPieces, !Specs) :-
|
|
(
|
|
MaybePorF = no,
|
|
SNAPrefixPieces = [],
|
|
PredOrFuncPieces = [decl("pred"), words("or"), decl("func")]
|
|
;
|
|
MaybePorF = yes(pf_predicate),
|
|
SNAPrefixPieces = [words("predicate")],
|
|
PredOrFuncPieces = [decl("pred")]
|
|
;
|
|
MaybePorF = yes(pf_function),
|
|
SNAPrefixPieces = [words("function")],
|
|
PredOrFuncPieces = [decl("func")]
|
|
),
|
|
UserArity = user_arity(UserArityInt),
|
|
SNA = sym_name_arity(SymName, UserArityInt),
|
|
MainPieces = [words("Error:") | DescPieces] ++
|
|
[words("for")] ++ SNAPrefixPieces ++ [unqual_sym_name_arity(SNA),
|
|
words("without corresponding")] ++ PredOrFuncPieces ++
|
|
[words("declaration."), nl],
|
|
(
|
|
OtherUserArities = [],
|
|
OtherArityPieces = []
|
|
;
|
|
OtherUserArities = [_ | _],
|
|
OtherUserArityInts =
|
|
list.map(project_user_arity_int, OtherUserArities),
|
|
list.map(string.int_to_string, OtherUserArityInts, OtherArityStrs),
|
|
OtherArityPieces = [unqual_sym_name(SymName), words("does exist with"),
|
|
words(choose_number(OtherArityStrs, "arity", "arities"))] ++
|
|
list_to_pieces(OtherArityStrs) ++
|
|
[suffix("."), nl]
|
|
),
|
|
Spec = simplest_spec($pred, severity_error, phase_parse_tree_to_hlds,
|
|
Context, MainPieces ++ OtherArityPieces),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
report_undeclared_mode_error(ModuleInfo, PredId, PredInfo, VarSet, ArgModes,
|
|
DescPieces, Context, !Specs) :-
|
|
PredIdPieces = describe_one_pred_name(ModuleInfo,
|
|
should_not_module_qualify, PredId),
|
|
strip_module_names_from_mode_list(strip_builtin_module_name,
|
|
ArgModes, StrippedArgModes),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
MaybeDet = no,
|
|
SubDeclStr = mercury_mode_subdecl_to_string(output_debug, PredOrFunc,
|
|
varset.coerce(VarSet), unqualified(Name), StrippedArgModes, MaybeDet),
|
|
|
|
MainPieces = [words("In") | DescPieces] ++ [words("for")] ++
|
|
PredIdPieces ++ [suffix(":"), nl,
|
|
words("error: mode annotation specifies undeclared mode"),
|
|
quote(SubDeclStr), suffix("."), nl],
|
|
ProcIds = pred_info_all_procids(PredInfo),
|
|
(
|
|
ProcIds = [],
|
|
VerbosePieces = [words("(There are no declared modes for this"),
|
|
p_or_f(PredOrFunc), suffix(".)"), nl]
|
|
;
|
|
ProcIds = [ProcIdsHead | ProcIdsTail],
|
|
(
|
|
ProcIdsTail = [],
|
|
VerbosePieces = [words("The declared mode for this"),
|
|
p_or_f(PredOrFunc), words("is:"),
|
|
nl_indent_delta(1)] ++
|
|
mode_decl_for_pred_info_to_pieces(PredInfo, ProcIdsHead) ++
|
|
[nl_indent_delta(-1)]
|
|
;
|
|
ProcIdsTail = [_ | _],
|
|
VerbosePieces = [words("The declared modes for this"),
|
|
p_or_f(PredOrFunc), words("are the following:"),
|
|
nl_indent_delta(1)] ++
|
|
component_list_to_line_pieces(
|
|
list.map(mode_decl_for_pred_info_to_pieces(PredInfo),
|
|
ProcIds),
|
|
[nl_indent_delta(-1)])
|
|
)
|
|
),
|
|
Msg = simple_msg(Context,
|
|
[always(MainPieces), verbose_only(verbose_always, VerbosePieces)]),
|
|
Spec = error_spec($pred, severity_error, phase_parse_tree_to_hlds, [Msg]),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
:- func mode_decl_for_pred_info_to_pieces(pred_info, proc_id)
|
|
= list(format_piece).
|
|
|
|
mode_decl_for_pred_info_to_pieces(PredInfo, ProcId) =
|
|
[words(":- mode"),
|
|
words(mode_decl_to_string(output_debug, ProcId, PredInfo)),
|
|
suffix(".")].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
maybe_report_undefined_pred_error(ModuleInfo, PredOrFunc, SymName,
|
|
PredFormArity, Status, IsClassMethod, Context, DescPieces, !Specs) :-
|
|
% Our caller (or one of its ancestors) will add an implicit declaration
|
|
% for every undeclared predicate or function that has a reference to it
|
|
% either in a clause or in some other declaration (e.g. a tabling pragma).
|
|
% It will also mark the predicate as one whose type should be inferred.
|
|
|
|
% We allow programmers to define predicates without declaring them first
|
|
% if the user has specified the `--infer-types' option, unless
|
|
% circumstances force us to require a predicate declaration anyway.
|
|
%
|
|
% The two relevant circumstances are:
|
|
%
|
|
% - predicates exported from their defining module, which must be declared
|
|
% to allow the compiler to put that declaration into the module's
|
|
% interface file without running the typechecker, and
|
|
%
|
|
% - predicates which implement type class methods.
|
|
% XXX Document the reason for the requirement here.
|
|
|
|
DefinedInThisModule = pred_status_defined_in_this_module(Status),
|
|
IsExported = pred_status_is_exported(Status),
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, infer_types, InferTypes),
|
|
( if
|
|
DefinedInThisModule = yes,
|
|
IsExported = no,
|
|
IsClassMethod = is_not_a_class_method,
|
|
InferTypes = yes
|
|
then
|
|
true
|
|
else
|
|
PFSymNameArity = pf_sym_name_arity(PredOrFunc, SymName, PredFormArity),
|
|
PredOrFuncStr = pred_or_func_to_str(PredOrFunc),
|
|
MainPieces = [invis_order_default_start(1),
|
|
words("Error:") | DescPieces] ++ [words("for"),
|
|
unqual_pf_sym_name_pred_form_arity(PFSymNameArity), nl,
|
|
words("without corresponding"),
|
|
decl(PredOrFuncStr), words("declaration."), nl],
|
|
MainMsg = simplest_msg(Context, MainPieces),
|
|
|
|
module_info_get_predicate_table(ModuleInfo, PredicateTable),
|
|
predicate_table_lookup_pf_sym(PredicateTable,
|
|
is_fully_qualified, PredOrFunc, SymName, AllArityPredIds),
|
|
gather_porf_arities(ModuleInfo, AllArityPredIds, PredOrFunc,
|
|
PorFArities),
|
|
set.delete(PredFormArity, PorFArities, OtherPredFormArities),
|
|
% The sorting is to make the error message easier to read.
|
|
% There should not be any duplicates among OtherArities, but better
|
|
% safe than sorry ...
|
|
set.to_sorted_list(OtherPredFormArities, OtherPredFormAritiesList),
|
|
FullPredOrFuncStr = pred_or_func_to_full_str(PredOrFunc),
|
|
(
|
|
OtherPredFormAritiesList = [],
|
|
Spec = error_spec($pred, severity_error, phase_parse_tree_to_hlds,
|
|
[MainMsg])
|
|
;
|
|
(
|
|
OtherPredFormAritiesList = [OtherPredFormArity],
|
|
OtherAritiesPieces = [words("However, a"),
|
|
words(FullPredOrFuncStr), words("of that name"),
|
|
words("does exist with arity"),
|
|
pred_form_arity_to_int_fixed(PredOrFunc,
|
|
OtherPredFormArity),
|
|
suffix("."), nl]
|
|
;
|
|
OtherPredFormAritiesList = [_, _ | _],
|
|
OtherAritiesPieces = [words("However,"),
|
|
words(FullPredOrFuncStr), suffix("s"),
|
|
words("of that name do exist with arities") |
|
|
component_list_to_pieces("and",
|
|
list.map(pred_form_arity_to_int_fixed(PredOrFunc),
|
|
OtherPredFormAritiesList))] ++
|
|
[suffix("."), nl]
|
|
),
|
|
OtherAritiesMsg = simplest_msg(Context, OtherAritiesPieces),
|
|
Spec = error_spec($pred, severity_error, phase_parse_tree_to_hlds,
|
|
[MainMsg, OtherAritiesMsg])
|
|
),
|
|
!:Specs = [Spec | !.Specs]
|
|
).
|
|
|
|
% Given a list of pred ids, find out which of them represent
|
|
% procedures which have the right pred_or_func field (WantedPorF),
|
|
% and return their original arities.
|
|
%
|
|
:- pred gather_porf_arities(module_info::in, list(pred_id)::in,
|
|
pred_or_func::in, set(pred_form_arity)::out) is det.
|
|
|
|
gather_porf_arities(_ModuleInfo, [], _WantedPorF, set.init).
|
|
gather_porf_arities(ModuleInfo, [PredId | PredIds], WantedPorF,
|
|
!:PorFArities) :-
|
|
gather_porf_arities(ModuleInfo, PredIds, WantedPorF, !:PorFArities),
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
PorF = pred_info_is_pred_or_func(PredInfo),
|
|
( if PorF = WantedPorF then
|
|
pred_info_get_markers(PredInfo, Markers),
|
|
( if check_marker(Markers, marker_no_pred_decl) then
|
|
% This pred has no declaration, so including its arity in the list
|
|
% would be misleading.
|
|
true
|
|
else
|
|
PredFormArity = pred_info_pred_form_arity(PredInfo),
|
|
set.insert(PredFormArity, !PorFArities)
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- func pred_form_arity_to_int_fixed(pred_or_func, pred_form_arity)
|
|
= format_piece.
|
|
|
|
pred_form_arity_to_int_fixed(PredOrFunc, PredFormArity) = Component :-
|
|
user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity),
|
|
UserArity = user_arity(UserArityInt),
|
|
Component = int_fixed(UserArityInt).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module hlds.make_hlds_error.
|
|
%---------------------------------------------------------------------------%
|