Commit Graph

13 Commits

Author SHA1 Message Date
Zoltan Somogyi
c8725fb4bc Carve module_dep_info.m out of module_imports.m.
compiler/module_dep_info.m:
    As above. The only change is added documentation.

compiler/parse_tree.m:
    Include the new module in the parse_tree package.

compiler/notes/compiler_design.html:
    Document the new module, and update the documentation of module_imports.m.

compiler/module_imports.m:
    Delete the moved code, put the main data structure at the top,
    and add some documentation for it.

compiler/compile_target_code.m:
compiler/generate_dep_d_files.m:
compiler/make.dependencies.m:
compiler/make.make_info.m:
compiler/make.module_dep_file.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make.util.m:
compiler/module_deps_graph.m:
    Import module_dep_info.m, usually instead of module_imports.m,
    sometimes beside module_imports.m.
2022-01-25 08:48:40 +11:00
Zoltan Somogyi
114cfb482e Create and use module_dep_summary.
compiler/module_imports.m:
    Until now, we stored the information we read in from .dep files
    in module_and_imports structures in which most of the fields
    were left filled-in with default values, which could be correct
    only by accident.

    This diff switches to storing information from .dep files in
    a values of a type, module_dep_summary, that is made for this purpose.
    With this type, it is obvious that the only fields that are ever
    accessed are fields that have been properly filled in.

    Delete the old predicate that constructed the half-filled-in
    module_and_imports structure, since it is not needed anymore.
    Also, delete the mcm_read construction method, since the deleted
    predicate was its only user.

    Since mmc --make operates both on values of this type *and* on
    values of the old module_and_imports type, introduce a new type,
    module_dep_info, which stores either one or the other,
    and add the needed access predicates on this type.

    Give a field of module_and_imports a more descriptive name.

compiler/make.m:
    Switch to recording module_dep_infos for modules, instead of
    just module_and_imports.

    Replace some uses of maybes and pairs with bespoke types.

compiler/make.module_dep_file.m:
    Store the result of reading a .dep file in a module_dep_summary,
    not in a partially-filled-in module_and_imports.

compiler/module_deps_graph.m:
    Store module_dep_infos in the deps_graph instead of module_and_imports
    structures.

    Delete a named mode, since mode "in" now works for functions
    with the default mode.

compiler/make.dependencies.m:
    Delete the maybe(option) field from dep_file, since it was *always*
    set to "no".

    Conform to the changes above.

compiler/make.util.m:
    Add a new utility predicate, for use in make.dependencies.m.

    Conform to the changes above.

compiler/generate_dep_d_files.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
    Conform to the changes above.

compiler/compile_target_code.m:
    Expect a module_dep_info instead of a module_and_imports,
    since that is what our callers have.

    Add an XXX for a surprising piece of code.
2021-07-29 17:39:04 +10:00
Zoltan Somogyi
97fcb29811 Don't record anccestors in module_and_imports.
compiler/module_imports.m:
    As above; delete the ancestors field, since users can compute its value
    by calling get_ancestors_set on the module name.

    On some initialization paths, the ancestors field used to be filled
    with a dummy empty set, so this change should improve robustness.

compiler/deps_map.m:
compiler/grab_modules.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/mercury_compile_main.m:
compiler/module_deps_graph.m:
compiler/write_deps_file.m:
    Conform to the changes in module_imports.m.
2021-07-19 23:12:33 +10:00
Zoltan Somogyi
0d667a7c94 Add some access predicates for module_and_imports structures.
compiler/module_imports.m:
    As above.

compiler/modules.m:
    Use the new access predicates if relevant. Add a sanity check.

compiler/compile_target_code.m:
compiler/deps_map.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.program_target.m:
compiler/mercury_compile_main.m:
compiler/module_deps_graph.m:
compiler/write_deps_file.m:
    Use the new access predicates if relevant.
2019-04-17 04:53:58 +10:00
Zoltan Somogyi
e6870d29f9 Make module_and_imports an abstract type.
compiler/module_imports.m:
    Make the definition of module_and_imports private, to make future changes
    to its structure easier.

    Add the construction, deconstruction, getter and setter predicates
    on the type that are now needed by the other compiler modules.

    Put the related fields of module_and_imports next to each other.
    Give some of the fields more descriptive names.

compiler/compile_target_code.m:
compiler/deps_map.m:
compiler/generate_dep_d_files.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make.util.m:
compiler/mercury_compile_main.m:
compiler/module_deps_graph.m:
compiler/modules.m:
compiler/write_deps_file.m:
    Conform to the changes above.
