Files
mercury/compiler/check_module_interface.m
Zoltan Somogyi fcad1b21e8 Delete module_names_contexts fields from parse trees.
compiler/prog_item.m:
    We used to include information about include_module, import_module
    and use_module declarations in a module in the parse_tree_module_src
    in two forms: an unchecked form, which had type module_names_contexts,
    and a checked form, which had types include_module_map and
    import_and_or_use_map respectively. We have been gradually switching
    more and more code working on parse trees from taking the unchecked form
    as input to taking the checked form as input.

    This diff completes the process.

    - It deletes the ptms_{int,imp}_includes and ptms_{int,imp}{imports,uses}
      fields from parse_tree_module_src. Their checked versions remain.

    - It changes the parse_tree_int3 type to store include and import
      information using checked rather than unchecked types. The reason
      why this wasn't done before is that the checked data structures
      could not preserve the relevant invariants until subtypes were added
      to the language. This diff thus also defines the needed new subtype.

    Fix a typo (wrong int file number) in a field name.

compiler/item_util.m:
    Add some utility predicates needed by new code in the modules below.

    Change the interface of a utility predicate

    - to stop requiring the caller to supply unchecked data structures,
      constructing them internally as intermediate data structures instead,
      and
    - to stop returning some now-unneeded unchecked data structures.

    Keep some utility predicates private that are no longer needed
    outside this module.

    Delete a whole bunch of utility predicates which are no longer needed
    at all.

compiler/comp_unit_interface.m:
compiler/convert_parse_tree.m:
    Conform to the changes in prog_item.m, by changing code that used
    to construct unchecked to now construct checked data structures.

compiler/check_module_interface.m:
compiler/equiv_type.m:
compiler/get_dependencies.m:
compiler/grab_modules.m:
compiler/make_hlds_separate_items.m:
compiler/module_qual.collect_mq_info.m:
compiler/module_qual.qualify_items.m:
compiler/parse_tree_out.m:
compiler/write_deps_file.m:
    Conform to the changes in prog_item.m, mostly by changing code that
    used to take unchecked data structures as input to now take checked
    data structures as input.

compiler/deps_map.m:
compiler/module_baggage.m:
compiler/module_dep_info.m:
    Delete now-unneeded imports.
2023-07-01 15:03:18 +02:00

184 lines
7.3 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2015-2011 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: check_module_interface.m.
%
% Check whether the interface of a module exports anything.
%
%---------------------------------------------------------------------------%
:- module parse_tree.check_module_interface.
:- interface.
:- import_module libs.
:- import_module libs.globals.
:- import_module parse_tree.error_spec.
:- import_module parse_tree.prog_item.
:- import_module list.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
% Given a module's source code, check whether its interface
% exports anything. If it does not, and --warn-nothing-exported is set,
% report a warning.
%
:- pred check_module_interface_for_no_exports(globals::in,
parse_tree_module_src::in,
list(error_spec)::in, list(error_spec)::out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module libs.options.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.item_util.
:- import_module parse_tree.prog_data.
:- import_module bool.
:- import_module int.
:- import_module map.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc, !Specs) :-
globals.lookup_bool_option(Globals, warn_nothing_exported, ExportWarning),
(
ExportWarning = no
;
ExportWarning = yes,
ParseTreeModuleSrc = parse_tree_module_src(ModuleName,
ModuleNameContext, InclMap, _ImportUseMap,
_IntFIMs, _ImpFIMs, _IntSelfFIMLangs, _ImpSelfFIMLangs,
TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
TypeSpecs, InstModeSpecs,
IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
IntDeclPragmas, IntPromises, _IntBadClauses,
_ImpTypeClasses, _ImpInstances, _ImpPredDecls, _ImpModeDecls,
_ImpClauses, _ImpForeignExportEnums,
_ImpDeclPragmas, _ImpImplPragmas, _ImpPromises,
_ImpInitialises, _ImpFinalises, _ImpMutables),
CountIntIncls =
( pred(_MN::in, InclInfo::in, Cnt0::in, Cnt::out) is det :-
InclInfo = include_module_info(Section, _),
(
Section = ms_interface,
Cnt = Cnt0 + 1
;
Section = ms_implementation,
Cnt = Cnt0
)
),
map.foldl(CountIntIncls, InclMap, 0, NumIntIncls),
( if
( NumIntIncls = 0
; NumIntIncls = 1
),
type_ctor_checked_map_get_src_defns(TypeCtorCheckedMap,
IntTypeDefns, _, _),
IntTypeDefns = [],
inst_ctor_checked_map_get_src_defns(InstCtorCheckedMap,
IntInstDefns, _),
IntInstDefns = [],
mode_ctor_checked_map_get_src_defns(ModeCtorCheckedMap,
IntModeDefns, _),
IntModeDefns = [],
% If some type, inst or mode definitions were invalid, then
% there are two possibilities: either some of them are in
% the interface section, or none of them are. Unfortunately,
% we don't know which is the case, so must choose an algorithm
% that works in both cases.
%
% - If some of the errors are in the interface section, then
% generating a "no exports" warning would be misleading.
%
% - If all of the errors are in the implementation section, then
% generating that warning would not be misleading, but
% it is also not quite needed. Due to those errors,
% the compilation will fail, with error messages that the
% programmer can and should fix, whether we generate
% a "no exports" warning or not. This means that the warning
% is not really needed *now*; it can be generated later,
% once the complained-about invalid definitions are fixed.
TypeSpecs = [],
InstModeSpecs = [],
IntTypeClasses = [],
IntInstances = [],
IntPredDecls = [],
IntModeDecls = [],
IntDeclPragmas = [],
IntPromises = []
then
generate_no_exports_warning(ModuleName, ModuleNameContext,
NumIntIncls, !Specs)
else
true
)
).
:- inst num_int_incls for int/0
---> 0
; 1.
:- pred generate_no_exports_warning(module_name::in, prog_context::in,
int::in(num_int_incls),
list(error_spec)::in, list(error_spec)::out) is det.
generate_no_exports_warning(ModuleName, Context, NumIntIncls, !Specs) :-
MainMsg = simple_msg(Context,
[always([invis_order_default_start(2),
words("Warning: the interface of module"),
qual_sym_name(ModuleName),
words("does not export anything."), nl]),
% We don't list mode declarations because they don't make sense
% without a corresponding pred or func declaration.
% We don't list decl pragmas for the same reason.
% We don't list promises because although they don't *have to be*
% about predicates and functions defined in the same module,
% they *should be*.
verbose_only(verbose_always,
[words("To be useful, a module should export something."),
words("A file should contain at least one declaration"),
words("other than"), decl("import_module"),
words("in its interface section(s)."),
words("This would normally be a"), decl("pred"), words("or"),
decl("func"), words("declaration, or a"),
decl("type"), suffix(","), decl("inst"), suffix(","),
decl("mode"), suffix(","), decl("typeclass"), words("or"),
decl("instance"), words("definition."), nl]
)]),
(
NumIntIncls = 0,
Msgs = [MainMsg]
;
NumIntIncls = 1,
InclMsg = simple_msg(Context,
[verbose_only(verbose_always,
[words("A module that includes a single submodule"),
words("is not useful, because it can be replaced"),
words("by that submodule."), nl])
]),
Msgs = [MainMsg, InclMsg]
),
Spec = error_spec($pred, severity_warning, phase_term_to_parse_tree, Msgs),
!:Specs = [Spec | !.Specs].
%---------------------------------------------------------------------------%
:- end_module parse_tree.check_module_interface.
%---------------------------------------------------------------------------%