Files
mercury/compiler/make_hlds_error.m
Zoltan Somogyi fb97df69ed Make "compute type representations" a separate pass.
The ultimate purpose of this diff is to prepare for future improvements
in type representations, allowing values of some data types to be represented
more compactly than up to now.

The main way this diff does that is by creating a separate pass for deciding
how values of each type should be represented. We have traditionally decided
data representations for each type as its type definition was processed
during the make_hlds pass, but these decisions were always tentative,
and could be overridden later, e.g. when we processed foreign_type or
foreign_enum pragmas for the type. This dispersed decision making algorithm
is hard to understand, and therefore to change.

This diff centralizes decisions about type representations in a separate
pass that does nothing else. It leaves the algorithm distributed among
several files (du_type_layout.m, make_tags.m, and add_foreign_enum.m) for now,
to make reviewing this diff easier, but soon after it is committed I intend
to move all the relevant code to du_type_layout.m, to centralize the decision
code in "space" as well as in time.

For the reason why this pass runs before any of the semantic analysis
passes, instead of after all of them as I originally intended and as we
discussed on m-dev in late october 2017, see the big comment at the start of
du_type_layout.m.

As per another part of that same discussion on m-dev, this diff
makes a start on implementing a new type of item, the type_repn item,
which is intended *only* to be used in compiler-generated interface files,
*not* in source files. It is only a start because we can use these items
only *after* the creation of a separate type representation decision pass,
and this diff is already very big. The code for making the compiler understand
these items will be added later. The code for generating them will be added
later still, once the code for understanding them has been installed on
all our systems.

Since I was going to be working on the affected code anyway, this diff
also carries out two other decisions that came out of that discussion:

- the deletion of the ability to reserve a tag in a type for HAL,
  either via a compiler option or via a pragma, and

- the deletion of the ability to represent a functor using the address
  of a statically allocated object (which we haven't used and won't use,
  because it slows down accesses to *all the other functors* of the type).

compiler/mercury_compile_front_end.m:
    Invoke the new pass for making decisions about type representations
    after the make_hlds pass. (We used to do only the final part of it then.)

    Fix a bad dump stage name.

    Add an extra check for what it means for a module to be error free.

    Make a sub-switch explicit.

compiler/hlds.m:
compiler/make_hlds.m:
    Move the modules that implement the new pass from the make_hlds package
    to the hlds package, to give the compiler's top level access to them.

    Make the same move for the modules that the new pass's modules need.
    Since they are now part of hlds, they cannot reach into make_hlds,
    and I think this is a cleaner solution than forwarding predicates.

    Delete some forwarding predicates that are no longer needed.

compiler/notes/compiler_design.html:
    Document the updated location of the moved modules.

    Add an XXX to note a place where the documentation has not been
    updated in the past.

compiler/du_type_layout.m:
    Add code to implement the new pass.

    Keep the algorithm for deciding type representations as close
    to the previously used algorithm as possible, since this diff
    is already big enough. (The previous algorithm was scattered across
    add_type.m, add_foreign_enum.m, and make_hlds_passes.m.)

    Simplifications and optimizations will come later, after this module
    is merged with make_tags.m and with (at least) the foreign_enum half of
    add_foreign_enum.m.

compiler/make_tags.m:
    Keep the functionality of this module, which does both the first part
    of deciding type representations (tentatively assigning tags to functors,
    an assignment that may be overridden later), and the last part (packing
    multiple adjacent less-than-word-sized enum args into a single word,
    if possible.), but simplify it where possible, and note possibilities
    for further improvements.

compiler/add_foreign_enum.m:
    This module has two halves, one dealing with foreign_enum pragmas
    and one dealing with foreign_export_enum pragmas.

    Change the half that deals with foreign_enum pragmas to just build
    a data structure that du_type_layout.m will need to make its decisions,
    this structure being a map from type_ctors to the foreign enum
    specification applicable to the current target language. Include
    in this structure a component that add_foreign_enum.m itself can use
    to report better error messages for duplicate foreign_enum pragmas;
    this component records, for each type_ctor and language, the context
    of the previous foreign_enum pragma for that combo.

    Change the input for the half that deals with foreign_export_enum pragmas
    to reflect the fact that it is invoked by du_type_layout.m after all
    decisions about type representations have already been made.

