From ae54908b7ea7606546e465ca40d29675bfa0e080 Mon Sep 17 00:00:00 2001 From: Zoltan Somogyi Date: Thu, 27 Nov 2025 17:07:41 +1100 Subject: [PATCH] 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. --- compiler/handle_options.m | 14 +--- compiler/hlds_module.m | 12 +++- compiler/make_hlds_passes.m | 25 ++++--- compiler/make_module_file_names.m | 2 +- compiler/mercury_compile_make_hlds.m | 16 ++--- compiler/module_qual.qualify_items.m | 87 +++++++++++++++-------- compiler/prog_data_used_modules.m | 16 ++--- compiler/type_inst_mode_map.m | 2 +- compiler/unused_imports.m | 102 +++++++++++++++++++-------- compiler/write_deps_file.m | 4 +- 10 files changed, 178 insertions(+), 102 deletions(-) diff --git a/compiler/handle_options.m b/compiler/handle_options.m index d77f2fa35..11bc2c8cf 100644 --- a/compiler/handle_options.m +++ b/compiler/handle_options.m @@ -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. diff --git a/compiler/hlds_module.m b/compiler/hlds_module.m index 47cd77c61..710d9da88 100644 --- a/compiler/hlds_module.m +++ b/compiler/hlds_module.m @@ -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) :- diff --git a/compiler/make_hlds_passes.m b/compiler/make_hlds_passes.m index f8ecf088c..726642980 100644 --- a/compiler/make_hlds_passes.m +++ b/compiler/make_hlds_passes.m @@ -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. diff --git a/compiler/make_module_file_names.m b/compiler/make_module_file_names.m index 3b0bbf6f0..692c5f4b8 100644 --- a/compiler/make_module_file_names.m +++ b/compiler/make_module_file_names.m @@ -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. diff --git a/compiler/mercury_compile_make_hlds.m b/compiler/mercury_compile_make_hlds.m index 4138b8215..33ad3afbc 100644 --- a/compiler/mercury_compile_make_hlds.m +++ b/compiler/mercury_compile_make_hlds.m @@ -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), diff --git a/compiler/module_qual.qualify_items.m b/compiler/module_qual.qualify_items.m index f4c6e6dbb..d98cf1c54 100644 --- a/compiler/module_qual.qualify_items.m +++ b/compiler/module_qual.qualify_items.m @@ -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 ). %---------------------% diff --git a/compiler/prog_data_used_modules.m b/compiler/prog_data_used_modules.m index b62ce6e7a..b4f024143 100644 --- a/compiler/prog_data_used_modules.m +++ b/compiler/prog_data_used_modules.m @@ -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. %---------------------------------------------------------------------------% diff --git a/compiler/type_inst_mode_map.m b/compiler/type_inst_mode_map.m index ebdc0aee1..4e5a7c180 100644 --- a/compiler/type_inst_mode_map.m +++ b/compiler/type_inst_mode_map.m @@ -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. diff --git a/compiler/unused_imports.m b/compiler/unused_imports.m index b829b80fa..4b82523b2 100644 --- a/compiler/unused_imports.m +++ b/compiler/unused_imports.m @@ -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). diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m index b540480b8..b5459d0c4 100644 --- a/compiler/write_deps_file.m +++ b/compiler/write_deps_file.m @@ -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.