2019-04-14 23:31:16 +10:00
Zoltan Somogyi
d967f36545 Improve error messages about unexpected module names, again.
When you get this message, the error may be in the module name that it
reports to be wrong, but it may be in the places that set the compiler's
expectations of what the name of the module should be. This latter is
very likely the case when one moves a module of the Mercury compiler
from one package to another. In such cases, the problems are the old modules
that continue to refer to the renamed module by its old name.

This diff improves the error message by indicating *precisely* the locations
that refer to the old name, since these are the locations that establish the
expectation that is not met.

compiler/module_imports.m:
    Change the module_and_imports structure to record, for each imported
    or used module, and for each child module, the location of the relevant
    ":- import_module" or ":- include_module" declaration(s).

compiler/deps_map.m:
    When tracing references from module A to module B.C (either because
    A imports B.C, or because A = B and A includes C), record the location
    of the ":- import_module" or ":- include_module" declaration as a source
    of the expectation that any file that contains module C will have
    B.C as module C's fully qualified name. Since a module is usually imported
    by more than one other module, there may be several sources of such
    expectations.

compiler/parse_module.m:
    Change the wording of the error message to reflect the change in what
    the context denotes.

compiler/get_dependencies.m:
compiler/prog_item.m:
    When returning the sets of modules imported, used or included by some
    entities such as item blocks, return the contexts of those
    imports/uses/includes as well.

compiler/compile_target_code.m:
compiler/hlds_module.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.program_target.m:
compiler/mercury_compile_main.m:
compiler/module_deps_graph.m:
compiler/module_qual.m:
compiler/modules.m:
compiler/write_deps_file.m:
    Conform to the changes above.

tests/invalid/bad_module_name.err_exp:
    Expect the updated error message.
2017-12-12 13:47:14 +11:00
Zoltan Somogyi
cc9912faa8 Don't import anything in packages.
Packages are modules whose only job is to serve as a container for submodules.
Modules like top_level.m, hlds.m, parse_tree.m and ll_backend.m are packages
in this (informal) sense.

Besides the include_module declarations for their submodules, most of the
packages in the compiler used to import some modules, mostly other packages
whose component modules their submodules may need. For example, ll_backend.m
used to import parse_tree.m. This meant that modules in the ll_backend package
did not have to import parse_tree.m before importing modules in the parse_tree
package.

However, this had a price. When we add a new module to the parse_tree package,
parse_tree.int would change, and this would require the recompilation of ALL
the modules in the ll_backend package, even the ones that did NOT import ANY
of the modules in the parse_tree package.

This happened even at one remove. Pretty much all modules in every one
of the backend have to import one or more modules in the hlds package,
and they therefore have import hlds.m. Since hlds.m imported transform_hlds.m,
any addition of a new middle pass to the transform_hlds package required
the recompilation of all backend modules, even in the usual case of the two
having nothing to do with each other.

This diff removes all import_module declarations from the packages,
and replaces them with import_module declarations in the modules that need
them. This includes only a SUBSET of their child modules and of the non-child
modules that import them.
2015-11-13 15:03:20 +11:00
Zoltan Somogyi
62ec97d443 Report imports shadowed by other imports.
If a module has two or more import_module or use_module declarations
for the same module, (typically, but not always, one being in its interface
and one in its implementation), generate an informational message about
each redundant declaration if --warn-unused-imports is enabled.

compiler/hlds_module.m:
    We used to record the set of imported/used modules, and the set of
    modules imported/used in the interface of the current module. However,
    these sets

    - did not record the distinction between imports and uses;
    - did not allow distinction between single and multiple imports/uses;
    - did not record the locations of the imports/uses.

    The first distinction was needed only by module_qual.m, which *did*
    pay attention to it; the other two were not needed at all.

    To generate messages for imports/uses shadowing other imports/uses,
    we need all three, so change the data structure storing such information
    for *direct* imports to one that records all three of the above kinds
    of information. (For imports made by read-in interface and optimization
    files, the old set of modules approach is fine, and this diff leaves
    the set of thus *indirectly* imported module names alone.)