compiler/add_special_pred.m:
    Move this module from the make_hlds package to the hlds package,
    since the code that adds special preds for type is now called from
    du_type_layout.m.

    Change the names of predicates to make clear whether they add
    only the declaration of a predicate, only its definition, or both.

    Don't try to pre-guess whether the implementation of a type's
    compare predicate will need an index predicate. Let the code
    that generates calls to the index predicate both declare and define
    the index predicate. This change removes the potential for
    inconsistencies between the two pieces of code.

compiler/add_pred.m:
    Move this module from the make_hlds package to the hlds package,
    since add_special_pred.m needs access to it.

compiler/add_type.m:
    When adding a type definition to the HLDS, don't try to decide
    its representation. Any such decision was tentative anyway, due
    to the possibility of e.g. the later processing of foreign_type
    or foreign_enum pragmas for the type. Likewise, don't try to
    create the special (unify, compare) predicates for the type.
    Leave both tasks to the du_type_layout pass.

    Likewise, don't try to pack the representation of types, or record
    no_tag types in the table of no_tag types, during the post-processing
    pass either; leave both of these to du_type_layout as well.
    Rename the predicate that post_processes type definitions to reflect
    the two tasks left for it to do.

compiler/prog_data.m:
    Do not store width information about the arguments of those data
    constructors in the parse tree. That information is not computed
    until later; until then, it was always filled in with dummy values.
    (But see hlds_data.m below.)

    Use bespoke types to represent the presence or absence of user-specified
    unify and compare predicates.

    Change the representation of data constructors to use a single "maybe"
    type, not two lists, to denote the presence or absence of existentially
    typed arguments.

    Give the HLDS the ability to hold representation information about
    abstract types that in the future we will get from type_repn items
    in the defining modules' interface files.

    Delete the uses_reserved_tag type, since we never use reserved tags
    anymore.

compiler/prog_item.m:
    Add the new type_repn item type, which is not used yet.

    Delete the reserve_tag pragma.

    Fix an earlier mistake in the wording of a context message.

compiler/hlds_data.m:
    Put all the fields of hlds_du_type (the type definition variant dealing
    with discriminated union types) that deal with type representation
    issues in a single "maybe" field that is set to "no" before the
    type representation decision pass has been run.

    Add new type, constructor_repn, that stores the same information as the old
    constructor type (defined in prog_data.m), PLUS the information
    describing how terms with that data constructor are stored.

    Likewise, add a new type ctor_arg_rep, which likewise stores
    the widths of each constructor argument. When we implement
    argument reordering, we would store the offset of the arg as well.

    Since the parse tree representations of constructors and their arguments
    don't store representation information anymore, the cons_table they
    are stored in doesn't either. Make the lookup of representation information
    for a given constructor possible by adding a map to the new "maybe" field
    of hlds_du_type.

    Provide some utility predicates.

    Optimize some existing predicates.

    Rename some types to better reflect their meaning.

compiler/hlds_module.m:
    Provide a slot in the module_info for storing the information
    gathered by make_hlds.m that is needed by the new pass.

compiler/make_hlds_separate_items.m:
    When we see either a foreign_enum or a foreign_export_enum pragma,
    return values of a bespoke type for them (a type defined in
    hlds_module.m), instead of an item_pragma. This makes handling them
    considerably easier.

compiler/make_hlds_passes.m:
    With the changes in this diff, adding a type to the HLDS won't
    decide its representation. Therefore delete the code that used
    to loop over foreign_export_enum pragmas; in the absence of
    the final type representation information, it won't work right.

    Record the information that the du_type_layout pass will need
    in the module_info.

