Make --warn-unused-imports more effective.

Specifically, make it warn about interface imports that are not used
in the initial HLDS, even if they *are* used after the expansion of
type-, inst- and mode-equivalences.

compiler/hlds_module.m:
    Add a slot to the HLDS to store the set of modules that are
    imported in the interface but are unused there when the HLDS
    is first constructed.

compiler/module_qual.qualify_items.m:
    Compute this set, and return it to mercury_compile_make_hlds.m.

    Make the code module qualifying aug_compilation_units warn about
    unused interface imports only if unused_imports.m won't do the same later.

compiler/mercury_compile_make_hlds.m:
    Pass the set to make_hlds_passes.m.

compiler/make_hlds_passes.m:
    Store the set in the initial HLDS.

compiler/prog_data_used_modules.m:
    Replace set_ordlists with set_tree234s.

compiler/unused_imports.m:
    Consider an interface-imported module unused in the interface
    if module_qual.qualify_items.m considered it unused, even if
    changes made by equiv_type.m has added uses of it later.

compiler/handle_options.m:
    Stop making --warn-unused-imports imply --no-warn-unused-interface-imports,
    since new logic in module_qual.qualify_items.m makes this unnecessary.

compiler/make_module_file_names.m:
compiler/type_inst_mode_map.m:
compiler/write_deps_file.m:
    Move imports from the interface section to the implementation section,
    in response to the new, more thorough warnings.
This commit is contained in:
Zoltan Somogyi
2025-11-27 17:07:41 +11:00
parent a239de1f5b
commit ae54908b7e
10 changed files with 178 additions and 102 deletions

View File

