mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-24 13:53:54 +00:00
compiler/check_module_interface.m:
compiler/parse_class.m:
Add color to the diagnostics generated by these modules.
In a few cases, improve the wording of the diagnostic.
tests/invalid/type_inf_loop.err_exp:
tests/invalid/typeclass_missing_det_3.err_exp:
tests/invalid_make_int/bad_existential_data_type.int_err_exp:
tests/invalid_make_int/unbound_type_vars_int.int_err_exp:
tests/invalid_nodepend/bigtest.err_exp:
tests/invalid_nodepend/duplicate_modes.err_exp:
tests/invalid_nodepend/errors_1.err_exp:
tests/invalid_nodepend/errors_2.err_exp:
tests/invalid_nodepend/errors_3.err_exp:
tests/invalid_nodepend/funcs_as_preds.err_exp:
tests/invalid_nodepend/inst_list_dup.err_exp:
tests/invalid_nodepend/no_exports.err_exp:
tests/invalid_nodepend/occurs.err_exp:
tests/invalid_nodepend/prog_io_erroneous.err_exp:
tests/invalid_nodepend/typeclass_no_param.err_exp:
tests/invalid_nodepend/typeclass_test_1.err_exp:
tests/invalid_nodepend/typeclass_test_2.err_exp:
tests/invalid_nodepend/typeclass_test_3.err_exp:
tests/invalid_nodepend/unicode_1.err_exp:
tests/invalid_nodepend/unicode_2.err_exp:
tests/invalid_nodepend/var_as_pred_name.err_exp:
tests/invalid_nodepend/vars_in_wrong_places.err_exp:
tests/warnings/empty_interface.err_exp:
Expect updated diagnostics.
209 lines
8.8 KiB
Mathematica
209 lines
8.8 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2011-2024 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, IntDeclMarkers, IntPromises, _IntBadClauses,
|
|
|
|
_ImpTypeClasses, _ImpInstances, _ImpPredDecls, _ImpModeDecls,
|
|
_ImpClauses, _ImpForeignProcs, _ImpForeignExportEnums,
|
|
_ImpDeclPragmas, _ImpDeclMarkers, _ImpImplPragmas, _ImpImplMarkers,
|
|
_ImpPromises, _ImpInitialises, _ImpFinalises, _ImpMutables),
|
|
CountIncls =
|
|
( pred(_MN::in, InclInfo::in, IntCnt0::in, IntCnt::out,
|
|
ImpCnt0::in, ImpCnt::out) is det :-
|
|
InclInfo = include_module_info(Section, _),
|
|
(
|
|
Section = ms_interface,
|
|
IntCnt = IntCnt0 + 1,
|
|
ImpCnt = ImpCnt0
|
|
;
|
|
Section = ms_implementation,
|
|
IntCnt = IntCnt0,
|
|
ImpCnt = ImpCnt0 + 1
|
|
)
|
|
),
|
|
map.foldl2(CountIncls, InclMap, 0, NumIntIncls, 0, NumImpIncls),
|
|
( if
|
|
(
|
|
NumIntIncls = 0
|
|
;
|
|
NumIntIncls = 1,
|
|
% If a module interface contains nothing but a single
|
|
% include_module declaration, then
|
|
% - we should report "nothing exported" if there are no
|
|
% include_module declarations in the implementation either,
|
|
% - but we should NOT report "nothing exported" if there are
|
|
% some include_module declarations in the implementation.
|
|
%
|
|
% Such packages are a useful way to establish a group of
|
|
% modules that have access to each other's interfaces,
|
|
% without those interfaces being accessible from the
|
|
% rest of the program (with the obvious exception of the
|
|
% module whose include_module declaration is exported.)
|
|
NumImpIncls = 0
|
|
),
|
|
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 = [],
|
|
% XXX We should delete the next three kinds of entities
|
|
% from this test.
|
|
%
|
|
% Mode declarations, decl pragmas and decl markers all say
|
|
% something about a predicate or function, and without
|
|
% a declaration of that predicate or function ALSO in the
|
|
% interface, they are not useful.
|
|
IntModeDecls = [], % we should delete this
|
|
IntDeclPragmas = [], % we should delete this
|
|
IntDeclMarkers = [], % we should delete this
|
|
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) :-
|
|
AlwaysPieces =
|
|
[invis_order_default_start(2, ""),
|
|
words("Warning: the interface of module")] ++
|
|
color_as_subject([qual_sym_name(ModuleName)]) ++
|
|
color_as_incorrect([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*.
|
|
StdVerbosePieces =
|
|
[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,
|
|
VerbosePieces = StdVerbosePieces
|
|
;
|
|
NumIntIncls = 1,
|
|
VerbosePieces = StdVerbosePieces ++
|
|
[words("A module that includes a single submodule"),
|
|
words("is not useful, because it can be replaced"),
|
|
words("by that submodule."), nl]
|
|
),
|
|
Msg = simple_msg(Context,
|
|
[always(AlwaysPieces),
|
|
verbose_only(verbose_always, VerbosePieces)]),
|
|
Spec = error_spec($pred, severity_warning, phase_t2pt, [Msg]),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.check_module_interface.
|
|
%---------------------------------------------------------------------------%
|