compiler/unused_imports.m:
    Use the extra information now available to generate a
    severity_informational message about any import or use that is made
    redundant by an earlier, more general import or use.

    Fix two bugs in the code that generated warnings for just plain unused
    modules.

    (1) It did not consider that a use of the builtin type char justified
    an import of char.m, but without that import, the type is not visible.

    (2) It scanned cons_ids in goals in procedure bodies, but did not scan
    cons_ids that have been put into the const_struct_db. (I did not update
    the code here when I added the const_struct_db.)

    Also, add a (hopefully temporary) workaround for a bug in
    make_hlds_passes.m, which is noted below.

    However, there are at least three problems that prevent us from enabling
    --warn-unused-imports by default.

    (1) In some places, the import of a module is used only by clauses for
    a predicate that also has foreign procs. When compiled in a grade that
    selects one of those foreign_procs as the implementation of the predicate,
    the clauses are discarded *without* being added to the HLDS at all.
    This leads unused_imports.m to generate an uncalled-for warning in such
    cases. To fix this, we would need to preserve the Mercury clauses for
    *all* predicates, even those with foreign procs, and do all the semantic
    checks on them before throwing them away. (I tried to do this once, and
    failed, but the task should be easier after the item list change.)

    (2) We have two pieces of code to generate import warnings. The one in
    unused_imports.m operates on the HLDS after type and mode checking,
    while module_qual.m operates on the parse tree before the creation of
    the HLDS. The former is more powerful, since it knows e.g. what types and
    modes are used in the bodies of predicates, and hence can generate warnings
    about an import being unused *anywhere* in a module, as opposed to just
    unused in its interface.

    If --warn-unused-imports is enabled, we will get two separate set of
    reports about an interface import being unused in the interface,
    *unless* we get a type or mode error, in which case unused_imports.m
    won't be invoked. But in case we do get such errors, we don't want to
    throw away the warnings from module_qual.m. We could store them and
    throw them away only after we know we won't need them, or just get
    the two modules to generate identical error_specs for each warning,
    so that the sort_and_remove_dups of the error specs will do the
    throwing away for us for free, if we get that far.

    (3) The valid/bug100.m test case was added as a regression test for a bug
    that was fixed in module_qual.m. However the bug is still present in
    unused_imports.m.

compiler/make_hlds_passes.m:
    Give hlds_module.m the extra information it now needs for each item_avail.

    Add an XXX for a bug that cannot be fixed right now: the setting of
    the status of abstract instances to abstract_imported. (The "abstract"
    part is correct; the "imported" part may not be.)

compiler/intermod.m:
compiler/try_expand.m:
compiler/xml_documentation.m:
    Conform to the change in hlds_module.m.

compiler/module_qual.m:
    Update the documentation of the relationship of this module
    with unused_imports.m.

compiler/hlds_data.m:
    Document a problem with the status of instance definitions.

compiler/hlds_out_module.m:
    Update the code that prints out the module_info to conform to the change
    to hlds_module.m.

    Print status information about instances, which was needed to diagnose
    one of the bugs in unused_imports.m. Format the output for instances
    nicer.

compiler/prog_item.m:
    Add a convenience predicate.

compiler/prog_data.m:
    Remove a type synonym that makes things harder to understand, not easier.

compiler/modules.m:
    Delete an XXX that asks for the feature this diff implements.
    Add another XXX about how that feature could be improved.

compiler/Mercury.options.m:
    Add some more modules to the list of modules on which the compiler
    should be invoked with --no-warn-unused-imports.

compiler/*.m:
library/*.m:
mdbcomp/*.m:
browser/*.m:
deep_profiler/*.m:
mfilterjavac/*.m:
    Delete unneeded imports. Many of these shadow other imports, and some
    are just plain unneeded, as shown by --warn-unused-imports. In a few
    modules, there were a *lot* of unneeded imports, but most had just
    one or two.

    In a few cases, removing an import from a module, because it *itself*
    does not need it, required adding that same import to those of its
    submodules which *do* need it.

    In a few cases, conform to other changes above.

tests/invalid/Mercury.options:
    Test the generation of messages about import shadowing on the existing
    import_in_parent.m test case (although it was also tested very thoroughly
    when giving me the information needed for the deletion of all the
    unneeded imports above).

tests/*/*.{m,*exp}:
    Delete unneeded imports, and update any expected error messages
    to expect the now-smaller line numbers.
2015-08-25 00:38:49 +10:00
Zoltan Somogyi
ef44f50bee Eliminate the old module_defn item.
After my earlier changes to the item list, we used module_defns for only
two things: recording when one module includes another, and recording
when one module imports or uses another. After this diff, both those
pieces of information are stored separately in each item block.
This has two benefits.

The first benefit is that it allows us to use the type system to enforce
structural invariants about where include_module, import_module and use_module
declarations may appear. The one invariant that we now enforce is that
optimization files may not contain either include_module or import_module
declarations, though they may contain use_module declarations. I suspect that
there are also similar invariants about interface files, but finding them
requires something like this change.