@@ -1760,7 +1760,6 @@ handle_stack_layout_options(!Globals, OT_OptDups0, OT_OptDups,
% smart_recompilation
% transitive_optimization
% warn_wrong_module_name
% warn_unused_interface_imports
% inform_generated_type_spec_pragmas
% detect_stdlib_grades
%
@@ -1951,7 +1950,6 @@ turn_off_all_only_codegen_warnings(HaltAtWarnSrcOpt, !Globals) :-
% use_trans_opt_files
% verbose_recompilation
% warn_missing_trans_opt_files
% warn_unused_interface_imports
%
:- pred handle_option_to_option_implications(op_mode::in,
globals::in, globals::out) is det.
@@ -2025,17 +2023,7 @@ handle_option_to_option_implications(OpMode, !Globals) :-
% is done when making the `.opt' file. With `--use-opt-files',
% that doesn't happen.
% XXX Should that be "with `--no-use-opt-files'"?
globals.set_option(use_opt_files, bool(no), !Globals),
globals.lookup_bool_option(!.Globals, warn_unused_imports, UnusedImports),
(
UnusedImports = no
;
UnusedImports = yes,
% warn_unused_interface_imports does *part* of the job
% of warn_unused_imports.
globals.set_option(warn_unused_interface_imports, bool(no), !Globals)
).
globals.set_option(use_opt_files, bool(no), !Globals).
% --use-opt-files implies --no-warn-missing-opt-files since
% we are expecting some to be missing.

View File

@@ -246,7 +246,8 @@
% compilation unit.
%
:- pred module_info_init(globals::in, module_name::in, prog_context::in,
string::in, include_module_map::in, used_modules::in, set(module_name)::in,
string::in, include_module_map::in,
used_modules::in, set(module_name)::in, set_tree234(module_name)::in,
partial_qualifier_info::in, maybe(recompilation_info)::in,
type_repn_decision_data::in, module_info::out) is det.
@@ -369,6 +370,8 @@
avail_module_map::out) is det.
:- pred module_info_get_used_modules(module_info::in,
used_modules::out) is det.
:- pred module_info_get_unused_interface_imports(module_info::in,
set_tree234(module_name)::out) is det.
:- pred module_info_get_maybe_complexity_proc_map(module_info::in,
maybe(pair(int, complexity_proc_map))::out) is det.
:- pred module_info_get_complexity_proc_infos(module_info::in,
@@ -987,6 +990,8 @@
% imports/uses of those modules.
mri_used_modules :: used_modules,
mri_unused_interface_imports :: set_tree234(module_name),
% Information about the procedures we are performing
% complexity experiments on.
mri_maybe_complexity_proc_map :: maybe(pair(int,
@@ -1122,7 +1127,7 @@
%---------------------------------------------------------------------------%
module_info_init(Globals, ModuleName, ModuleNameContext, DumpBaseFileName,
InclMap, UsedModules, ImplicitlyUsedModules,
InclMap, UsedModules, ImplicitlyUsedModules, UnusedInterfaceImports,
QualifierInfo, MaybeRecompInfo, TypeRepnDec, ModuleInfo) :-
SpecialPredMaps = special_pred_maps(map.init, map.init, map.init),
map.init(ClassTable),
@@ -1246,6 +1251,7 @@ module_info_init(Globals, ModuleName, ModuleNameContext, DumpBaseFileName,
AvailModuleMap,
AvailModuleSets,
UsedModules,
UnusedInterfaceImports,
MaybeComplexityMap,
ComplexityProcInfos,
ProcAnalysisKinds,
@@ -1430,6 +1436,8 @@ module_info_get_avail_module_sets(MI, X) :-
X = MI ^ mi_rare_info ^ mri_avail_module_sets.
module_info_get_used_modules(MI, X) :-
X = MI ^ mi_rare_info ^ mri_used_modules.
module_info_get_unused_interface_imports(MI, X) :-
X = MI ^ mi_rare_info ^ mri_unused_interface_imports.
module_info_get_maybe_complexity_proc_map(MI, X) :-
X = MI ^ mi_rare_info ^ mri_maybe_complexity_proc_map.
module_info_get_complexity_proc_infos(MI, X) :-

View File

@@ -20,6 +20,8 @@
:- import_module hlds.make_hlds.qual_info.
:- import_module libs.
:- import_module libs.globals.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.
:- import_module parse_tree.equiv_type.
:- import_module parse_tree.error_spec.
@@ -30,23 +32,27 @@
:- import_module io.
:- import_module list.
:- import_module set_tree234.
%---------------------------------------------------------------------------%
% parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals,
% DumpBaseFileName, MQInfo, TypeEqvMap, UsedModules, QualInfo,
% InvalidTypes, InvalidModes, HLDS, Specs):
% DumpBaseFileName, MQInfo0, TypeEqvMap,
% UsedModules, UnusedInterfaceImports,
% QualInfo, InvalidType, InvalidInstOrMode, HLDS, Specs):
%
% Given MQInfo (returned by module_qual.m) and TypeEqvMap and UsedModules
% (both returned by equiv_type.m), convert AugCompUnit to HLDS.
% Return any errors found in Specs.
% Return InvalidTypes = yes if we found undefined types.
% Return InvalidModes = yes if we found undefined or cyclic insts or modes.
% Return InvalidType = yes if we found undefined types.
% Return InvalidInstOrMode = yes if we found undefined or cyclic
% insts or modes.
% QualInfo is an abstract type that check_typeclass.m will later pass
% to produce_instance_method_clauses.
%
:- pred parse_tree_to_hlds(io.text_output_stream::in, aug_compilation_unit::in,
globals::in, string::in, mq_info::in, type_eqv_map::in, used_modules::in,
globals::in, string::in, mq_info::in, type_eqv_map::in,
used_modules::in, set_tree234(module_name)::in,
qual_info::out, found_invalid_type::out, found_invalid_inst_or_mode::out,
module_info::out, list(error_spec)::out) is det.
@@ -77,10 +83,8 @@
:- import_module hlds.special_pred.
:- import_module hlds.status.
:- import_module libs.options.
:- import_module mdbcomp.
:- import_module mdbcomp.builtin_modules.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.error_util.
:- import_module parse_tree.get_dependencies.
:- import_module parse_tree.maybe_error.
@@ -105,7 +109,6 @@
:- import_module pair.
:- import_module require.
:- import_module set.
:- import_module set_tree234.
:- import_module term_context.
:- import_module term_subst.
:- import_module varset.
@@ -113,7 +116,7 @@
%---------------------------------------------------------------------------%
parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
MQInfo0, TypeEqvMap, UsedModules, !:QualInfo,
MQInfo0, TypeEqvMap, UsedModules, UnusedInterfaceImports, !:QualInfo,
!:FoundInvalidType, !:FoundInvalidInstOrMode, !:ModuleInfo, !:Specs) :-
ParseTreeModuleSrc = AugCompUnit ^ acu_module_src,
maybe_warn_include_and_non_include(Globals, ParseTreeModuleSrc, InclSpecs),
@@ -218,8 +221,8 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
TypeRepnDec = type_repn_decision_data(TypeRepnMap, DirectArgMap,
ForeignEnums, ForeignExportEnums),
module_info_init(Globals, ModuleName, ModuleNameContext, DumpBaseFileName,
InclMap, UsedModules, ImplicitlyUsedModules, PQInfo, no, TypeRepnDec,
!:ModuleInfo),
InclMap, UsedModules, ImplicitlyUsedModules, UnusedInterfaceImports,
PQInfo, no, TypeRepnDec, !:ModuleInfo),
% The old pass 1.

