mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
Fix some mispelled variable names.
compiler/accumulator.m:
compiler/check_import_accessibility.m:
compiler/decide_type_repn.m:
compiler/du_type_layout.m:
compiler/error_spec.m:
compiler/hlds_data.m:
compiler/hlds_goal.m:
compiler/mlds.m:
compiler/parse_item.m:
compiler/prog_data.m:
compiler/type_util.m:
As above.
1033 lines
44 KiB
Mathematica
1033 lines
44 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2023-2026 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_import_accessibility.m.
|
|
% Main author: fjh (original), zs (current).
|
|
%
|
|
% Given the parse tree of a module, and information about the accessibility
|
|
% of included and/or imported modules gathered by our caller from either
|
|
% an aug_compilation_unit or an aug_make_int_unit, we look for and report
|
|
% two different but related kinds of errors.
|
|
%
|
|
% The first is when we see a reference to module x.y.z, but module x.y
|
|
% does not include a submodule named z.
|
|
%
|
|
% The second is when module m.n has an import_module or use_module
|
|
% declaration for module x.y.z, but there is some ancestor of x.y.z
|
|
% (either x or x.y) that neither m.n nor its ancestor m imports or uses.
|
|
%
|
|
% XXX ITEM_LIST We should either record in an updated AugCompUnit
|
|
% the set of imported modules that are inaccessible, or remove their
|
|
% imports from it, so that
|
|
%
|
|
% - when we report e.g. an undefined type, we don't tell the user that
|
|
% the module that defines the type hasn't been imported, when in fact
|
|
% it *was* imported, but the import was disregarded because the module
|
|
% is inaccessible due to the missing import of an ancestor; and
|
|
%
|
|
% - we don't generate "unused module" warnings for them when
|
|
% --warn-unused-imports is enabled.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.check_import_accessibility.
|
|
:- interface.
|
|
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.prog_parse_tree.
|
|
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type import_accessibility_info.
|
|
|
|
% Generate the information that the main part of this module,
|
|
% check_import_accessibility, needs.
|
|
%
|
|
% This part needs to be done slightly differently for
|
|
% aug_compilation_units and aug_make_int_units, which is why
|
|
% this part of the job is separated out.
|
|
%
|
|
:- pred aug_comp_unit_get_import_accessibility_info(aug_compilation_unit::in,
|
|
import_accessibility_info::out) is det.
|
|
:- pred aug_make_int_unit_get_import_accessibility_info(aug_make_int_unit::in,
|
|
import_accessibility_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% check_import_accessibility(ParseTreeModuleSrc, ImportAccessibilityInfo,
|
|
% MissingModulesInt, MissingModulesImp, DelayedSpecs, Specs):
|
|
%
|
|
% This predicate does the job described in the top-of-module comment.
|
|
% It also returns the list of modules for which at least use_module,
|
|
% if not import_module, declarations are missing from the interface
|
|
% and implementation sections respectively. Any errors caused by these
|
|
% are returned in DelayedSpecs, not Specs.
|
|
%
|
|
:- pred check_import_accessibility(parse_tree_module_src::in,
|
|
import_accessibility_info::in,
|
|
list(module_name)::out, list(module_name)::out,
|
|
list(error_spec)::out, list(error_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module parse_tree.convert_import_use.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_item.
|
|
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module one_or_more.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module term_context.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% aug_{comp,make_int}_unit_get_import_accessibility_info both generate
|
|
% a value of type import_accessibility_info by scanning the relevant kinds
|
|
% of items in the input structures they are given.
|
|
%
|
|
% - The iai_read_modules field will contain the set of module names
|
|
% from whose files (source files, interface files, optimization files)
|
|
% the information in the rest of the fields originates.
|
|
%
|
|
% - The iai_inclusion_map field will map the name of each module
|
|
% that is named in an include_module declaration in the input
|
|
% data structure to the context of that declaration.
|
|
%
|
|
% The iai_seen_includes field, supplied by the caller, specifies
|
|
% whether any include_module declarations in the read-in modules
|
|
% may be intentionally missing from this map. When the input is
|
|
% an aug_compilation_unit, all include_module declarations in the
|
|
% relevant modules will be in this map, but when the input is
|
|
% an aug_make_int_unit, the map will contain information only about
|
|
% include_module declarations in the interface sections of those modules
|
|
% (since the .int3 files we read in from them contain nothing at all
|
|
% from the implementation section).
|
|
%
|
|
% - The iai_src_int_import_use_map field will map the module names
|
|
% that occur in import_module or use_module declarations in the
|
|
% interface sections of the given parse_tree_module_src itself
|
|
% to the context(s) of those declarations.
|
|
%
|
|
% - The iai_src_imp_import_use_map field contains the same info
|
|
% for the implementation section.
|
|
%
|
|
% - The iai_ancestor_import_use_map field again contains the same info,
|
|
% but for import_module and use_module declarations read from
|
|
% (the .int0 interface files of) the ancestors of the
|
|
% parse_tree_module_src.
|
|
%
|
|
% NOTE By making the value in both the module_inclusion_map and the
|
|
% module_import_or_use_map a (nonempty) list, we can represent situations
|
|
% in which a module includes, imports or uses another module
|
|
% more than once. This is an error, and we could and probably should
|
|
% diagnose it here, but doing so would require disabling the code
|
|
% we have elsewhere in the compiler that does that job. If we did that,
|
|
% we could replace the nonempty lists of contexts with just one context,
|
|
% and a message for every other context.
|
|
%
|
|
:- type import_accessibility_info
|
|
---> import_accessibility_info(
|
|
iai_read_modules :: set(module_name),
|
|
iai_seen_includes :: seen_includes,
|
|
iai_inclusion_map :: module_inclusion_map,
|
|
iai_src_int_import_use_map :: module_import_or_use_map,
|
|
iai_src_imp_import_use_map :: module_import_or_use_map,
|
|
iai_ancestor_import_use_map :: module_import_or_use_map
|
|
).
|
|
|
|
:- type seen_includes
|
|
---> seen_only_int_includes
|
|
; seen_all_includes.
|
|
|
|
% The module_inclusion_map and module_import_or_use_map are computed by
|
|
% record_includes_imports_uses, for use by find_any_missing_ancestor_imports.
|
|
% For their documentation, see those predicates below.
|
|
|
|
:- type maybe_abstract_section
|
|
---> non_abstract_section
|
|
; abstract_section.
|
|
|
|
:- type include_context
|
|
---> include_context(maybe_abstract_section, term_context).
|
|
|
|
:- type module_inclusion_map ==
|
|
map(module_name, one_or_more(include_context)).
|
|
|
|
:- type import_or_use_context
|
|
---> import_or_use_context(import_or_use, term_context).
|
|
|
|
:- type module_import_or_use_map ==
|
|
map(module_name, one_or_more(import_or_use_context)).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
aug_comp_unit_get_import_accessibility_info(AugCompUnit,
|
|
ImportAccessibilityInfo) :-
|
|
AugCompUnit = aug_compilation_unit(ParseTreeModuleSrc, AncestorIntSpecs,
|
|
DirectIntSpecs, IndirectIntSpecs, PlainOpts, _TransOpts,
|
|
IntForOptSpecs, _TypeRepnSpecs, _ModuleVersionNumbers),
|
|
some [!ReadModules, !InclMap, !SrcIntImportUseMap, !SrcImpImportUseMap,
|
|
!AncestorImportUseMap]
|
|
(
|
|
set.init(!:ReadModules),
|
|
map.init(!:InclMap),
|
|
map.init(!:SrcIntImportUseMap),
|
|
map.init(!:SrcImpImportUseMap),
|
|
map.init(!:AncestorImportUseMap),
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
Ancestors = get_ancestors_set(ModuleName),
|
|
record_includes_imports_uses_in_parse_tree_module_src(
|
|
ParseTreeModuleSrc,
|
|
!ReadModules, !InclMap, !SrcIntImportUseMap, !SrcImpImportUseMap),
|
|
map.foldl3_values(
|
|
record_includes_imports_uses_in_ancestor_int_spec(Ancestors),
|
|
AncestorIntSpecs, !ReadModules, !InclMap, !AncestorImportUseMap),
|
|
map.foldl2_values(
|
|
record_includes_imports_uses_in_direct_int1_spec(Ancestors),
|
|
DirectIntSpecs, !ReadModules, !InclMap),
|
|
map.foldl2_values(
|
|
record_includes_imports_uses_in_indirect_int2_spec(Ancestors),
|
|
IndirectIntSpecs, !ReadModules, !InclMap),
|
|
map.foldl_values(
|
|
record_includes_imports_uses_in_parse_tree_plain_opt(Ancestors),
|
|
PlainOpts, !AncestorImportUseMap),
|
|
% .trans_opt files may contain no include_module, import_module
|
|
% or use_module declarations, so there is nothing to record for them.
|
|
map.foldl3_values(
|
|
record_includes_imports_uses_in_int_for_opt_spec(Ancestors),
|
|
IntForOptSpecs, !ReadModules, !InclMap, !AncestorImportUseMap),
|
|
ImportAccessibilityInfo = import_accessibility_info(!.ReadModules,
|
|
seen_all_includes, !.InclMap,
|
|
!.SrcIntImportUseMap, !.SrcImpImportUseMap, !.AncestorImportUseMap)
|
|
).
|
|
|
|
aug_make_int_unit_get_import_accessibility_info(AugMakeIntUnit,
|
|
ImportAccessibilityInfo) :-
|
|
AugMakeIntUnit = aug_make_int_unit(ParseTreeModuleSrc, _, AncestorIntSpecs,
|
|
DirectIntSpecs, IndirectIntSpecs, _ModuleVersionNumbers),
|
|
some [!ReadModules, !InclMap, !SrcIntImportUseMap, !SrcImpImportUseMap,
|
|
!AncestorImportUseMap]
|
|
(
|
|
set.init(!:ReadModules),
|
|
map.init(!:InclMap),
|
|
map.init(!:SrcIntImportUseMap),
|
|
map.init(!:SrcImpImportUseMap),
|
|
map.init(!:AncestorImportUseMap),
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
Ancestors = get_ancestors_set(ModuleName),
|
|
record_includes_imports_uses_in_parse_tree_module_src(
|
|
ParseTreeModuleSrc,
|
|
!ReadModules, !InclMap, !SrcIntImportUseMap, !SrcImpImportUseMap),
|
|
map.foldl3_values(
|
|
record_includes_imports_uses_in_parse_tree_int0(Ancestors),
|
|
AncestorIntSpecs, !ReadModules, !InclMap, !AncestorImportUseMap),
|
|
map.foldl2_values(
|
|
record_includes_imports_uses_in_direct_int3_spec(Ancestors),
|
|
DirectIntSpecs, !ReadModules, !InclMap),
|
|
map.foldl2_values(
|
|
record_includes_imports_uses_in_indirect_int3_spec(Ancestors),
|
|
IndirectIntSpecs, !ReadModules, !InclMap),
|
|
ImportAccessibilityInfo = import_accessibility_info(!.ReadModules,
|
|
seen_only_int_includes, !.InclMap,
|
|
!.SrcIntImportUseMap, !.SrcImpImportUseMap, !.AncestorImportUseMap)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred record_includes_imports_uses_in_parse_tree_module_src(
|
|
parse_tree_module_src::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_parse_tree_module_src(ParseTreeModuleSrc,
|
|
!ReadModules, !MaybeAbstractInclMap,
|
|
!SrcIntImportUseMap, !SrcImpImportUseMap) :-
|
|
ParseTreeModuleSrc = parse_tree_module_src(ModuleName, _,
|
|
InclMap, ImportUseMap,
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _),
|
|
set.insert(ModuleName, !ReadModules),
|
|
map.foldl(record_include(non_abstract_section, yes(non_abstract_section)),
|
|
InclMap, !MaybeAbstractInclMap),
|
|
map.foldl2(record_avail_in_import_use_map_entry, ImportUseMap,
|
|
!SrcIntImportUseMap, !SrcImpImportUseMap).
|
|
|
|
:- pred record_includes_imports_uses_in_ancestor_int_spec(set(module_name)::in,
|
|
ancestor_int_spec::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_ancestor_int_spec(Ancestors,
|
|
AncestorSpec, !ReadModules, !InclMap, !AncestorImportUseMap) :-
|
|
AncestorSpec = ancestor_int0(ParseTreeInt0, _ReadWhyInt0),
|
|
record_includes_imports_uses_in_parse_tree_int0(Ancestors,
|
|
ParseTreeInt0, !ReadModules, !InclMap, !AncestorImportUseMap).
|
|
|
|
:- pred record_includes_imports_uses_in_direct_int1_spec(
|
|
set(module_name)::in, direct_int1_spec::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_direct_int1_spec(Ancestors,
|
|
DirectSpec, !ReadModules, !InclMap) :-
|
|
DirectSpec = direct_int1(ParseTreeInt1, ReadWhyInt1),
|
|
record_includes_imports_uses_in_parse_tree_int1(Ancestors,
|
|
ParseTreeInt1, ReadWhyInt1, !ReadModules, !InclMap).
|
|
|
|
:- pred record_includes_imports_uses_in_indirect_int2_spec(
|
|
set(module_name)::in, indirect_int2_spec::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_indirect_int2_spec(Ancestors,
|
|
IndirectSpec, !ReadModules, !InclMap) :-
|
|
IndirectSpec = indirect_int2(ParseTreeInt2, ReadWhyInt2),
|
|
record_includes_imports_uses_in_parse_tree_int2(Ancestors,
|
|
ParseTreeInt2, ReadWhyInt2, !ReadModules, !InclMap).
|
|
|
|
:- pred record_includes_imports_uses_in_direct_int3_spec(
|
|
set(module_name)::in, direct_int3_spec::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_direct_int3_spec(Ancestors,
|
|
IndirectSpec, !ReadModules, !InclMap) :-
|
|
IndirectSpec = direct_int3(ParseTreeInt3, _ReadWhyInt3),
|
|
record_includes_imports_uses_in_parse_tree_int3(Ancestors,
|
|
ParseTreeInt3, non_abstract_section, !ReadModules, !InclMap).
|
|
|
|
:- pred record_includes_imports_uses_in_indirect_int3_spec(
|
|
set(module_name)::in, indirect_int3_spec::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_indirect_int3_spec(Ancestors,
|
|
IndirectSpec, !ReadModules, !InclMap) :-
|
|
IndirectSpec = indirect_int3(ParseTreeInt3, _ReadWhyInt3),
|
|
record_includes_imports_uses_in_parse_tree_int3(Ancestors,
|
|
ParseTreeInt3, abstract_section, !ReadModules, !InclMap).
|
|
|
|
:- pred record_includes_imports_uses_in_int_for_opt_spec(set(module_name)::in,
|
|
int_for_opt_spec::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_int_for_opt_spec(Ancestors,
|
|
IntForOptSpec, !ReadModules, !InclMap, !AncestorImportUseMap) :-
|
|
(
|
|
IntForOptSpec = for_opt_int0(ParseTreeInt0, _ReadWhyInt0),
|
|
record_includes_imports_uses_in_parse_tree_int0(Ancestors,
|
|
ParseTreeInt0, !ReadModules, !InclMap, !AncestorImportUseMap)
|
|
;
|
|
IntForOptSpec = for_opt_int1(ParseTreeInt1, ReadWhyInt1),
|
|
record_includes_imports_uses_in_parse_tree_int1(Ancestors,
|
|
ParseTreeInt1, ReadWhyInt1, !ReadModules, !InclMap)
|
|
;
|
|
IntForOptSpec = for_opt_int2(ParseTreeInt2, ReadWhyInt2),
|
|
record_includes_imports_uses_in_parse_tree_int2(Ancestors,
|
|
ParseTreeInt2, ReadWhyInt2, !ReadModules, !InclMap)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred record_includes_imports_uses_in_parse_tree_int0(set(module_name)::in,
|
|
parse_tree_int0::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_parse_tree_int0(Ancestors,
|
|
ParseTreeInt0, !ReadModules, !MaybeAbstractInclMap,
|
|
!AncestorImportUseMap) :-
|
|
ParseTreeInt0 = parse_tree_int0(ModuleName, _, _, InclMap, ImportUseMap,
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _),
|
|
set.insert(ModuleName, !ReadModules),
|
|
% Both possible values of ReadWhyInt0 call for treating the file contents
|
|
% as non-abstract.
|
|
map.foldl(record_include(non_abstract_section, yes(non_abstract_section)),
|
|
InclMap, !MaybeAbstractInclMap),
|
|
( if set.contains(Ancestors, ModuleName) then
|
|
% XXX CLEANUP This work could be done on ImportUseMap,
|
|
% *without* constructing AllAvails.
|
|
section_import_and_or_use_map_to_item_avails(ImportUseMap,
|
|
IntAvails, ImpAvails),
|
|
AllAvails = IntAvails ++ ImpAvails,
|
|
record_avails_acc(AllAvails, !AncestorImportUseMap)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred record_includes_imports_uses_in_parse_tree_int1(set(module_name)::in,
|
|
parse_tree_int1::in, read_why_int1::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_parse_tree_int1(Ancestors,
|
|
ParseTreeInt1, ReadWhyInt1, !ReadModules, !InclMap) :-
|
|
ParseTreeInt1 = parse_tree_int1(ModuleName, _, _, InclMap, _,
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _),
|
|
set.insert(ModuleName, !ReadModules),
|
|
(
|
|
( ReadWhyInt1 = rwi1_int_import
|
|
; ReadWhyInt1 = rwi1_imp_import
|
|
; ReadWhyInt1 = rwi1_int_use
|
|
; ReadWhyInt1 = rwi1_imp_use
|
|
; ReadWhyInt1 = rwi1_int_use_imp_import
|
|
),
|
|
% All these values of ReadWhyInt1 call for treating
|
|
% - the interface as non-abstract, and
|
|
% - the implementation as abstract.
|
|
map.foldl(
|
|
record_include(non_abstract_section, yes(abstract_section)),
|
|
InclMap, !InclMap)
|
|
;
|
|
ReadWhyInt1 = rwi1_opt,
|
|
map.foldl(
|
|
record_include(non_abstract_section, yes(non_abstract_section)),
|
|
InclMap, !InclMap)
|
|
;
|
|
ReadWhyInt1 = rwi1_type_repn
|
|
),
|
|
expect_not(set.contains(Ancestors, ModuleName), $pred,
|
|
"processing the .int file of an ancestor").
|
|
|
|
:- pred record_includes_imports_uses_in_parse_tree_int2(set(module_name)::in,
|
|
parse_tree_int2::in, read_why_int2::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_parse_tree_int2(Ancestors,
|
|
ParseTreeInt2, ReadWhyInt2, !ReadModules, !InclMap) :-
|
|
ParseTreeInt2 = parse_tree_int2(ModuleName, _, _,
|
|
IntInclMap, _, _, _, _, _, _, _, _, _),
|
|
set.insert(ModuleName, !ReadModules),
|
|
InclMap = coerce(IntInclMap),
|
|
(
|
|
( ReadWhyInt2 = rwi2_int_use
|
|
; ReadWhyInt2 = rwi2_imp_use
|
|
; ReadWhyInt2 = rwi2_opt
|
|
),
|
|
map.foldl(record_include(non_abstract_section, no), InclMap, !InclMap)
|
|
;
|
|
ReadWhyInt2 = rwi2_abstract,
|
|
map.foldl(record_include(abstract_section, no), InclMap, !InclMap)
|
|
),
|
|
expect_not(set.contains(Ancestors, ModuleName), $pred,
|
|
"processing the .int2 file of an ancestor").
|
|
|
|
:- pred record_includes_imports_uses_in_parse_tree_int3(set(module_name)::in,
|
|
parse_tree_int3::in, maybe_abstract_section::in,
|
|
set(module_name)::in, set(module_name)::out,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_parse_tree_int3(Ancestors,
|
|
ParseTreeInt3, MaybeAbstractSection, !ReadModules, !InclMap) :-
|
|
ParseTreeInt3 = parse_tree_int3(ModuleName, _, IntInclMap,
|
|
_, _, _, _, _, _, _),
|
|
set.insert(ModuleName, !ReadModules),
|
|
InclMap = coerce(IntInclMap),
|
|
map.foldl(record_include(MaybeAbstractSection, no), InclMap, !InclMap),
|
|
expect_not(set.contains(Ancestors, ModuleName), $pred,
|
|
"processing the .int3 file of an ancestor").
|
|
|
|
:- pred record_includes_imports_uses_in_parse_tree_plain_opt(
|
|
set(module_name)::in, parse_tree_plain_opt::in,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_includes_imports_uses_in_parse_tree_plain_opt(Ancestors,
|
|
ParseTreePlainOpt, !AncestorImportUseMap) :-
|
|
ParseTreePlainOpt = parse_tree_plain_opt(ModuleName, _, UseMap,
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _),
|
|
( if set.contains(Ancestors, ModuleName) then
|
|
Avails = use_map_to_item_avails(UseMap),
|
|
record_avails_acc(Avails, !AncestorImportUseMap)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred record_include(maybe_abstract_section::in,
|
|
maybe(maybe_abstract_section)::in,
|
|
module_name::in, include_module_info::in,
|
|
module_inclusion_map::in, module_inclusion_map::out) is det.
|
|
|
|
record_include(MaybeAbsSectionInt, MaybeMaybeAbsSectionImp,
|
|
ModuleName, InclInfo, !InclMap) :-
|
|
InclInfo = include_module_info(Section, Context),
|
|
(
|
|
Section = ms_interface,
|
|
IncludeContext0 = include_context(MaybeAbsSectionInt, Context),
|
|
MaybeIncludeContext = yes(IncludeContext0)
|
|
;
|
|
Section = ms_implementation,
|
|
(
|
|
MaybeMaybeAbsSectionImp = yes(MaybeAbsSectionImp),
|
|
IncludeContext0 = include_context(MaybeAbsSectionImp, Context),
|
|
MaybeIncludeContext = yes(IncludeContext0)
|
|
;
|
|
MaybeMaybeAbsSectionImp = no,
|
|
MaybeIncludeContext = no
|
|
)
|
|
),
|
|
(
|
|
MaybeIncludeContext = yes(IncludeContext),
|
|
( if map.search(!.InclMap, ModuleName, OneOrMore0) then
|
|
OneOrMore0 = one_or_more(HeadContext, TailContexts),
|
|
OneOrMore =
|
|
one_or_more(IncludeContext, [HeadContext | TailContexts]),
|
|
map.det_update(ModuleName, OneOrMore, !InclMap)
|
|
else
|
|
OneOrMore = one_or_more(IncludeContext, []),
|
|
map.det_insert(ModuleName, OneOrMore, !InclMap)
|
|
)
|
|
;
|
|
MaybeIncludeContext = no
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred record_avail_in_import_use_map_entry(module_name::in,
|
|
maybe_implicit_import_and_or_use::in,
|
|
module_import_or_use_map::in, module_import_or_use_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_avail_in_import_use_map_entry(ModuleName, MaybeImplicit,
|
|
!IntImportUseMap, !ImpImportUseMap) :-
|
|
(
|
|
MaybeImplicit = implicit_avail(_ImplicitImportOrUse,
|
|
MaybeSectionImportOrUse),
|
|
(
|
|
MaybeSectionImportOrUse = no
|
|
;
|
|
MaybeSectionImportOrUse = yes(SectionImportOrUse),
|
|
record_avail_in_section(ModuleName, SectionImportOrUse,
|
|
!IntImportUseMap, !ImpImportUseMap)
|
|
)
|
|
;
|
|
MaybeImplicit = explicit_avail(SectionImportOrUse),
|
|
record_avail_in_section(ModuleName, SectionImportOrUse,
|
|
!IntImportUseMap, !ImpImportUseMap)
|
|
).
|
|
|
|
:- pred record_avail_in_section(module_name::in, section_import_and_or_use::in,
|
|
module_import_or_use_map::in, module_import_or_use_map::out,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_avail_in_section(ModuleName, SectionImportOrUse,
|
|
!IntImportUseMap, !ImpImportUseMap) :-
|
|
(
|
|
( SectionImportOrUse = int_import(Context), IoU = import_decl
|
|
; SectionImportOrUse = int_use(Context), IoU = use_decl
|
|
),
|
|
record_avail(ModuleName, IoU, Context, !IntImportUseMap)
|
|
;
|
|
( SectionImportOrUse = imp_import(Context), IoU = import_decl
|
|
; SectionImportOrUse = imp_use(Context), IoU = use_decl
|
|
),
|
|
record_avail(ModuleName, IoU, Context, !ImpImportUseMap)
|
|
;
|
|
SectionImportOrUse = int_use_imp_import(IntContext, ImpContext),
|
|
record_avail(ModuleName, use_decl, IntContext, !IntImportUseMap),
|
|
record_avail(ModuleName, import_decl, ImpContext, !ImpImportUseMap)
|
|
).
|
|
|
|
:- pred record_avail(module_name::in, import_or_use::in, prog_context::in,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_avail(ModuleName, ImportOrUse, Context, !ImportUseMap) :-
|
|
IoUC = import_or_use_context(ImportOrUse, Context),
|
|
( if map.search(!.ImportUseMap, ModuleName, OneOrMore0) then
|
|
OneOrMore0 = one_or_more(HeadIoUC, TailIoUCs),
|
|
OneOrMore = one_or_more(IoUC, [HeadIoUC | TailIoUCs]),
|
|
map.det_update(ModuleName, OneOrMore, !ImportUseMap)
|
|
else
|
|
OneOrMore = one_or_more(IoUC, []),
|
|
map.det_insert(ModuleName, OneOrMore, !ImportUseMap)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
:- pred record_avails_acc(list(item_avail)::in,
|
|
module_import_or_use_map::in, module_import_or_use_map::out) is det.
|
|
|
|
record_avails_acc([], !ImportUseMap).
|
|
record_avails_acc([Avail | Avails], !ImportUseMap) :-
|
|
(
|
|
Avail = avail_import(avail_import_info(ModuleName, Context, _SeqNum)),
|
|
ImportOrUse = import_decl
|
|
;
|
|
Avail = avail_use(avail_use_info(ModuleName, Context, _SeqNum)),
|
|
ImportOrUse = use_decl
|
|
),
|
|
IoUC = import_or_use_context(ImportOrUse, Context),
|
|
( if map.search(!.ImportUseMap, ModuleName, OneOrMore0) then
|
|
OneOrMore0 = one_or_more(HeadIoUC, TailIoUCs),
|
|
OneOrMore = one_or_more(IoUC, [HeadIoUC | TailIoUCs]),
|
|
map.det_update(ModuleName, OneOrMore, !ImportUseMap)
|
|
else
|
|
OneOrMore = one_or_more(IoUC, []),
|
|
map.det_insert(ModuleName, OneOrMore, !ImportUseMap)
|
|
),
|
|
record_avails_acc(Avails, !ImportUseMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
check_import_accessibility(ParseTreeModuleSrc, ImportAccessibilityInfo,
|
|
MissingModulesInt, MissingModulesImp, !:DelayedSpecs, !:Specs) :-
|
|
ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
|
|
ModuleNameContext = ParseTreeModuleSrc ^ ptms_module_name_context,
|
|
ImportAccessibilityInfo = import_accessibility_info(ReadModules,
|
|
SeenIncludes, InclMap, SrcIntImportUseMap, SrcImpImportUseMap,
|
|
AncestorImportUseMap),
|
|
|
|
!:Specs = [],
|
|
% The current module is not an import, but this is the obvious place
|
|
% to check whether its purported parent module (if any) actually
|
|
% includes it.
|
|
report_any_missing_includes(ReadModules, SeenIncludes, InclMap,
|
|
ModuleName, [ModuleNameContext], !Specs),
|
|
map.foldl(
|
|
report_any_missing_includes_for_imports(ReadModules,
|
|
SeenIncludes, InclMap),
|
|
SrcIntImportUseMap, !Specs),
|
|
map.foldl(
|
|
report_any_missing_includes_for_imports(ReadModules,
|
|
SeenIncludes, InclMap),
|
|
SrcImpImportUseMap, !Specs),
|
|
|
|
% When checking whether avail declarations (i.e. import_module
|
|
% and use_module declarations) in the interface section
|
|
% have an accessible avail declaration for their ancestor modules,
|
|
% the places where those declarations may occur include not just
|
|
% the interface of the module itself, but also the contents of
|
|
% the .int0 interface files of ancestor modules.
|
|
map.union(append_one_or_more, SrcIntImportUseMap, AncestorImportUseMap,
|
|
SrcIntAncImportUseMap),
|
|
map.foldl(
|
|
find_any_missing_ancestor_imports(ModuleName, poa_parent,
|
|
SrcIntAncImportUseMap),
|
|
SrcIntImportUseMap, map.init, SrcIntMissingAncestorMap),
|
|
|
|
% When checking whether avail declarations in the implementation section
|
|
% have an accessible avail declaration for their ancestor modules,
|
|
% the places where those declarations may occur include not just
|
|
% the implementation section of the module itself, but also every place
|
|
% that the interface of the module has access to.
|
|
map.union(append_one_or_more, SrcIntAncImportUseMap, SrcImpImportUseMap,
|
|
SrcIntImpImportUseMap),
|
|
map.foldl(
|
|
find_any_missing_ancestor_imports(ModuleName, poa_parent,
|
|
SrcIntImpImportUseMap),
|
|
SrcImpImportUseMap, map.init, SrcImpMissingAncestorMap0),
|
|
|
|
% If we generate a message about a missing import (or use) for a module
|
|
% in the interface section, do not generate another message for it
|
|
% also missing in the implementation section, because adding an
|
|
% import_module or use_module declaration for it to the interface
|
|
% will also cure the problem in the implementation section.
|
|
map.keys(SrcIntMissingAncestorMap, SrcIntMissingAncestors),
|
|
map.delete_list(SrcIntMissingAncestors,
|
|
SrcImpMissingAncestorMap0, SrcImpMissingAncestorMap),
|
|
|
|
!:DelayedSpecs = [],
|
|
map.foldl2(
|
|
report_missing_ancestor(ModuleName,
|
|
missing_in_src_int(SrcImpImportUseMap)),
|
|
SrcIntMissingAncestorMap, [], MissingModulesInt, !DelayedSpecs),
|
|
map.foldl2(
|
|
report_missing_ancestor(ModuleName, missing_in_src_imp),
|
|
SrcImpMissingAncestorMap, [], MissingModulesImp, !DelayedSpecs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type parent_or_ancestor
|
|
---> poa_parent
|
|
; poa_ancestor.
|
|
|
|
:- type import_and_or_use
|
|
---> import_only
|
|
; use_only
|
|
; import_and_use.
|
|
|
|
:- type missing_ancestor_info
|
|
---> missing_ancestor_info(
|
|
mai_modules :: set(module_name),
|
|
mai_max_depth :: parent_or_ancestor,
|
|
mai_import_use :: import_and_or_use,
|
|
mai_least_context :: term_context
|
|
).
|
|
|
|
:- type missing_ancestor_map == map(module_name, missing_ancestor_info).
|
|
|
|
% find_any_missing_ancestor_imports(CurrentModule, ParentOrAncestor,
|
|
% ImportUseMap, ImportedModule, IoUCs, !MissingAncestorMap):
|
|
%
|
|
% If there are any ancestors of ImportedModule for which there is
|
|
% neither an explicit import_module or use_module declaration in
|
|
% ImportUseMap, nor an implicit declaration by virtue of that ancestor
|
|
% module being an ancestor of CurrentModule as well, then record
|
|
% the fact that we are missing an import or use of that ancestor.
|
|
%
|
|
% We don't generate an error message right here, so that if several
|
|
% imported modules are missing the same ancestor, we can generate
|
|
% just one message for that missing ancestor.
|
|
%
|
|
% The other inputs allow us to record information that will make
|
|
% the eventual error message more informative.
|
|
%
|
|
:- pred find_any_missing_ancestor_imports(module_name::in,
|
|
parent_or_ancestor::in, module_import_or_use_map::in,
|
|
module_name::in, one_or_more(import_or_use_context)::in,
|
|
missing_ancestor_map::in, missing_ancestor_map::out) is det.
|
|
|
|
find_any_missing_ancestor_imports(CurrentModule, ParentOrAncestor,
|
|
ImportUseMap, ImportedModule, IoUCs, !MissingAncestorMap) :-
|
|
(
|
|
ImportedModule = qualified(ParentModule, _SubModule),
|
|
( if
|
|
(
|
|
% Does CurrentModule import ParentModule explicitly?
|
|
map.search(ImportUseMap, ParentModule, _ParentIoUCs)
|
|
;
|
|
% Is ParentModule the same as CurrentModule, or a parent
|
|
% or an ancestor of CurrentModule? If yes, then CurrentModule
|
|
% imports it implicitly.
|
|
is_same_module_or_submodule(CurrentModule, ParentModule)
|
|
)
|
|
then
|
|
true
|
|
else
|
|
IoUCs = one_or_more(HeadIoUC, TailIoUCs),
|
|
( if
|
|
map.search(!.MissingAncestorMap, ParentModule,
|
|
MissingAncestorInfo0)
|
|
then
|
|
MissingAncestorInfo0 = missing_ancestor_info(ChildModules0,
|
|
PoA0, ImportAndOrUse0, LeastContext0),
|
|
set.insert(ImportedModule, ChildModules0, ChildModules),
|
|
( if
|
|
PoA0 = poa_parent,
|
|
ParentOrAncestor = poa_ancestor
|
|
then
|
|
PoA = poa_ancestor
|
|
else
|
|
PoA = PoA0
|
|
),
|
|
update_iu_and_least_context(HeadIoUC,
|
|
ImportAndOrUse0, ImportAndOrUse1,
|
|
LeastContext0, LeastContext1),
|
|
list.foldl2(update_iu_and_least_context, TailIoUCs,
|
|
ImportAndOrUse1, ImportAndOrUse,
|
|
LeastContext1, LeastContext),
|
|
MissingAncestorInfo = missing_ancestor_info(ChildModules,
|
|
PoA, ImportAndOrUse, LeastContext),
|
|
map.det_update(ParentModule, MissingAncestorInfo,
|
|
!MissingAncestorMap)
|
|
else
|
|
ChildModules = set.make_singleton_set(ImportedModule),
|
|
HeadIoUC = import_or_use_context(HeadImportOrUse, HeadContext),
|
|
(
|
|
HeadImportOrUse = import_decl,
|
|
ImportAndOrUse0 = import_only
|
|
;
|
|
HeadImportOrUse = use_decl,
|
|
ImportAndOrUse0 = use_only
|
|
),
|
|
list.foldl2(update_iu_and_least_context, TailIoUCs,
|
|
ImportAndOrUse0, ImportAndOrUse,
|
|
HeadContext, LeastContext),
|
|
MissingAncestorInfo = missing_ancestor_info(ChildModules,
|
|
ParentOrAncestor, ImportAndOrUse, LeastContext),
|
|
map.det_insert(ParentModule, MissingAncestorInfo,
|
|
!MissingAncestorMap),
|
|
find_any_missing_ancestor_imports(CurrentModule, poa_ancestor,
|
|
ImportUseMap, ParentModule, IoUCs, !MissingAncestorMap)
|
|
)
|
|
)
|
|
;
|
|
ImportedModule = unqualified(_)
|
|
% For modules without parent modules, accessibility is moot.
|
|
).
|
|
|
|
:- pred update_iu_and_least_context(import_or_use_context::in,
|
|
import_and_or_use::in, import_and_or_use::out,
|
|
term_context::in, term_context::out) is det.
|
|
|
|
update_iu_and_least_context(IoUC, !ImportAndOrUse, !LeastContext) :-
|
|
IoUC = import_or_use_context(ImportOrUse, Context),
|
|
(
|
|
ImportOrUse = import_decl,
|
|
(
|
|
!.ImportAndOrUse = import_only
|
|
;
|
|
( !.ImportAndOrUse = use_only
|
|
; !.ImportAndOrUse = import_and_use
|
|
),
|
|
!:ImportAndOrUse = import_and_use
|
|
)
|
|
;
|
|
ImportOrUse = use_decl,
|
|
(
|
|
!.ImportAndOrUse = use_only
|
|
;
|
|
( !.ImportAndOrUse = import_only
|
|
; !.ImportAndOrUse = import_and_use
|
|
),
|
|
!:ImportAndOrUse = import_and_use
|
|
)
|
|
),
|
|
( if
|
|
compare((<), Context, !.LeastContext),
|
|
not is_dummy_context(Context)
|
|
then
|
|
!:LeastContext = Context
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Error reporting.
|
|
%
|
|
|
|
:- type missing_where
|
|
---> missing_in_src_int(module_import_or_use_map)
|
|
; missing_in_src_imp.
|
|
|
|
:- pred report_missing_ancestor(module_name::in,
|
|
missing_where::in, module_name::in, missing_ancestor_info::in,
|
|
list(module_name)::in, list(module_name)::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
report_missing_ancestor(ModuleName, MissingWhere,
|
|
MissingModuleName, MissingAncestorInfo, !ModulesToAdd, !Specs) :-
|
|
!:ModulesToAdd = [MissingModuleName | !.ModulesToAdd],
|
|
MissingAncestorInfo = missing_ancestor_info(DescendantModuleNamesSet,
|
|
MaxDepth, ImportAndOrUse, LeastContext),
|
|
set.to_sorted_list(DescendantModuleNamesSet, DescendantModuleNames),
|
|
( MaxDepth = poa_parent, ChildOrDescendant = "child"
|
|
; MaxDepth = poa_ancestor, ChildOrDescendant = "descendant"
|
|
),
|
|
(
|
|
ImportAndOrUse = import_only,
|
|
DeclPieces = [decl("import_module")]
|
|
;
|
|
ImportAndOrUse = use_only,
|
|
DeclPieces = [decl("use_module")]
|
|
;
|
|
ImportAndOrUse = import_and_use,
|
|
DeclPieces = [decl("import_module"), words("and"), decl("use_module")]
|
|
),
|
|
(
|
|
MissingWhere = missing_in_src_int(_),
|
|
InTheInterface = [words("in the interface")]
|
|
;
|
|
MissingWhere = missing_in_src_imp,
|
|
InTheInterface = []
|
|
),
|
|
DescendantPieces = list.map(wrap_module_name, DescendantModuleNames),
|
|
ModuleS = choose_number(DescendantModuleNames, "module", "modules"),
|
|
DeclarationS = choose_number(DescendantModuleNames,
|
|
"declaration", "declarations"),
|
|
MainPieces = [words("In module"), qual_sym_name(ModuleName),
|
|
suffix(":"), words("error:"), nl,
|
|
words("the absence of an")] ++
|
|
color_as_correct([decl("import_module")]) ++
|
|
[words("or")] ++
|
|
color_as_correct([decl("use_module"), words("declaration")]) ++
|
|
[words("for")] ++
|
|
color_as_subject([qual_sym_name(MissingModuleName)] ++
|
|
InTheInterface) ++
|
|
color_as_incorrect([words("prevents access")]) ++
|
|
[words("to the")] ++ DeclPieces ++ [words(DeclarationS)] ++
|
|
InTheInterface ++
|
|
[words("for its"), words(ChildOrDescendant), words(ModuleS)] ++
|
|
piece_list_to_pieces("and", DescendantPieces) ++
|
|
[suffix("."), nl],
|
|
MainMsg = msg(LeastContext, MainPieces),
|
|
( if
|
|
MissingWhere = missing_in_src_int(SrcImpImportUseMap),
|
|
map.search(SrcImpImportUseMap, MissingModuleName, IoUCs)
|
|
then
|
|
% XXX _TailIoUCs
|
|
IoUCs = one_or_more(HeadIoUC, _TailIoUCs),
|
|
HeadIoUC = import_or_use_context(ImportOrUse, ImpContext),
|
|
( ImportOrUse = import_decl, ImportOrUseDecl = "import_module"
|
|
; ImportOrUse = use_decl, ImportOrUseDecl = "use_module"
|
|
),
|
|
ImpPieces = [words("Adding such a declaration would obsolete"),
|
|
words("this"), decl(ImportOrUseDecl), words("declaration"),
|
|
words("in the implementation section."), nl],
|
|
ImpMsg = msg(ImpContext, ImpPieces),
|
|
Msgs = [MainMsg, ImpMsg]
|
|
else
|
|
Msgs = [MainMsg]
|
|
),
|
|
Spec = error_spec($pred, severity_error, phase_pt2h, Msgs),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
%---------------------%
|
|
|
|
:- pred report_any_missing_includes_for_imports(set(module_name)::in,
|
|
seen_includes::in, module_inclusion_map::in,
|
|
module_name::in, one_or_more(import_or_use_context)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
report_any_missing_includes_for_imports(ReadModules, SeenIncludes, InclMap,
|
|
ModuleName, IoUCs, !Specs) :-
|
|
IoUCs = one_or_more(HeadIoUC, TailIoUCs),
|
|
Contexts = list.map(project_out_import_or_use, [HeadIoUC | TailIoUCs]),
|
|
report_any_missing_includes(ReadModules, SeenIncludes, InclMap,
|
|
ModuleName, Contexts, !Specs).
|
|
|
|
% report_any_missing_includes(ReadModules, InclMap, Module, Contexts,
|
|
% !Specs):
|
|
%
|
|
% If Module is a submodule of ParentModule but we haven't seen
|
|
% an include_module declaration for Module in ParentModule even though
|
|
% we should have seen it if it exists (because we have read an interface
|
|
% file for ParentModule, which should contain all its include_module
|
|
% declarations), then add an error message reporting this fact to !Specs.
|
|
%
|
|
:- pred report_any_missing_includes(set(module_name)::in,
|
|
seen_includes::in, module_inclusion_map::in,
|
|
module_name::in, list(term_context)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
report_any_missing_includes(ReadModules, SeenIncludes, InclMap,
|
|
Module, Contexts, !Specs) :-
|
|
(
|
|
Module = qualified(ParentModule, SubModule),
|
|
( if map.search(InclMap, Module, IncludeContexts) then
|
|
% Module *has* its include in ParentModule, ...
|
|
IncludeContexts =
|
|
one_or_more(HeadIncludeContext, TailIncludeContexts),
|
|
IncludeContextsList = [HeadIncludeContext | TailIncludeContexts],
|
|
( if any_true(is_non_abstract_include, IncludeContextsList) then
|
|
% ... and it is visible here.
|
|
true
|
|
else
|
|
% ... and it is NOT visible here.
|
|
list.foldl(report_abstract_include(ParentModule, SubModule),
|
|
Contexts, !Specs)
|
|
)
|
|
else
|
|
% We have not seen Module's include in ParentModule.
|
|
( if set.contains(ReadModules, ParentModule) then
|
|
% We have read item blocks from ParentModule, and they
|
|
% *should* have included its include_module declarations.
|
|
list.foldl(
|
|
report_missing_include(SeenIncludes,
|
|
ParentModule, SubModule),
|
|
Contexts, !Specs)
|
|
else
|
|
% We have not read any item blocks from ParentModule.
|
|
% For all we know, ParentModule *may* contain an include
|
|
% for Module; we just don't know. Reporting an error
|
|
% would be misleading.
|
|
%
|
|
% If we had imported ParentModule, we would have read
|
|
% item blocks from one of its interface files. We will
|
|
% report the missing import. If the include is truly missing
|
|
% in ParentModule, we will discover and report that fact
|
|
% when the missing import of ParentModule in the *current*
|
|
% module is fixed by the programmer.
|
|
true
|
|
)
|
|
),
|
|
report_any_missing_includes(ReadModules, SeenIncludes, InclMap,
|
|
ParentModule, Contexts, !Specs)
|
|
;
|
|
Module = unqualified(_)
|
|
% For modules without parent modules, accessibility is moot.
|
|
).
|
|
|
|
:- pred report_abstract_include(module_name::in, string::in, term_context::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
report_abstract_include(ParentModule, SubModule, Context, !Specs) :-
|
|
Pieces = [words("Error:"),
|
|
words("module"), qual_sym_name(ParentModule),
|
|
words("has a submodule named")] ++
|
|
color_as_subject([quote(SubModule), suffix(",")]) ++
|
|
[words("but it is")] ++
|
|
color_as_incorrect([words("visible only to its other submodules.")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
:- pred report_missing_include(seen_includes::in, module_name::in, string::in,
|
|
term_context::in, list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
report_missing_include(SeenIncludes, ParentModule, SubModule, Context,
|
|
!Specs) :-
|
|
(
|
|
SeenIncludes = seen_all_includes,
|
|
SubmodulePieces = [words("a submodule")]
|
|
;
|
|
SeenIncludes = seen_only_int_includes,
|
|
SubmodulePieces = [words("a visible submodule")]
|
|
),
|
|
Pieces = [words("Error:"), words("module")] ++
|
|
color_as_subject([qual_sym_name(ParentModule)]) ++
|
|
color_as_incorrect([words("does not have")]) ++
|
|
SubmodulePieces ++ [words("named")] ++
|
|
color_as_subject([quote(SubModule), suffix(".")]) ++
|
|
[nl],
|
|
Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Utility operations.
|
|
%
|
|
|
|
:- pred append_one_or_more(one_or_more(T)::in, one_or_more(T)::in,
|
|
one_or_more(T)::out) is det.
|
|
|
|
append_one_or_more(A, B, AB) :-
|
|
A = one_or_more(HeadA, TailA),
|
|
B = one_or_more(HeadB, TailB),
|
|
AB = one_or_more(HeadA, TailA ++ [HeadB | TailB]).
|
|
|
|
:- pred is_non_abstract_include(include_context::in) is semidet.
|
|
|
|
is_non_abstract_include(IncludeContext) :-
|
|
IncludeContext = include_context(MaybeAbstractInclude, _Context),
|
|
MaybeAbstractInclude = non_abstract_section.
|
|
|
|
:- func project_out_import_or_use(import_or_use_context) = term_context.
|
|
|
|
project_out_import_or_use(import_or_use_context(_, Context)) = Context.
|
|
|
|
:- func wrap_module_name(sym_name) = format_piece.
|
|
|
|
wrap_module_name(Module) = qual_sym_name(Module).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.check_import_accessibility.
|
|
%---------------------------------------------------------------------------%
|