The second benefit is that it allows traversals of item blocks to scan
only the part of the item block that may contain the object of interest.
While reading in interface and optimization files, we used to scan the
full item list several times to find included and imported modules; those
scans can now look at just the relevant information. Since the item lists
that need to be processed usually include all the declarations in a
substantial number of other modules, including some (such as list.m) that
have LOTS of declarations, the speedup can be substantial. On tools/speedtest,
the speedup is 1.5%.

compiler/prog_item.m:
    Make the change described above.

    Provide utility predicates on the new types representing include_module,
    import_module and use_module declarations.

    Move an old utility predicate from here to prog_io.m, since only prog_io.m
    uses it.

compiler/module_imports.m:
    Several fields of the module_imports type contained sets of module names,
    but stored them as lists. Change these to actual sets, to distinguish them
    from the lists whose order is actually important. (Basically, the order
    of processing .trans_opt files is important, but the order in which
    we read in .int0, .int3, .int2, .int and .opt files isn't.) In several
    places, this also avoids the need for conversions of lists to sets
    for set operations, and then back to lists.

compiler/modules.m:
    This module had several predicates that processed list of module names.
    Make these operate on sets of module names instead, and break each of them
    into two predicates: one that decides whether there is a next module name,
    and if yes whether it has been processed already, and one to do the actual
    processing if needed. This avoid the need for excessive indentation.

    The code that discovers what other modules' interface files may need
    to be read is now simpler due to the updated item_block structure.

    Remove the submodule whose job it was to discover what modules are included
    in items or item blocks, since that task has now become trivial, and is
    now done by a utility predicate in prog_item.m. Since this was the second
    last submodule (of the original eight), the last submodule is now the
    whole module. Therefore this module now has significantly greater cohesion
    than it had before.

compiler/write_module_interface_files.m:

compiler/prog_io_item.m:
    Parse include_module, import_module and use_module declarations as
    markers, not as items.

compiler/prog_io.m:
    Expect include_module, import_module and use_module declarations as
    markers, not as items.

compiler/split_parse_tree_src.m:
    Discover included submodules more simply with the updated item_block
    structure.

compiler/compile_target_code.m:
    Put the arguments of the predicates in this module in a more standard
    order.

compiler/recompilation.version.m:
    Conform to the above changes. Note a possible bug.

    Use a bespoke type to replace some bools.

compiler/check_raw_comp_unit.m:
compiler/comp_unit_interface.m:
compiler/deps_map.m:
compiler/equiv_type.m:
compiler/generate_dep_d_files.m:
compiler/get_dependencies.m:
compiler/hlds_module.m:
compiler/intermod.m:
compiler/item_util.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/make_hlds_passes.m:
compiler/mercury_compile.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mercury_to_mercury.m:
compiler/module_deps_graph.m:
compiler/module_qual.m:
compiler/prog_io_find.m:
compiler/read_modules.m:
compiler/recompilation.check.m:
compiler/recompilation.usage.m:
compiler/trans_opt.m:
compiler/write_deps_file.m:
    Conform to the above changes.

mdbcomp/sym_name.m:
    Provide a utility predicate to get the set of ancestors of a module
    as a set as well as a list.

tests/invalid/exported_unify3.err_exp:
tests/invalid/ii_parent.ii_child.err_exp:
    Update the expected error messages, which refer to line numbers in
    .int0 files, which have now changed, as we now put all import_module
    declarations before ordinary items.

    (Error messages shouldn't refer to automatically generated files,
    but that is a separate concern.)
2015-08-11 21:56:01 +10:00
Zoltan Somogyi
f91bad4579 Carve generate_dep_d_file.m out of modules.m.
The predicates in modules.m that generate .dep and .d files are independent
of the rest of that module, so moving them out into a new module improves
both modules' cohesion.

compiler/generate_dep_d_file.m:
    New module containing the code moved out of modules.m, as well as
    some code moved here from module_deps_graph.m, since it was called
    only from here.

    Give some predicates more descrriptive names.

compiler/parse_tree.m:
compiler/notes/compiler_design.html:
    Mention the new module.

compiler/modules.m:
    Remove the stuff moved to generate_dep_d_file.m.

compiler/make.program_target.m:
    Move here a predicate from module_deps_graph.m, since it was only called
    from here.

compiler/write_deps_file.m:
    Move here a predicate from module_deps_graph.m, since it was only called
    from here.

compiler/module_deps_graph.m:
    Remove the stuff moved to generate_dep_d_file.m, make.program_target.m
    or write_deps_file.m. What is left does only one job, and it is needed
    by both generate_dep_d_file.m and make.program_target.m.

compiler/mercury_compile.m:
    Conform to the changes above.
2015-08-02 07:16:53 +10:00
Zoltan Somogyi
fe785c668b Consistently use set.is_empty and set.is_non_empty.
compiler/*.m:
deep_profiler/*.m:
    As above.

library/set.m:
library/set_bbbtree.m:
library/set_ctree234.m:
library/set_ordlist.m:
library/set_tree234.m:
library/set_unordlist.m:
    Add is_non_empty to the set modules that did not already have it.
    (Some did, some didn't.)

    Make the documentation of empty, is_empty, non_empty and is_non_empty
    consistent.
2014-11-04 23:18:43 +11:00
Zoltan Somogyi
38dc676f18 Record each kind of error when reading in files.
compiler/prog_io_error.m:
    Replace the enum that used to record only whether we found no errors,
    some nonfatal errors or some fatal errors, with a type that records
    just what kinds of errors we found. Document each kind of error.

compiler/prog_io.m:
    Record any errors using the new type. In some cases, we used to
    forget fatal errors after finding nonfatal ones; now we don't.

compiler/read_modules.m:
    Do not generate error messages about not being able to open a file
    if we *could* open the file, but found other fatal errors inside it.

    Factor out some common code.

compiler/intermod.m:
    Ignore the error of not being able to open .opt files, but do not
    ignore any other errors inside them. This fixes a long-standing piece
    of strange-looking code.

compiler/module_imports.m:
    Do not ignore old fatal errors if reading a new interface file
    gets some new nonfatal errors. This fixes a long-standing XXX.

compiler/write_module_interface_files.m:
    Do not ignore fatal errors when considering whether to write out interface
    files. This fixes a long-standing XXX.

compiler/modules.m:
    Generate better error messages for fatal errors inside modules
    other than not being able to open the module.

compiler/deps_map.m:
compiler/make.module_dep_file.m:
compiler/mercury_compile.m:
compiler/module_deps_graph.m:
compiler/recompilation.check.m:
compiler/trans_opt.m:
compiler/write_deps_file.m:
    Conform to the change in prog_io_error.m.
2014-11-04 21:12:18 +11:00
Zoltan Somogyi
10732f58da Improve the cohesion of modules.m.
Once upon a time, modules.m contained all the code in the compiler that dealt
with interface files, and it was by far the biggest module in the compiler
(almost 9000 lines). Once before, I moved cohesive bunches of functionality
out of modules.m into new modules, such as file_util.m and module_cmds.m.
This diff does likewise, creating three new modules.

Besides that main task, it has two minor algorithmic changes that should
have no overall effect on correctness. First, it merges some traversals of
the item list, which should yield a very minor speedup, and second,
in order to avoid the need for an undesirable module import, it eliminates
an unnecessary sorting of the item list that we used to do when reading
in interface files. (The sorting makes sense only when *creating* interface
files).

This diff also gives more meaningful names to some predicates.

compiler/module_deps_graph.m:
    This new module defines the module dependency graph, and provides
    predicates for building it and using it.

compiler/write_module_iterface_files.m:
    This new module does what its name says it does.

compiler/item_util.m:
    This new module contains utility predicates that deal with items that are
    now needed in more than one module.

compiler/parse_tree.m:
compiler/notes/compiler_design.html:
    Include the new modules.

compiler/write_deps_file.m:
    Move some predicates here from modules.m, since they belong here.
    E.g. one prints .d files, and related code to print .dv and .dep files
    was already here.

compiler/mercury_compile.m:
    Move a predicate here from modules.m, since it was only called from here,
    and related code is also here.

compiler/prog_item.m:
    Move a predicate here from modules.m, since it is a utility predicate
    for a type that is defined here.

compiler/prog_type.m:
    Move a predicate here from modules.m, since it is a utility predicate
    for types, like all the other predicates in this module.

compiler/modules.m:
    Remove the code that is now in other modules. Impose some structure
    on the remaining code. (It used to be too jumbled up to make much sense of,
    which was one reason why working with this code was unnecessarily hard).

compiler/deps_map.m:
    Note the relationship to the new module module_deps_graph.m.

compiler/*.m:
    Import the new modules as well as (or instead of) modules.m, and/or conform
    to new names for predicates.
2014-10-23 19:20:33 +11:00