View File

@@ -30,7 +30,6 @@
:- import_module io.
:- import_module list.
:- import_module map.
:- import_module set.
%---------------------------------------------------------------------------%
@@ -66,6 +65,7 @@
:- implementation.
:- import_module map.
:- import_module string.
:- import_module uint.

View File

@@ -170,7 +170,7 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
"% Module qualifying items...\n", !IO),
maybe_flush_output(ProgressStream, Verbose, !IO),
module_qualify_aug_comp_unit(Globals, AugCompUnit1, AugCompUnit2,
EventSpecMap0, EventSpecMap1, EventSetFileName, MQInfo0,
EventSpecMap0, EventSpecMap1, EventSetFileName, MQInfo0, UnusedImports,
MQUndefTypes, MQUndefInsts, MQUndefModes, MQUndefTypeClasses,
[], QualifySpecs),
!:Specs = QualifySpecs ++ !.Specs,
@@ -194,8 +194,8 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
EventSet = event_set(EventSetName, EventSpecMap),
make_hlds(ProgressStream, ErrorStream, Globals, AugCompUnit, EventSet,
MQInfo, TypeEqvMap, UsedModules, Verbose, Stats, HLDS0, QualInfo,
MakeHLDSFoundInvalidType, MakeHLDSFoundInvalidInstOrMode,
MQInfo, TypeEqvMap, UsedModules, UnusedImports, Verbose, Stats, HLDS0,
QualInfo, MakeHLDSFoundInvalidType, MakeHLDSFoundInvalidInstOrMode,
FoundSemanticError, !Specs, !IO),
bool.or(FoundSemanticError, IntermodError, PreHLDSErrors),
maybe_write_definitions(ProgressStream,
@@ -610,14 +610,14 @@ maybe_grab_plain_and_trans_opt_files(ProgressStream, ErrorStream, Globals,
:- pred make_hlds(io.text_output_stream::in, io.text_output_stream::in,
globals::in, aug_compilation_unit::in, event_set::in, mq_info::in,
type_eqv_map::in, used_modules::in, bool::in, bool::in,
module_info::out, qual_info::out,
type_eqv_map::in, used_modules::in, set_tree234(module_name)::in,
bool::in, bool::in, module_info::out, qual_info::out,
found_invalid_type::out, found_invalid_inst_or_mode::out, bool::out,
list(error_spec)::in, list(error_spec)::out, io::di, io::uo) is det.
make_hlds(ProgressStream, ErrorStream, Globals, AugCompUnit, EventSet, MQInfo,
TypeEqvMap, UsedModules, Verbose, Stats, !:HLDS, QualInfo,
FoundInvalidType, FoundInvalidInstOrMode,
TypeEqvMap, UsedModules, UnusedImports, Verbose, Stats, !:HLDS,
QualInfo, FoundInvalidType, FoundInvalidInstOrMode,
FoundSemanticError, !Specs, !IO) :-
maybe_write_out_errors(ErrorStream, Verbose, Globals, !Specs, !IO),
maybe_write_string(ProgressStream, Verbose,
@@ -627,7 +627,7 @@ make_hlds(ProgressStream, ErrorStream, Globals, AugCompUnit, EventSet, MQInfo,
module_name_to_cur_dir_file_name(ext_cur_user_hlds_dump,
ModuleName, DumpBaseFileName),
parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
MQInfo, TypeEqvMap, UsedModules, QualInfo,
MQInfo, TypeEqvMap, UsedModules, UnusedImports, QualInfo,
FoundInvalidType, FoundInvalidInstOrMode, !:HLDS, MakeSpecs),
!:Specs = MakeSpecs ++ !.Specs,
module_info_set_event_set(EventSet, !HLDS),

View File

@@ -19,6 +19,8 @@
:- import_module libs.
:- import_module libs.globals.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.error_spec.
:- import_module parse_tree.module_qual.id_set.
:- import_module parse_tree.module_qual.mq_info.
@@ -33,7 +35,8 @@
% module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
% EventSpecMap0, EventSpecMap, MaybeContext, EventSpecFileName, MQ_Info,
% UndefTypes, UndefInsts, UndefModes, UndefTypeClasses, !Specs):
% UnusedImportsSet, UndefTypes, UndefInsts, UndefModes,
% UndefTypeClasses, !Specs):
%
% AugCompUnit is AugCompUnit0 with all items module qualified
% as much as possible; likewise for EventSpecMap0 and EventSpecMap.
@@ -43,6 +46,7 @@
:- pred module_qualify_aug_comp_unit(globals::in,
aug_compilation_unit::in, aug_compilation_unit::out,
event_spec_map::in, event_spec_map::out, string::in, mq_info::out,
set_tree234(module_name)::out,
set_tree234(type_ctor)::out, set_tree234(inst_ctor)::out,
set_tree234(mode_ctor)::out, set_tree234(sym_name_arity)::out,
list(error_spec)::in, list(error_spec)::out) is det.
@@ -88,8 +92,6 @@
:- implementation.
:- import_module libs.options.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.module_qual.collect_mq_info.
:- import_module parse_tree.module_qual.qual_errors.
:- import_module parse_tree.prog_data_foreign.
@@ -115,7 +117,8 @@
module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
EventSpecMap0, EventSpecMap, EventSpecFileName, !:Info,
UndefTypes, UndefInsts, UndefModes, UndefTypeClasses, !Specs) :-
UnusedImportsSet, UndefTypes, UndefInsts, UndefModes,
UndefTypeClasses, !Specs) :-
AugCompUnit0 = aug_compilation_unit(ParseTreeModuleSrc0,
AncestorIntSpecs, DirectInt1Specs, IndirectInt2Specs,
PlainOptSpecs, TransOptSpecs, IntForOptSpecs, TypeRepnSpecs,
@@ -143,7 +146,34 @@ module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
mq_info_get_undef_insts(!.Info, UndefInsts),
mq_info_get_undef_modes(!.Info, UndefModes),
mq_info_get_undef_typeclasses(!.Info, UndefTypeClasses),
maybe_report_qual_warnings(Globals, !.Info, ModuleName, !Specs).
globals.lookup_bool_option(Globals, warn_unused_interface_imports,
WarnUnusedInterfaceImports),
globals.lookup_bool_option(Globals, warn_unused_imports,
WarnUnusedImports),
( if
( WarnUnusedInterfaceImports = yes
; WarnUnusedImports = yes
)
then
get_unused_imports_map(!.Info, UnusedImportsMap),
map.keys(UnusedImportsMap, UnusedImports),
set_tree234.sorted_list_to_set(UnusedImports, UnusedImportsSet),
(
WarnUnusedImports = yes
% The unused imports will be reported later by unused_imports.m.
% That is why we return UnusedImportsSet to our caller, to be
% stored in the HLDS until unused_imports.m can look at it.
;
WarnUnusedImports = no,
% We can get here only if WarnUnusedInterfaceImports is yes.
map.to_assoc_list(UnusedImportsMap, UnusedImportsAL),
list.foldl(warn_unused_interface_import(ModuleName),
UnusedImportsAL, !Specs)
)
else
UnusedImportsSet = set_tree234.init
).
%---------------------%
@@ -166,12 +196,24 @@ module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
AugMakeIntUnit = aug_make_int_unit(ParseTreeModuleSrc, DelayedSpecs0,
AncestorInt0s, DirectInt3Specs, IndirectInt3Specs,
ModuleVersionNumbers),
maybe_report_qual_warnings(Globals, !.Info, ModuleName, !Specs)
globals.lookup_bool_option(Globals, warn_interface_imports,
WarnInterfaceImports),
(
WarnInterfaceImports = no
;
WarnInterfaceImports = yes,
get_unused_imports_map(!.Info, UnusedImportsMap),
map.to_assoc_list(UnusedImportsMap, UnusedImports),
list.foldl(warn_unused_interface_import(ModuleName), UnusedImports,
!Specs)
)
).
%---------------------%
% Warn about any unused module imports in the interface.
% Compute the set of unused module imports in the interface,
% so we can warn about them.
%
% There is a special case involving type class instances that
% we need to handle here. Consider:
%
@@ -196,30 +238,19 @@ module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
% the interface of the importing module, except if the importing
% module itself exports _no_ type class instances.
%
:- pred maybe_report_qual_warnings(globals::in, mq_info::in, module_name::in,
list(error_spec)::in, list(error_spec)::out) is det.
:- pred get_unused_imports_map(mq_info::in, module_names_contexts::out) is det.
maybe_report_qual_warnings(Globals, Info, ModuleName, !Specs) :-
globals.lookup_bool_option(Globals, warn_interface_imports,
WarnInterfaceImports),
get_unused_imports_map(Info, UnusedImportsMap) :-
mq_info_get_as_yet_unused_interface_modules(Info, UnusedImportsMap0),
mq_info_get_exported_instances_flag(Info, ModuleExportsInstances),
(
WarnInterfaceImports = no
ModuleExportsInstances = yes,
mq_info_get_imported_instance_modules(Info, InstanceImports),
map.delete_list(set_tree234.to_sorted_list(InstanceImports),
UnusedImportsMap0, UnusedImportsMap)
;
WarnInterfaceImports = yes,
mq_info_get_as_yet_unused_interface_modules(Info, UnusedImportsMap0),
mq_info_get_exported_instances_flag(Info, ModuleExportsInstances),
(
ModuleExportsInstances = yes,
mq_info_get_imported_instance_modules(Info, InstanceImports),
map.delete_list(set_tree234.to_sorted_list(InstanceImports),
UnusedImportsMap0, UnusedImportsMap)
;
ModuleExportsInstances = no,
UnusedImportsMap = UnusedImportsMap0
),
map.to_assoc_list(UnusedImportsMap, UnusedImports),
list.foldl(warn_unused_interface_import(ModuleName), UnusedImports,
!Specs)
ModuleExportsInstances = no,
UnusedImportsMap = UnusedImportsMap0
).
%---------------------%