compiler/add_pragma.m:
    Delete the code for passing on foreign_enum and foreign_export_enum
    pragmas to add_foreign_enum.m; they are now passed to add_foreign_enum.m
    by du_type_layout.m.

    Move a utility predicate to make_hlds_error.m, to allow add_foreign_enum.m
    to call it.

compiler/make_hlds_error.m:
    Add the utility predicate moved from add_pragma.m.

    Move the module from the make_hlds to the hlds package.

compiler/module_qual.m:
    Provide a mechanism for recording error messages about e.g. undefined
    types without recording that we found an undefined type. This sounds
    strange, but there is a valid use case.

    When a type definition declares a functor's argument to be of an
    undefined type, that error is usually fatal; we stop the compiler
    from proceeding even to typechecking, since the typechecker will
    probably abort with a map lookup failure. Most other references
    to undefined types are similarly fatal for the same reason. However,
    if e.g. a foreign_export_enum pragma refers to an undefined type,
    that error *won't* be visible to the typechecker, and therefore
    won't crash it. The error will still cause the compiler to exit
    without generating any target language code, but at least it will be
    able to run the typechecker and other semantic analysis passes.

    Without this change, the compiler will report only one error in
    the ee_invalid.m test case; with it, it reports *every* error
    in the test case expected output.

compiler/module_qual.qualify_items.m:
    Use the capability describe above for undefined types in
    foreign_export_enum pragmas.

compiler/module_qual.qual_errors.m:
    Delete a (somewhat incorrect) copy of a predicate in prog_item.m,
    to reduce code duplication.