View File

@@ -1,7 +1,7 @@
%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2016, 2022 The Mercury team.
% Copyright (C) 2016, 2022, 2025 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.
%---------------------------------------------------------------------------%
@@ -16,15 +16,15 @@
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module set.
:- import_module set_tree234.
%---------------------------------------------------------------------------%
:- type used_modules
---> used_modules(
% The modules used in the interface and implementation.
int_used_modules :: set(module_name),
imp_used_modules :: set(module_name)
int_used_modules :: set_tree234(module_name),
imp_used_modules :: set_tree234(module_name)
).
:- type item_visibility
@@ -58,7 +58,7 @@
:- import_module list.
used_modules_init = used_modules(set.init, set.init).
used_modules_init = used_modules(set_tree234.init, set_tree234.init).
record_sym_name_module_as_used(Visibility, SymName, !UsedModules) :-
(
@@ -83,10 +83,10 @@ record_module_and_ancestors_as_used(Visibility, ModuleName, !UsedModules) :-
).
:- pred add_module_and_ancestors(sym_name::in,
set(module_name)::in, set(module_name)::out) is det.
set_tree234(module_name)::in, set_tree234(module_name)::out) is det.
add_module_and_ancestors(ModuleName, !UsedModuleNames) :-
set.insert(ModuleName, !UsedModuleNames),
set_tree234.insert(ModuleName, !UsedModuleNames),
(
ModuleName = unqualified(_)
;
@@ -98,7 +98,7 @@ record_format_modules_as_used(!UsedModules) :-
ImpUsedModules0 = !.UsedModules ^ imp_used_modules,
FormatModules = [mercury_string_format_module,
mercury_string_parse_util_module, mercury_stream_module],
set.insert_list(FormatModules, ImpUsedModules0, ImpUsedModules),
set_tree234.insert_list(FormatModules, ImpUsedModules0, ImpUsedModules),
!UsedModules ^ imp_used_modules := ImpUsedModules.
%---------------------------------------------------------------------------%

View File

@@ -19,7 +19,6 @@
:- module parse_tree.type_inst_mode_map.
:- interface.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_item.
:- import_module list.
@@ -70,6 +69,7 @@
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.item_util.
:- import_module parse_tree.prog_data.
:- import_module cord.
:- import_module map.

View File

@@ -78,7 +78,7 @@
:- import_module one_or_more_map.
:- import_module pair.
:- import_module pretty_printer.
:- import_module set.
:- import_module set_tree234.
:- import_module string.
:- import_module term.
@@ -94,23 +94,65 @@ warn_about_unused_imports(ProgressStream, ModuleInfo, !:Specs) :-
get_avail_modules_anywhere_interface(ModuleAvails,
cord.init, AvailAnywhereCord,
cord.init, AvailInterfaceCord),
set.sorted_list_to_set(cord.list(AvailAnywhereCord),
set_tree234.sorted_list_to_set(cord.list(AvailAnywhereCord),
AvailAnywhereModules),
set.sorted_list_to_set(cord.list(AvailInterfaceCord),
set_tree234.sorted_list_to_set(cord.list(AvailInterfaceCord),
AvailInterfaceModules),
UsedInInterface = UsedModules ^ int_used_modules,
UsedInImplementation = UsedModules ^ imp_used_modules,
UsedAnywhere = set.union(UsedInInterface, UsedInImplementation),
UsedAnywhere = set_tree234.union(UsedInInterface, UsedInImplementation),
% The unused imports is simply the set of all imports minus all the
% used modules.
set.difference(AvailAnywhereModules, UsedAnywhere, UnusedAnywhereImports),
set_tree234.difference(AvailAnywhereModules, UsedAnywhere,
UnusedAnywhereImports),
% Determine the modules imported in the interface but not used in
% the interface.
UnusedInterfaceImports =
set.difference(AvailInterfaceModules, UsedInInterface),
set_tree234.difference(AvailInterfaceModules, UsedInInterface,
UnusedInterfaceImports0),
% As its name implies, UnusedInterfaceImports0 contains a subset
% of the modules that are imported in the interface. Specifically,
% it contains the subset that are not used in the interface *now*.
% However, it misses some imports that don't need to be in the interface
% because they are not used in the interface *when the HLDS is initially
% constructed*.
%
% To see the difference, consider a module A that imports module B
% in its interface. Module A's interface starts out containing
% no references to anything defined in module B, but it does contain
% a reference to a type tc, which defined in module C, which module A
% also imports in its interface. If module C defines and exports type tc
% as an equivalence type, *and* if the right hand side of that equivalence
% contains a reference to a type defined by module B, then module A's
% interface *will* contains a reference to that type from B after
% equiv_type.m has done its job. The same thing can also happen
% with inst and mode definitions.
%
% There are two obvious approaches to fixing this problem.
%
% Approach 1 is to extend the parse tree's representations of
% all the items that contain types, insts and modes (including
% type definitions, predicate and mode declarations, and typeclass
% method declarations) with a copy of every type, inst and mode that
% equiv_type.m would leave alone. We would then copy all those fields
% into their HLDS equivalents, and then get find_all_non_warn_modules
% to process those fields.
%
% Approach 2 is to remember which modules imported in the interface
% are not used in the interface during a traversal that we already perform,
% the module qualification pass (module_qual.m), which occurs *before*
% we invoked equiv_type.m.
%
% We use approach 2, both because it requires a lot less code, and because
% it imposes a much smaller memory overhead. The value returned by
% module_info_get_unused_interface_imports is the value computed by
% the module qualification pass.
module_info_get_unused_interface_imports(ModuleInfo,
UnusedInterfaceImports1),
set_tree234.union(UnusedInterfaceImports0, UnusedInterfaceImports1,
UnusedInterfaceImports),
trace [compile_time(flag("debug_unused_imports")),
runtime(env("DEBUG_UNUSED_IMPORTS")), io(!IO)]
@@ -192,7 +234,8 @@ get_avail_modules_anywhere_interface([ModuleEntry | ModuleEntries],
:- type unused_avail_map ==
one_or_more_map(unused_avail_msg_kind, unused_avail).
:- pred maybe_warn_about_avail(set(module_name)::in, set(module_name)::in,
:- pred maybe_warn_about_avail(
set_tree234(module_name)::in, set_tree234(module_name)::in,
module_name::in, avail_module_entry::in,
list(error_spec)::in, list(error_spec)::out,
unused_avail_map::in, unused_avail_map::out) is det.
@@ -217,7 +260,7 @@ maybe_warn_about_avail(UnusedAnywhereImports, UnusedInterfaceImports,
HeadAvail = avail_module(Section, ImportOrUse, HeadCtxt),
maybe_generate_redundant_avail_warnings(ModuleName, SortedAvails,
[], !Specs),
( if set.contains(UnusedAnywhereImports, ModuleName) then
( if set_tree234.contains(UnusedAnywhereImports, ModuleName) then
MsgKindA = unused_avail_msg_kind(aoi_anywhere, ImportOrUse),
one_or_more_map.add(MsgKindA, unused_avail(HeadCtxt, ModuleName),
!UnusedAvailMap),
@@ -227,7 +270,7 @@ maybe_warn_about_avail(UnusedAnywhereImports, UnusedInterfaceImports,
),
( if
Section = ms_interface,
set.contains(UnusedInterfaceImports, ModuleName),
set_tree234.contains(UnusedInterfaceImports, ModuleName),
% Do not generate a report that a module is unused in the interface
% if we have generated a report that it is unused *anywhere*.
AnywhereWarning = no
@@ -506,36 +549,36 @@ find_all_non_warn_modules(ProgressStream, ModuleInfo, !:UsedModules) :-
"instances" - UsedModulesInstance,
"builtin" - UsedModulesBuiltin
],
dump_used_modules_history(ProgressStream, set.init, set.init,
UsedModulesHistory, !IO)
dump_used_modules_history(ProgressStream,
set_tree234.init, set_tree234.init, UsedModulesHistory, !IO)
).
:- pred dump_used_modules_history(io.text_output_stream::in,
set(module_name)::in, set(module_name)::in,
set_tree234(module_name)::in, set_tree234(module_name)::in,
assoc_list(string, used_modules)::in, io::di, io::uo) is det.
dump_used_modules_history(_, _, _, [], !IO).
dump_used_modules_history(ProgressStream, !.IntUsed, !.ImpUsed,
[Head | Tail], !IO) :-
Head = HeadStr - used_modules(HeadInt, HeadImp),
set.difference(HeadInt, !.IntUsed, NewHeadInt),
set.difference(HeadImp, !.ImpUsed, NewHeadImp),
set_tree234.difference(HeadInt, !.IntUsed, NewHeadInt),
set_tree234.difference(HeadImp, !.ImpUsed, NewHeadImp),
io.format(ProgressStream, "modules added at stage %s\n\n",
[s(HeadStr)], !IO),
( if set.is_empty(NewHeadInt) then
( if set_tree234.is_empty(NewHeadInt) then
true
else
io.write_string(ProgressStream, "interface:\n", !IO),
output_module_name_set_nl(ProgressStream, NewHeadInt, !IO)
),
( if set.is_empty(NewHeadImp) then
( if set_tree234.is_empty(NewHeadImp) then
true
else
io.write_string(ProgressStream, "implementation:\n", !IO),
output_module_name_set_nl(ProgressStream, NewHeadImp, !IO)
),
set.union(HeadInt, !IntUsed),
set.union(HeadImp, !ImpUsed),
set_tree234.union(HeadInt, !IntUsed),
set_tree234.union(HeadImp, !ImpUsed),
dump_used_modules_history(ProgressStream, !.IntUsed, !.ImpUsed, Tail, !IO).
%-----------------------------------------------------------------------------%
@@ -759,8 +802,9 @@ const_struct_used_modules(ProgressStream, ConstNum - ConstStruct,
FinalUsedModules = !.UsedModules,
InitUsedModules = used_modules(_InitIntModules, InitImpModules),
FinalUsedModules = used_modules(_FinalIntModules, FinalImpModules),
set.difference(FinalImpModules, InitImpModules, NewImpModules),
( if set.is_empty(NewImpModules) then
set_tree234.difference(FinalImpModules, InitImpModules,
NewImpModules),
( if set_tree234.is_empty(NewImpModules) then
true
else
ConstStructDoc = pretty_printer.format(ConstStruct),
@@ -834,16 +878,18 @@ pred_info_used_modules(ProgressStream, PredId, PredInfo, !UsedModules) :-
FinalUsedModules = !.UsedModules,
InitUsedModules = used_modules(InitIntModules, InitImpModules),
FinalUsedModules = used_modules(FinalIntModules, FinalImpModules),
set.difference(FinalIntModules, InitIntModules, NewIntModules),
set.difference(FinalImpModules, InitImpModules, NewImpModules),
( if set.is_empty(NewIntModules) then
set_tree234.difference(FinalIntModules, InitIntModules,
NewIntModules),
set_tree234.difference(FinalImpModules, InitImpModules,
NewImpModules),
( if set_tree234.is_empty(NewIntModules) then
true
else
io.write_string(ProgressStream,
"new interface modules:\n", !IO),
output_module_name_set_nl(ProgressStream, NewIntModules, !IO)
),
( if set.is_empty(NewImpModules) then
( if set_tree234.is_empty(NewImpModules) then
true
else
io.write_string(ProgressStream,
@@ -1255,11 +1301,11 @@ exported_to_visibility(Exported) = Visibility :-
%-----------------------------------------------------------------------------%
:- pred output_module_name_set_nl(io.text_output_stream::in,
set(module_name)::in, io::di, io::uo) is det.
set_tree234(module_name)::in, io::di, io::uo) is det.
output_module_name_set_nl(Stream, ModuleNameSet, !IO) :-
ModuleNameStrSet = set.map(sym_name_to_string, ModuleNameSet),
set.to_sorted_list(ModuleNameStrSet, ModuleNameStrs),
ModuleNameStrSet = set_tree234.map(sym_name_to_string, ModuleNameSet),
set_tree234.to_sorted_list(ModuleNameStrSet, ModuleNameStrs),
list.foldl(write_string_nl(Stream), ModuleNameStrs, !IO),
io.nl(Stream, !IO).

View File

@@ -45,8 +45,6 @@
:- import_module libs.
:- import_module libs.globals.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.d_file_deps.
:- import_module parse_tree.deps_map.
:- import_module parse_tree.error_spec.
@@ -116,6 +114,8 @@
:- import_module libs.file_util.
:- import_module libs.mmakefiles.
:- import_module libs.options.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.file_names.
:- import_module parse_tree.make_module_file_names.
:- import_module parse_tree.maybe_error.