compiler/prog_type.m:
    Add ways to represent abstract types whose representations are nevertheless
    known (from type_repn items in the defining modules' interface files)
    to be notag or dummy types. This will be needed to fix Mantis bug #441,
    a fix that will probably be one of the first later changes to build
    on this diff.

    Delete a type moved to type_util.m.

compiler/type_util.m:
    Provide extra versions of some predicates, with the difference between
    the old and the new versions being that one requires type representations
    to have been decided already, and the other one does not.

    Move the definition of the ctor_defn type here from prog_type.m,
    since prog_type.m itself does not use it, but type_util.m does.

    Give some predicates more meaningful names.

compiler/parse_type_defn.m:
    Simplify the code for parsing type definitions, to make it easier
    to reuse to parse type_repn items.

    Add a sanity check that requires existential constraints to have
    *some* existential variables to apply to.

    Allow "type_is_representable_in_n_bits" as a synonym for
    "type_is_abstract_enum", since in the future we want to be able to pack
    e.g. multiple int8s, not just multiple enums, into a single word.

    Generate more specific error messages for some classes of malformed input.

compiler/parse_type_repn.m:
    New module to parse type_repn items.

compiler/polymorphism.m:
    Make some predicates that operate on type constructors take
    the type constructors themselves as input arguments, not a whole type
    *using* that type constructor. Put the arguments of those predicates
    in a more standard order.

    Note that some predicates don't belong in this module.

compiler/special_pred.m:
    Make the code that decides whether a special predicate for a type
    constructor can be defined lazily avoid using type representation
    information. (Actually, we now make decisions about lazy vs eager
    definitions after type representation is available, but that was
    not so in an earlier version of this change, and the new code
    is more robust.)

compiler/unify_proc.m:
    When we decide to generate code for a compare predicate that needs
    the type to have an index predicate, don't presume that the index
    predicate has already been declared and defined; instead, declare
    and define it then and there. (Index predicates are *never* called
    from anywhere else.)

    Pack the information needed to define a special predicate
    into a single structure, to simplify the above.

    Since the creation of a clause for a compare predicate may now require
    the declaration and definition of an index predicate, the module_info
    field of the unify_proc_info is now a writeable field.

    Give some predicates and function symbols more meaningful names.

    Note some problems with the existing code.

compiler/add_class.m:
compiler/add_clause.m:
compiler/add_foreign_proc.m:
compiler/add_mode.m:
compiler/add_mutable_aux_preds.m:
compiler/add_pragma_tabling.m:
compiler/add_pragma_type_spec.m:
compiler/add_solver.m:
compiler/check_typeclass.m:
compiler/code_info.m:
compiler/comp_unit_interface.m:
compiler/ctgc.selector.m:
compiler/ctgc.util.m:
compiler/default_func_mode.m:
compiler/det_report.m:
compiler/equiv_type.m:
compiler/equiv_type_hlds.m:
compiler/erl_code_gen.m:
compiler/export.m:
compiler/foreign.m:
compiler/get_dependencies.m:
compiler/goal_expr_to_goal.m:
compiler/hhf.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_out_module.m:
compiler/inst_check.m:
compiler/inst_test.m:
compiler/inst_util.m:
compiler/intermod.m:
compiler/item_util.m:
compiler/make_hlds_warn.m:
compiler/ml_accurate_gc.m:
compiler/ml_simplify_switch.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
compiler/mode_util.m:
compiler/modecheck_goal.m:
compiler/module_qual.collect_mq_info.m:
compiler/modules.m:
compiler/parse_item.m:
compiler/parse_pragma.m:
compiler/parse_tree.m:
compiler/parse_tree_out.m:
compiler/parse_tree_out_pragma.m:
compiler/post_term_analysis.m:
compiler/proc_requests.m:
compiler/prog_item_stats.m:
compiler/qual_info.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/recompilation.version.m:
compiler/resolve_unify_functor.m:
compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
compiler/simplify_goal_ite.m:
compiler/stack_opt.m:
compiler/state_var.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/superhomogeneous.m:
compiler/switch_gen.m:
compiler/switch_util.m:
compiler/table_gen.m:
compiler/term_constr_build.m:
compiler/term_norm.m:
compiler/trailing_analysis.m:
compiler/type_constraints.m:
compiler/type_ctor_info.m:
compiler/typecheck.m:
compiler/unify_gen.m:
compiler/untupling.m:
compiler/unused_imports.m:
compiler/write_module_interface_files.m:
compiler/xml_documentation.m:
    Conform to the changes above.

tests/invalid/Mmakefile:
    Disable the reserve_tag test case, as it is not applicable anymore.

tests/invalid/exported_foreign_enum.{m,err_exp}:
tests/invalid/pragma_qual_error.{m,err_exp}:
    Delete reserve_tag pragmas from these test cases, and its effects
    from the expected outputs.

tests/invalid/bad_foreign_type.err_exp:
tests/invalid/bigtest.err_exp:
tests/invalid/foreign_enum_invalid.err_exp:
tests/invalid/type_lhs_var.err_exp:
tests/invalid/uu_type.err_exp:
tests/invalid/where_abstract_enum.err_exp:
tests/invalid/where_direct_arg.err_exp:
    Expect the updated messages for some errors.

tests/valid/Mmake.valid.common:
tests/valid/Mmakefile:
    Disable any reserve_tag test cases, as they are not applicable anymore.
2018-01-31 17:54:40 +11:00

323 lines
13 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.status.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.
:- import_module parse_tree.error_util.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_item.
:- import_module list.
%-----------------------------------------------------------------------------%
:- pred report_multiple_def_error(sym_name::in, int::in, string::in,
prog_context::in, prog_context::in, list(format_component)::in,
list(error_spec)::in, list(error_spec)::out) is det.
:- pred report_undefined_pred_or_func_error(sym_name::in,
arity::in, list(arity)::in, prog_context::in, list(format_component)::in,
list(error_spec)::in, list(error_spec)::out) is det.
% Similar to report_undeclared_mode_error, but gives less information.
% XXX perhaps we should get rid of this, and change the callers to
% instead call undeclared_mode_error.
%
:- pred report_undefined_mode_error(sym_name::in, int::in, prog_context::in,
list(format_component)::in,
list(error_spec)::in, list(error_spec)::out) is det.
:- pred maybe_report_undefined_pred_error(module_info::in,
sym_name::in, int::in, pred_or_func::in, pred_status::in,
maybe_class_method::in, prog_context::in, list(format_component)::in,
list(error_spec)::in, list(error_spec)::out) is det.
% Emit an error reporting that something should not have occurred in
% a module interface.
%
:- pred error_is_exported(prog_context::in, format_components::in,
list(error_spec)::in, list(error_spec)::out) is det.
% Check for invalid pragmas in interface sections.
%
:- pred report_if_pragma_is_wrongly_in_interface(item_mercury_status::in,
item_pragma_info::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.hlds_pred.
:- 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 maybe.
:- import_module set.
:- import_module string.
:- import_module varset.
%-----------------------------------------------------------------------------%
report_multiple_def_error(Name, Arity, DefType, Context, OrigContext,
ExtraPieces, !Specs) :-
Pieces1 = [words("Error:"), fixed(DefType),
qual_sym_name_and_arity(sym_name_arity(Name, Arity)),
words("multiply defined."), nl],
Pieces2 = [words("Here is the previous definition of"), fixed(DefType),
qual_sym_name_and_arity(sym_name_arity(Name, Arity)),
suffix("."), nl],
Msg1 = simple_msg(Context, [always(Pieces1)]),
Msg2 = error_msg(yes(OrigContext), treat_as_first, 0,
[always(Pieces2)]),
(
ExtraPieces = [],
ExtraMsgs = []
;
ExtraPieces = [_ | _],
ExtraMsgs = [simple_msg(Context, [always(ExtraPieces)])]
),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds,
[Msg1, Msg2] ++ ExtraMsgs),
!:Specs = [Spec | !.Specs].
report_undefined_pred_or_func_error(Name, Arity, OtherArities, Context,
DescPieces, !Specs) :-
MainPieces = [words("Error:") | DescPieces] ++ [words("for"),
unqual_sym_name_and_arity(sym_name_arity(Name, Arity)),
words("without corresponding"), decl("pred"), words("or"),
decl("func"), words("declaration."), nl],
(
OtherArities = [],
OtherArityPieces = []
;
OtherArities = [_ | _],
list.map(string.int_to_string, OtherArities, OtherArityStrs),
OtherArityPieces = [unqual_sym_name(Name), words("does exist with"),
words(choose_number(OtherArityStrs, "arity", "arities"))] ++
list_to_pieces(OtherArityStrs) ++
[suffix("."), nl]
),
Msg = simple_msg(Context, [always(MainPieces ++ OtherArityPieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs].
report_undefined_mode_error(Name, Arity, Context, DescPieces, !Specs) :-
Pieces = [words("Error:") | DescPieces] ++ [words("for"),
qual_sym_name_and_arity(sym_name_arity(Name, Arity)),
words("specifies non-existent mode.")],
Msg = simple_msg(Context, [always(Pieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs].
% Similar to report_undefined_mode_error, but gives more information.
% XXX the documentation here should be somewhat less circular.
%
:- func report_undeclared_mode_error(list(mer_mode), prog_varset,
pred_id, pred_info, module_info, prog_context) = error_spec.
:- pragma consider_used(report_undeclared_mode_error/6).
report_undeclared_mode_error(ModeList, VarSet, PredId, PredInfo, ModuleInfo,
Context) = Spec :-
PredIdPieces = describe_one_pred_name(ModuleInfo,
should_not_module_qualify, PredId),
strip_builtin_qualifiers_from_mode_list(ModeList, StrippedModeList),
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), StrippedModeList, MaybeDet),
MainPieces = [words("In clause 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 = [_ | _],
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(severity_error, phase_parse_tree_to_hlds, [Msg]).
:- func mode_decl_for_pred_info_to_pieces(pred_info, proc_id)
= list(format_component).
mode_decl_for_pred_info_to_pieces(PredInfo, ProcId) =
[words(":- mode"), words(mode_decl_to_string(ProcId, PredInfo)),
suffix(".")].
%----------------------------------------------------------------------------%
maybe_report_undefined_pred_error(ModuleInfo, Name, Arity, PredOrFunc, Status,
IsClassMethod, Context, DescPieces, !Specs) :-
% This is not considered an unconditional error anymore:
% if there is no `:- pred' or `:- func' declaration,
% and the declaration is local, and not a type class method,
% and the `--infer-types' option was specified,
% then we just add an implicit declaration for that predicate or
% function, marking it as one whose type will be inferred.
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
PredOrFuncStr = pred_or_func_to_str(PredOrFunc),
MainPieces = [words("Error:") | DescPieces] ++ [words("for"),
simple_call(simple_call_id(PredOrFunc, Name, Arity)), nl,
words("without corresponding"),
decl(PredOrFuncStr), words("declaration."), nl],
MainMsg = simple_msg(Context, [always(MainPieces)]),
module_info_get_predicate_table(ModuleInfo, PredicateTable),
predicate_table_lookup_pf_sym(PredicateTable,
is_fully_qualified, PredOrFunc, Name, AllArityPredIds),
gather_porf_arities(ModuleInfo, AllArityPredIds, PredOrFunc,
PorFArities),
set.delete(Arity, PorFArities, OtherArities),
% 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(OtherArities, OtherAritiesList),
FullPredOrFuncStr = pred_or_func_to_full_str(PredOrFunc),
(
OtherAritiesList = [],
Spec = error_spec(severity_error, phase_parse_tree_to_hlds,
[MainMsg])
;
(
OtherAritiesList = [OtherArity],
OtherAritiesPieces = [words("However, a"),
words(FullPredOrFuncStr), words("of that name"),
words("does exist with arity"), int_fixed(OtherArity),
suffix("."), nl]
;
OtherAritiesList = [_, _ | _],
OtherAritiesPieces = [words("However,"),
words(FullPredOrFuncStr), suffix("s"),
words("of that name do exist with arities") |
component_list_to_pieces("and",
list.map(wrap_int_fixed, OtherAritiesList))] ++
[suffix("."), nl]
),
OtherAritiesMsg = simple_msg(Context,
[always(OtherAritiesPieces)]),
Spec = error_spec(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(int)::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_orig_arity(PredInfo, OrigArity),
adjust_func_arity(PorF, OrigArity, Arity),
set.insert(Arity, !PorFArities)
else
true
).
:- func wrap_int_fixed(int) = format_component.
wrap_int_fixed(N) = int_fixed(N).
%----------------------------------------------------------------------------%
error_is_exported(Context, ItemPieces, !Specs) :-
Pieces = [words("Error:")] ++ ItemPieces ++
[words("in module interface."), nl],
Msg = simple_msg(Context, [always(Pieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs].
%----------------------------------------------------------------------------%
report_if_pragma_is_wrongly_in_interface(ItemMercuryStatus, ItemPragmaInfo,
!Specs) :-
ItemPragmaInfo = item_pragma_info(Pragma, MaybeAttrs, Context, _SeqNum),
( if
% Is the pragma in the interface?
ItemMercuryStatus = item_defined_in_this_module(ItemExport),
ItemExport = item_export_anywhere,
% Is the pragma *wrongly* in the interface?
pragma_allowed_in_interface(Pragma) = no,
% Is there any point in generating an error message about the pragma?
% If the pragma was created by the compiler, then the *real* problem
% is whatever bug in the compiler caused it to *create* this pragma,
% and the user cannot do anything about that bug.
MaybeAttrs = item_origin_user
then
ContextPieces = pragma_context_pieces(Pragma),
error_is_exported(Context, ContextPieces, !Specs)
else
true
).
%----------------------------------------------------------------------------%
:- end_module hlds.make_hlds_error.
%----------------------------------------------------------------------------%