Subject: [PATCH 1/2] Change submodule visibility rules.

From: Peter Wang <[email-masked]>
Date: Wed, 15 Jul 2026 12:05:58 +1000

The test case in Mantis bug #584 contains a module with this structure:

    :- module mod_a.
    :- interface.
    :- include_module sub1.

    :- implementation.
    :- include_module mod_a.sub2.
    :- import_module mod_a.sub2.

    :- end_module mod_a.

where the interface of sub1 refers to a type defined in sub2,
but sub1 does not import sub2 itself (which is valid under the existing
visibility rules). Without an explicit import of sub2, we generated a
mod_a.sub1.int file that also did not contain a `:- use_module' declaration
for sub2. If an unrelated module then imported mod_a.sub1, it could encounter
the type defined in sub2 which it knows nothing about, leading to a compiler
abort.

Zoltan's suggestion in the Mantis bug discussion was to make it an error
for sub1 to reference the type in sub2 when generating its .int file.
To that end, I propose:

Visibility rule change #1:

  - An `:- import_module` or `:- use_module` declaration for module `M`
    in the implementation section of a module will make the declarations
    in the interface section of `M` visible in the implementation sections
    of its submodules only. Previously, the declarations would also be also
    visible in the submodules' interface sections.

However, after implementing that, it revealed a different problem.
If a submodule inherits visibility of M's exports in its implementation
section, it should still be possible to import M in its interface section.
But when compiling the submodule, the compiler would read the interface file
for M, due to M being imported in an ancestor's implementation section.
The compiler would not read M's interface file again even though M is also
imported in the submodule's interface file. Under the new rules, the
submodule would only have visibility to M's exports in the implementation
section.

Visibility rule change #2:

  - If a submodule contains `:- import_module` or `:- use_module` declarations
    that import module `M`, visibility of M's exports within the submodule will
    be determined only by those declarations, not by import or use declarations
    in any ancestor module.

That only requires fairly simple changes to the compiler, and also seems to
me a decent language design. As Zoltan mentioned in bug #584, we may want to
require submodules to do all their own imports in the future anyway;
this rule change would be consistent with that direction.

doc/mercury_reference_manual.texi:
    Rename "Visibility rules" section to "Submodule visibility rules".

    Document new submodule visibility rules.

    Try to clarify existing visibility rules.

NEWS.md:
    Announce changes to submodule visibility rules.

compiler/prog_parse_tree.m:
    Add rwi1_ancestor_{int,imp}_{import,use} constructors.

    Add rwi3_direct_ancestor_{int,imp}_{import,use} constructors.

    (As it turns out, these additions might not be strictly necessary.)

compiler/convert_import_use.m:
    Add helper predicate avail_module_names.

compiler/grab_modules.m:
    Make grab_module_int0_files_for_amiu and grab_module_int0_files_for_acu
    return ancestor imports/uses from different sections in separate sets.

    When grabbing .int3 or .int files due to ancestor imports/uses,
    exclude modules explicitly imported/used by the current module.
    Leave those files to be grabbed as part of the direct import/use sets.

    Use rwi3_direct_ancestor_* and rwi1_ancestor_* as the reason
    when grabbing .int3 or .int files due to ancestor imports.

compiler/module_qual.collect_mq_info.m:
    Handle rwi1_ancestor_* in collect_mq_info_in_parse_tree_int1.

    Handle rwi3_direct_ancestor_* in collect_mq_info_in_parse_tree_int3.

    Use ImpPermissions in collect_mq_info_in_included_module_info
    for Section = ms_implementation.
    (XXX not sure this is required in the end, but it does not seem to hurt)

compiler/check_import_accessibility.m:
compiler/make_hlds_separate_items.m:
    Conform to addition of rwi1_ancestor_* constructors.

compiler/module_baggage.m:
    Update comments for recomp_avail cases.

compiler/module_qual.qualify_items.m:
    Incidental changes.

library/bit_buffer.read.m:
library/bit_buffer.write.m:
library/io.text_read.m:
library/string.builder.m:
    Conform to new visibility rules.

tests/invalid_submodules/Mmakefile:
tests/invalid_submodules/bug584.err_exp:
tests/invalid_submodules/bug584.err_exp2:
tests/invalid_submodules/bug584.m:
tests/invalid_submodules/bug584_helper_1.m:
tests/invalid_submodules/sub_visibility_a1.err_exp:
tests/invalid_submodules/sub_visibility_a1.m:
tests/invalid_submodules/sub_visibility_a2.err_exp:
tests/invalid_submodules/sub_visibility_a2.err_exp2:
tests/invalid_submodules/sub_visibility_a2.m:
tests/invalid_submodules/sub_visibility_a3.err_exp:
tests/invalid_submodules/sub_visibility_a3.err_exp2:
tests/invalid_submodules/sub_visibility_a3.m:
tests/invalid_submodules/sub_visibility_a4.err_exp:
tests/invalid_submodules/sub_visibility_a4.err_exp2:
tests/invalid_submodules/sub_visibility_a4.m:
tests/invalid_submodules/sub_visibility_b1.err_exp:
tests/invalid_submodules/sub_visibility_b1.m:
tests/invalid_submodules/sub_visibility_b2.err_exp:
tests/invalid_submodules/sub_visibility_b2.err_exp2:
tests/invalid_submodules/sub_visibility_b2.m:
tests/invalid_submodules/sub_visibility_b3.err_exp:
tests/invalid_submodules/sub_visibility_b3.err_exp2:
tests/invalid_submodules/sub_visibility_b3.m:
tests/invalid_submodules/sub_visibility_b4.err_exp:
tests/invalid_submodules/sub_visibility_b4.err_exp2:
tests/invalid_submodules/sub_visibility_b4.m:
tests/invalid_submodules/sub_visibility_c1.m:
tests/invalid_submodules/sub_visibility_c2.err_exp:
tests/invalid_submodules/sub_visibility_c2.err_exp2:
tests/invalid_submodules/sub_visibility_c2.m:
tests/invalid_submodules/sub_visibility_c3.err_exp:
tests/invalid_submodules/sub_visibility_c3.err_exp2:
tests/invalid_submodules/sub_visibility_c3.m:
tests/invalid_submodules/sub_visibility_c4.err_exp:
tests/invalid_submodules/sub_visibility_c4.err_exp2:
tests/invalid_submodules/sub_visibility_c4.m:
tests/invalid_submodules/sub_visibility_d1.m:
tests/invalid_submodules/sub_visibility_d2.err_exp:
tests/invalid_submodules/sub_visibility_d2.err_exp2:
tests/invalid_submodules/sub_visibility_d2.m:
tests/invalid_submodules/sub_visibility_d3.err_exp:
tests/invalid_submodules/sub_visibility_d3.err_exp2:
tests/invalid_submodules/sub_visibility_d3.m:
tests/invalid_submodules/sub_visibility_d4.err_exp:
tests/invalid_submodules/sub_visibility_d4.err_exp2:
tests/invalid_submodules/sub_visibility_d4.m:
tests/submodules/Mmakefile:
tests/submodules/accessibility_t3.exp:
tests/submodules/accessibility_t3.m:
    Add new test cases.

tests/submodules/parent_t2.parent_t2_helper_1.m:
tests/valid_seq/nested_module_ambiguity.m:
tests/valid_seq/spurious_match.m:
    Conform to new visibility rules.
---
 NEWS.md                                       |  13 ++
 compiler/check_import_accessibility.m         |   6 +-
 compiler/convert_import_use.m                 |  15 ++
 compiler/grab_modules.m                       | 180 +++++++++++++-----
 compiler/make_hlds_separate_items.m           |  16 +-
 compiler/module_baggage.m                     |  20 +-
 compiler/module_qual.collect_mq_info.m        |  51 +++--
 compiler/module_qual.qualify_items.m          |   9 +-
 compiler/prog_parse_tree.m                    |  42 ++--
 doc/mercury_reference_manual.texi             |  50 +++--
 library/bit_buffer.read.m                     |   1 +
 library/bit_buffer.write.m                    |   3 +-
 library/io.text_read.m                        |   6 -
 library/string.builder.m                      |   7 +-
 tests/invalid_submodules/Mmakefile            |  50 ++++-
 tests/invalid_submodules/bug584.err_exp       |  12 ++
 tests/invalid_submodules/bug584.err_exp2      |  13 ++
 tests/invalid_submodules/bug584.m             |  23 +++
 tests/invalid_submodules/bug584_helper_1.m    |  36 ++++
 .../sub_visibility_a1.err_exp                 |   4 +
 tests/invalid_submodules/sub_visibility_a1.m  |  44 +++++
 .../sub_visibility_a2.err_exp                 |  13 ++
 .../sub_visibility_a2.err_exp2                |  14 ++
 tests/invalid_submodules/sub_visibility_a2.m  |  49 +++++
 .../sub_visibility_a3.err_exp                 |  12 ++
 .../sub_visibility_a3.err_exp2                |  13 ++
 tests/invalid_submodules/sub_visibility_a3.m  |  49 +++++
 .../sub_visibility_a4.err_exp                 |  18 ++
 .../sub_visibility_a4.err_exp2                |  19 ++
 tests/invalid_submodules/sub_visibility_a4.m  |  49 +++++
 .../sub_visibility_b1.err_exp                 |   4 +
 tests/invalid_submodules/sub_visibility_b1.m  |  44 +++++
 .../sub_visibility_b2.err_exp                 |  13 ++
 .../sub_visibility_b2.err_exp2                |  14 ++
 tests/invalid_submodules/sub_visibility_b2.m  |  49 +++++
 .../sub_visibility_b3.err_exp                 |  12 ++
 .../sub_visibility_b3.err_exp2                |  13 ++
 tests/invalid_submodules/sub_visibility_b3.m  |  49 +++++
 .../sub_visibility_b4.err_exp                 |  18 ++
 .../sub_visibility_b4.err_exp2                |  19 ++
 tests/invalid_submodules/sub_visibility_b4.m  |  49 +++++
 .../sub_visibility_c1.err_exp                 |   0
 tests/invalid_submodules/sub_visibility_c1.m  |  44 +++++
 .../sub_visibility_c2.err_exp                 |  13 ++
 .../sub_visibility_c2.err_exp2                |  14 ++
 tests/invalid_submodules/sub_visibility_c2.m  |  49 +++++
 .../sub_visibility_c3.err_exp                 |  12 ++
 .../sub_visibility_c3.err_exp2                |  13 ++
 tests/invalid_submodules/sub_visibility_c3.m  |  49 +++++
 .../sub_visibility_c4.err_exp                 |  18 ++
 .../sub_visibility_c4.err_exp2                |  19 ++
 tests/invalid_submodules/sub_visibility_c4.m  |  49 +++++
 .../sub_visibility_d1.err_exp                 |   0
 tests/invalid_submodules/sub_visibility_d1.m  |  44 +++++
 .../sub_visibility_d2.err_exp                 |  13 ++
 .../sub_visibility_d2.err_exp2                |  14 ++
 tests/invalid_submodules/sub_visibility_d2.m  |  49 +++++
 .../sub_visibility_d3.err_exp                 |  12 ++
 .../sub_visibility_d3.err_exp2                |  13 ++
 tests/invalid_submodules/sub_visibility_d3.m  |  49 +++++
 .../sub_visibility_d4.err_exp                 |  18 ++
 .../sub_visibility_d4.err_exp2                |  19 ++
 tests/invalid_submodules/sub_visibility_d4.m  |  49 +++++
 .../test_visibility.err_exp                   |   0
 tests/submodules/Mmakefile                    |   1 +
 tests/submodules/accessibility_t3.exp         |   1 +
 tests/submodules/accessibility_t3.m           |  68 +++++++
 .../submodules/parent_t2.parent_t2_helper_1.m |   4 +-
 tests/valid_seq/nested_module_ambiguity.m     |   2 +
 tests/valid_seq/spurious_match.m              |   2 +
 70 files changed, 1641 insertions(+), 118 deletions(-)
 create mode 100644 tests/invalid_submodules/bug584.err_exp
 create mode 100644 tests/invalid_submodules/bug584.err_exp2
 create mode 100644 tests/invalid_submodules/bug584.m
 create mode 100644 tests/invalid_submodules/bug584_helper_1.m
 create mode 100644 tests/invalid_submodules/sub_visibility_a1.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_a1.m
 create mode 100644 tests/invalid_submodules/sub_visibility_a2.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_a2.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_a2.m
 create mode 100644 tests/invalid_submodules/sub_visibility_a3.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_a3.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_a3.m
 create mode 100644 tests/invalid_submodules/sub_visibility_a4.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_a4.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_a4.m
 create mode 100644 tests/invalid_submodules/sub_visibility_b1.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_b1.m
 create mode 100644 tests/invalid_submodules/sub_visibility_b2.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_b2.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_b2.m
 create mode 100644 tests/invalid_submodules/sub_visibility_b3.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_b3.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_b3.m
 create mode 100644 tests/invalid_submodules/sub_visibility_b4.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_b4.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_b4.m
 create mode 100644 tests/invalid_submodules/sub_visibility_c1.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_c1.m
 create mode 100644 tests/invalid_submodules/sub_visibility_c2.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_c2.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_c2.m
 create mode 100644 tests/invalid_submodules/sub_visibility_c3.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_c3.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_c3.m
 create mode 100644 tests/invalid_submodules/sub_visibility_c4.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_c4.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_c4.m
 create mode 100644 tests/invalid_submodules/sub_visibility_d1.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_d1.m
 create mode 100644 tests/invalid_submodules/sub_visibility_d2.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_d2.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_d2.m
 create mode 100644 tests/invalid_submodules/sub_visibility_d3.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_d3.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_d3.m
 create mode 100644 tests/invalid_submodules/sub_visibility_d4.err_exp
 create mode 100644 tests/invalid_submodules/sub_visibility_d4.err_exp2
 create mode 100644 tests/invalid_submodules/sub_visibility_d4.m
 create mode 100644 tests/invalid_submodules/test_visibility.err_exp
 create mode 100644 tests/submodules/accessibility_t3.exp
 create mode 100644 tests/submodules/accessibility_t3.m

diff --git a/NEWS.md b/NEWS.md
index d7f53a2fff..9432d2c6fb 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,6 +4,19 @@ NEWS since Mercury 22.01
 Changes that may break compatibility
 ------------------------------------
 
+* We have changed the visibility rules for submodules:
+
+  - An `:- import_module` or `:- use_module` declaration for module `M`
+    in the implementation section of a module will make the declarations
+    in the interface section of `M` visible in the implementation sections
+    of its submodules only. Previously, the declarations would also be also
+    visible in the submodules' interface sections.
+
+  - If a submodule contains `:- import_module` or `:- use_module` declarations
+    that import module `M`, visibility of M's exports within the submodule will
+    be determined only by those declarations, not by import or use declarations
+    in any ancestor module.
+
 * The predicates `read_term/3`, `read_term/4`, `read_term_with_op_table/4`,
   `read_term_with_op_table/5` have been removed from the `term_io` module
   of the Mercury standard library.
diff --git a/compiler/check_import_accessibility.m b/compiler/check_import_accessibility.m
index b48e2b8fb7..8efe7aefe9 100644
--- a/compiler/check_import_accessibility.m
+++ b/compiler/check_import_accessibility.m
@@ -389,7 +389,11 @@ record_includes_imports_uses_in_parse_tree_int1(Ancestors,
         _, _, _, _, _, _, _, _, _, _, _, _, _, _),
     set.insert(ModuleName, !ReadModules),
     (
-        ( ReadWhyInt1 = rwi1_int_import
+        ( ReadWhyInt1 = rwi1_ancestor_int_import
+        ; ReadWhyInt1 = rwi1_ancestor_int_use
+        ; ReadWhyInt1 = rwi1_ancestor_imp_import
+        ; ReadWhyInt1 = rwi1_ancestor_imp_use
+        ; ReadWhyInt1 = rwi1_int_import
         ; ReadWhyInt1 = rwi1_imp_import
         ; ReadWhyInt1 = rwi1_int_use
         ; ReadWhyInt1 = rwi1_imp_use
diff --git a/compiler/convert_import_use.m b/compiler/convert_import_use.m
index 1c07e890b5..269a6017f2 100644
--- a/compiler/convert_import_use.m
+++ b/compiler/convert_import_use.m
@@ -175,6 +175,8 @@
 :- pred avail_imports_uses(list(item_avail)::in,
     list(avail_import_info)::out, list(avail_use_info)::out) is det.
 
+:- pred avail_module_names(list(item_avail)::in, set(module_name)::out) is det.
+
     % Return "import_module" or "use_module", depending on the argument.
     %
 :- func import_or_use_decl_name(import_or_use) = string.
@@ -1363,6 +1365,19 @@ avail_imports_uses([Avail | Avails], !:Imports, !:Uses) :-
         !:Uses = [AvailUseInfo | !.Uses]
     ).
 
+avail_module_names(Avails, ModuleNamesSet) :-
+    list.map(avail_module_name, Avails, ModuleNames),
+    set.list_to_set(ModuleNames, ModuleNamesSet).
+
+:- pred avail_module_name(item_avail::in, module_name::out) is det.
+
+avail_module_name(Avail, ModuleName) :-
+    (
+        Avail = avail_import(avail_import_info(ModuleName, _Context, _SN))
+    ;
+        Avail = avail_use(avail_use_info(ModuleName, _Context, _SN))
+    ).
+
 import_or_use_decl_name(import_decl) = "import_module".
 import_or_use_decl_name(use_decl) = "use_module".
 
diff --git a/compiler/grab_modules.m b/compiler/grab_modules.m
index b65725ec7e..408cd33a66 100644
--- a/compiler/grab_modules.m
+++ b/compiler/grab_modules.m
@@ -188,7 +188,7 @@
 grab_unqual_imported_modules_make_int(ProgressStream, Globals,
         ParseTreeModuleSrc0, !:AugMakeIntUnit,
         !Baggage, !HaveParseTreeMaps, !IO) :-
-    % The predicates grab_imported_modules_augment and
+    % The predicates grab_qual_imported_modules_augment and
     % grab_unqual_imported_modules_make_int have quite similar tasks.
     % Please keep the corresponding parts of these two predicates in sync.
     %
@@ -234,18 +234,40 @@ grab_unqual_imported_modules_make_int(ProgressStream, Globals,
         % Get the .int0 files of the ancestor modules.
         Ancestors = get_ancestors(ModuleName),
         grab_module_int0_files_for_amiu(ProgressStream, Globals,
-            "unqual_ancestors",
-            Ancestors, set.init, AncestorImports, set.init, AncestorUses,
+            "unqual_ancestors", Ancestors,
+            set.init, AncestorIntImports0, set.init, AncestorImpImports0,
+            set.init, AncestorIntUses0, set.init, AncestorImpUses0,
             !HaveParseTreeMaps, !Baggage, !AugMakeIntUnit, !IO),
 
+        % Any modules that are explicitly imported or used by declarations
+        % in the current module have visibility determined by those
+        % declarations instead of inheriting visibility from ancestor modules.
+        import_and_or_use_map_to_item_avails(do_not_include_implicit,
+            ImportAndOrUseMap0, ExplicitIntAvails, ExplicitImpAvails),
+        avail_module_names(ExplicitIntAvails ++ ExplicitImpAvails,
+            ExplicitAvailModules),
+        set.difference(AncestorIntImports0, ExplicitAvailModules,
+            AncestorIntImports),
+        set.difference(AncestorImpImports0, ExplicitAvailModules,
+            AncestorImpImports),
+        set.difference(AncestorIntUses0, ExplicitAvailModules,
+            AncestorIntUses),
+        set.difference(AncestorImpUses0, ExplicitAvailModules,
+            AncestorImpUses),
+
         % Get the .int3 files of the modules imported using `import_module'.
         set.init(!:IntIndirectImported),
         set.init(!:ImpIndirectImported),
         grab_module_int3_files(ProgressStream, Globals,
-            "unqual_parent_imported", rwi3_direct_ancestor_import,
-            set.to_sorted_list(AncestorImports),
+            "unqual_parent_int_imported", rwi3_direct_ancestor_int_import,
+            set.to_sorted_list(AncestorIntImports),
             !IntIndirectImported, !HaveParseTreeMaps,
             !Baggage, !AugMakeIntUnit, !IO),
+        grab_module_int3_files(ProgressStream, Globals,
+            "unqual_parent_imp_imported", rwi3_direct_ancestor_imp_import,
+            set.to_sorted_list(AncestorImpImports),
+            !ImpIndirectImported, !HaveParseTreeMaps,
+            !Baggage, !AugMakeIntUnit, !IO),
         grab_module_int3_files(ProgressStream, Globals,
             "unqual_int_imported", rwi3_direct_int_import,
             set.to_sorted_list(IntImports),
@@ -259,10 +281,15 @@ grab_unqual_imported_modules_make_int(ProgressStream, Globals,
 
         % Get the .int3 files of the modules imported using `use_module'.
         grab_module_int3_files(ProgressStream, Globals,
-            "unqual_parent_used", rwi3_direct_ancestor_use,
-            set.to_sorted_list(AncestorUses),
+            "unqual_parent_int_used", rwi3_direct_ancestor_int_use,
+            set.to_sorted_list(AncestorIntUses),
             !IntIndirectImported, !HaveParseTreeMaps,
             !Baggage, !AugMakeIntUnit, !IO),
+        grab_module_int3_files(ProgressStream, Globals,
+            "unqual_parent_imp_used", rwi3_direct_ancestor_imp_use,
+            set.to_sorted_list(AncestorImpUses),
+            !ImpIndirectImported, !HaveParseTreeMaps,
+            !Baggage, !AugMakeIntUnit, !IO),
         grab_module_int3_files(ProgressStream, Globals,
             "unqual_int_used", rwi3_direct_int_use,
             set.to_sorted_list(IntUses),
@@ -415,7 +442,7 @@ add_missing_imp_module(ModuleName, !ImportAndOrUseMap) :-
 grab_qual_imported_modules_augment(ProgressStream, Globals, MaybeTimestamp,
         ParseTreeModuleSrc0, !:AugCompUnit, !Baggage,
         !HaveParseTreeMaps, !IO) :-
-    % The predicates grab_imported_modules_augment and
+    % The predicates grab_qual_imported_modules_augment and
     % grab_unqual_imported_modules_make_int have quite similar tasks.
     % Please keep the corresponding parts of these two predicates in sync.
     %
@@ -464,10 +491,10 @@ grab_qual_imported_modules_augment(ProgressStream, Globals, MaybeTimestamp,
         import_and_or_use_map_to_module_name_contexts(ImportUseMap,
             IntImportMap, IntUseMap, ImpImportMap, ImpUseMap,
             IntUseImpImportMap),
-        map.keys_as_set(IntImportMap, IntImports0),
-        map.keys_as_set(IntUseMap, IntUses0),
-        ImpImports = map.sorted_keys(ImpImportMap),
-        ImpUses = map.sorted_keys(ImpUseMap),
+        map.keys_as_set(IntImportMap, IntImports),
+        map.keys_as_set(IntUseMap, IntUses),
+        map.keys_as_set(ImpImportMap, ImpImports),
+        map.keys_as_set(ImpUseMap, ImpUses),
         IntUseImpImports = map.sorted_keys(IntUseImpImportMap),
 
         % Get the .int0 files of the ancestor modules.
@@ -479,15 +506,42 @@ grab_qual_imported_modules_augment(ProgressStream, Globals, MaybeTimestamp,
         % AncestorUsed slightly differently from !.IntImported and !.IntUsed.
         Ancestors = get_ancestors(ModuleName),
         grab_module_int0_files_for_acu(ProgressStream, Globals,
-            "ancestors", rwi0_section,
-            Ancestors, IntImports0, IntImports, IntUses0, IntUses,
+            "ancestors", rwi0_section, Ancestors,
+            set.init, AncestorIntImports0, set.init, AncestorIntUses0,
+            set.init, AncestorImpImports0, set.init, AncestorImpUses0,
             !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
 
+        % Any modules that are explicitly imported or used by declarations
+        % in the current module have visibility determined by those
+        % declarations instead of inheriting visibility from ancestor modules.
+        import_and_or_use_map_to_item_avails(do_not_include_implicit,
+            ImportUseMap, ExplicitIntAvails, ExplicitImpAvails),
+        avail_module_names(ExplicitIntAvails ++ ExplicitImpAvails,
+            ExplicitAvailModules),
+        set.difference(AncestorIntImports0, ExplicitAvailModules,
+            AncestorIntImports),
+        set.difference(AncestorImpImports0, ExplicitAvailModules,
+            AncestorImpImports),
+        set.difference(AncestorIntUses0, ExplicitAvailModules,
+            AncestorIntUses),
+        set.difference(AncestorImpUses0, ExplicitAvailModules,
+            AncestorImpUses),
+
         % Get the .int files of the modules imported using `import_module'.
         set.init(!:IntIndirectImported),
         set.init(!:ImpIndirectImported),
         set.init(!:IntImpIndirectImported),
         set.init(!:ImpImpIndirectImported),
+        grab_module_int1_files(ProgressStream, Globals,
+            "ancestor_int_imported", rwi1_ancestor_int_import,
+            set.to_sorted_list(AncestorIntImports),
+            !IntIndirectImported, !IntImpIndirectImported,
+            !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
+        grab_module_int1_files(ProgressStream, Globals,
+            "ancestor_imp_imported", rwi1_ancestor_imp_import,
+            set.to_sorted_list(AncestorImpImports),
+            !ImpIndirectImported, !ImpImpIndirectImported,
+            !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
         grab_module_int1_files(ProgressStream, Globals,
             "int_imported", rwi1_int_import,
             set.to_sorted_list(IntImports),
@@ -495,11 +549,21 @@ grab_qual_imported_modules_augment(ProgressStream, Globals, MaybeTimestamp,
             !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
         grab_module_int1_files(ProgressStream, Globals,
             "imp_imported", rwi1_imp_import,
-            ImpImports,
+            set.to_sorted_list(ImpImports),
             !ImpIndirectImported, !ImpImpIndirectImported,
             !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
 
         % Get the .int files of the modules imported using `use_module'.
+        grab_module_int1_files(ProgressStream, Globals,
+            "ancestor_int_used", rwi1_ancestor_int_use,
+            set.to_sorted_list(AncestorIntUses),
+            !IntIndirectImported, !IntImpIndirectImported,
+            !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
+        grab_module_int1_files(ProgressStream, Globals,
+            "ancestor_imp_used", rwi1_ancestor_imp_use,
+            set.to_sorted_list(AncestorImpUses),
+            !ImpIndirectImported, !ImpImpIndirectImported,
+            !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
         grab_module_int1_files(ProgressStream, Globals,
             "int_used", rwi1_int_use,
             set.to_sorted_list(IntUses),
@@ -507,7 +571,7 @@ grab_qual_imported_modules_augment(ProgressStream, Globals, MaybeTimestamp,
             !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
         grab_module_int1_files(ProgressStream, Globals,
             "imp_used", rwi1_imp_use,
-            ImpUses,
+            set.to_sorted_list(ImpUses),
             !ImpIndirectImported, !ImpImpIndirectImported,
             !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
 
@@ -664,8 +728,13 @@ grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
     grab_module_int0_files_for_acu(ProgressStream, Globals,
         "opt_int0s", rwi0_opt,
         set.to_sorted_list(OptOnlyModuleAncestors),
-        set.init, OptAncestorImports, set.init, OptAncestorUses,
+        set.init, OptAncestorIntImports, set.init, OptAncestorIntUses,
+        set.init, OptAncestorImpImports, set.init, OptAncestorImpUses,
         !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
+    set.union(OptAncestorIntImports, OptAncestorImpImports,
+        OptAncestorImports),
+    set.union(OptAncestorIntUses, OptAncestorImpUses,
+        OptAncestorUses),
 
     % Figure out which .int files are implicitly needed by the .opt files.
     combine_implicit_needs(cord.list(ImplicitNeedsCord), AllImplicitNeeds),
@@ -812,16 +881,20 @@ grab_module_int3_files_transitively(ProgressStream, Globals, Why, ReadWhy3,
     string::in, read_why_int0::in, list(module_name)::in,
     set(module_name)::in, set(module_name)::out,
     set(module_name)::in, set(module_name)::out,
+    set(module_name)::in, set(module_name)::out,
+    set(module_name)::in, set(module_name)::out,
     have_parse_tree_maps::in, have_parse_tree_maps::out,
     module_baggage::in, module_baggage::out,
     aug_compilation_unit::in, aug_compilation_unit::out,
     io::di, io::uo) is det.
 
-grab_module_int0_files_for_acu(_ProgressStream, _Globals, _Why, _ReadWhy0, [],
-        !DirectImports, !DirectUses,
+grab_module_int0_files_for_acu(_ProgressStream, _Globals, _Why, _ReadWhy0,
+        [], !DirectIntImports, !DirectIntUses,
+        !DirectImpImports, !DirectImpUses,
         !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO).
 grab_module_int0_files_for_acu(ProgressStream, Globals, Why, ReadWhy0,
-        [ModuleName | ModuleNames], !DirectImports, !DirectUses,
+        [ModuleName | ModuleNames], !DirectIntImports, !DirectIntUses,
+        !DirectImpImports, !DirectImpUses,
         !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO) :-
     ( if should_read_interface(!.Baggage, ModuleName, ifk_int0) then
         maybe_log_augment_decision(ProgressStream, Why, ifk_int0, ReadWhy0,
@@ -829,32 +902,37 @@ grab_module_int0_files_for_acu(ProgressStream, Globals, Why, ReadWhy0,
         grab_module_int0_file_for_acu(ProgressStream, Globals, ReadWhy0,
             ModuleName, IntImports, ImpImports, IntUses, ImpUses,
             !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO),
-        set.union(IntImports, !DirectImports),
-        set.union(ImpImports, !DirectImports),
-        set.union(IntUses, !DirectUses),
-        set.union(ImpUses, !DirectUses)
+        set.union(IntImports, !DirectIntImports),
+        set.union(ImpImports, !DirectImpImports),
+        set.union(IntUses, !DirectIntUses),
+        set.union(ImpUses, !DirectImpUses)
     else
         maybe_log_augment_decision(ProgressStream, Why, ifk_int0, ReadWhy0,
             ModuleName, decided_not_to_read, !IO)
     ),
     grab_module_int0_files_for_acu(ProgressStream, Globals, Why, ReadWhy0,
-        ModuleNames, !DirectImports, !DirectUses,
+        ModuleNames,
+        !DirectIntImports, !DirectIntUses,
+        !DirectImpImports, !DirectImpUses,
         !HaveParseTreeMaps, !Baggage, !AugCompUnit, !IO).
 
 :- pred grab_module_int0_files_for_amiu(io.text_output_stream::in, globals::in,
     string::in, list(module_name)::in,
     set(module_name)::in, set(module_name)::out,
     set(module_name)::in, set(module_name)::out,
+    set(module_name)::in, set(module_name)::out,
+    set(module_name)::in, set(module_name)::out,
     have_parse_tree_maps::in, have_parse_tree_maps::out,
     module_baggage::in, module_baggage::out,
     aug_make_int_unit::in, aug_make_int_unit::out,
     io::di, io::uo) is det.
 
 grab_module_int0_files_for_amiu(_ProgressStream, _Globals, _Why, [],
-        !DirectImports, !DirectUses,
+        !DirectIntImports, !DirectImpImports, !DirectIntUses, !DirectImpUses,
         !HaveParseTreeMaps, !Baggage, !AugMakeIntUnit, !IO).
 grab_module_int0_files_for_amiu(ProgressStream, Globals, Why,
-        [ModuleName | ModuleNames], !DirectImports, !DirectUses,
+        [ModuleName | ModuleNames],
+        !DirectIntImports, !DirectImpImports, !DirectIntUses, !DirectImpUses,
         !HaveParseTreeMaps, !Baggage, !AugMakeIntUnit, !IO) :-
     ReadWhy0 = rwi0_section,
     ( if should_read_interface(!.Baggage, ModuleName, ifk_int0) then
@@ -863,16 +941,16 @@ grab_module_int0_files_for_amiu(ProgressStream, Globals, Why,
         grab_module_int0_file_for_amiu(ProgressStream, Globals, ModuleName,
             IntImports, ImpImports, IntUses, ImpUses,
             !HaveParseTreeMaps, !Baggage, !AugMakeIntUnit, !IO),
-        set.union(IntImports, !DirectImports),
-        set.union(ImpImports, !DirectImports),
-        set.union(IntUses, !DirectUses),
-        set.union(ImpUses, !DirectUses)
+        set.union(IntImports, !DirectIntImports),
+        set.union(ImpImports, !DirectImpImports),
+        set.union(IntUses, !DirectIntUses),
+        set.union(ImpUses, !DirectImpUses)
     else
         maybe_log_augment_decision(ProgressStream, Why, ifk_int0, ReadWhy0,
             ModuleName, decided_not_to_read, !IO)
     ),
     grab_module_int0_files_for_amiu(ProgressStream, Globals, Why, ModuleNames,
-        !DirectImports, !DirectUses,
+        !DirectIntImports, !DirectImpImports, !DirectIntUses, !DirectImpUses,
         !HaveParseTreeMaps, !Baggage, !AugMakeIntUnit, !IO).
 
 :- pred grab_module_int1_files(io.text_output_stream::in, globals::in,
@@ -1099,16 +1177,24 @@ grab_module_int1_file(ProgressStream, Globals, ReadWhy1, ModuleName,
         module_baggage_add_grabbed_file(ModuleName, GrabbedFile, !Baggage),
         (
             (
-                ReadWhy1 = rwi1_int_import,
+                ( ReadWhy1 = rwi1_ancestor_int_import
+                ; ReadWhy1 = rwi1_int_import
+                ),
                 RecompAvail = recomp_avail_int_import
             ;
-                ReadWhy1 = rwi1_int_use,
+                ( ReadWhy1 = rwi1_ancestor_int_use
+                ; ReadWhy1 = rwi1_int_use
+                ),
                 RecompAvail = recomp_avail_int_use
             ;
-                ReadWhy1 = rwi1_imp_import,
+                ( ReadWhy1 = rwi1_ancestor_imp_import
+                ; ReadWhy1 = rwi1_imp_import
+                ),
                 RecompAvail = recomp_avail_imp_import
             ;
-                ReadWhy1 = rwi1_imp_use,
+                ( ReadWhy1 = rwi1_ancestor_imp_use
+                ; ReadWhy1 = rwi1_imp_use
+                ),
                 RecompAvail = recomp_avail_imp_use
             ;
                 ReadWhy1 = rwi1_int_use_imp_import,
@@ -1212,22 +1298,24 @@ grab_module_int3_file(ProgressStream, Globals, ReadWhy3, ModuleName,
         module_baggage_add_grabbed_file(ModuleName, GrabbedFile, !Baggage),
         (
             (
-                ReadWhy3 = rwi3_direct_ancestor_import,
+                ( ReadWhy3 = rwi3_direct_ancestor_int_import
+                ; ReadWhy3 = rwi3_direct_int_import
+                ),
                 RecompAvail = recomp_avail_int_import
             ;
-                ReadWhy3 = rwi3_direct_int_import,
-                RecompAvail = recomp_avail_int_import
-            ;
-                ReadWhy3 = rwi3_direct_imp_import,
+                ( ReadWhy3 = rwi3_direct_ancestor_imp_import
+                ; ReadWhy3 = rwi3_direct_imp_import
+                ),
                 RecompAvail = recomp_avail_imp_import
             ;
-                ReadWhy3 = rwi3_direct_ancestor_use,
+                ( ReadWhy3 = rwi3_direct_ancestor_int_use
+                ; ReadWhy3 = rwi3_direct_int_use
+                ),
                 RecompAvail = recomp_avail_int_use
             ;
-                ReadWhy3 = rwi3_direct_int_use,
-                RecompAvail = recomp_avail_int_use
-            ;
-                ReadWhy3 = rwi3_direct_imp_use,
+                ( ReadWhy3 = rwi3_direct_ancestor_imp_use
+                ; ReadWhy3 = rwi3_direct_imp_use
+                ),
                 RecompAvail = recomp_avail_imp_use
             ;
                 ReadWhy3 = rwi3_direct_int_use_imp_import,
diff --git a/compiler/make_hlds_separate_items.m b/compiler/make_hlds_separate_items.m
index aba024c4ab..ef2b2f5314 100644
--- a/compiler/make_hlds_separate_items.m
+++ b/compiler/make_hlds_separate_items.m
@@ -1,7 +1,7 @@
 %---------------------------------------------------------------------------%
 % vim: ft=mercury ts=4 sw=4 et
 %---------------------------------------------------------------------------%
-% Copyright (C) 2015-2025 The Mercury team.
+% Copyright (C) 2015-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.
 %---------------------------------------------------------------------------%
@@ -685,6 +685,20 @@ acc_parse_tree_int0(ParseTreeInt0, ReadWhy0, !Acc) :-
 acc_parse_tree_int1(ParseTreeInt1, ReadWhy1, !Acc) :-
     (
         (
+            % XXX import_locn does not distinguish where
+            % the ancestor did the import
+            ( ReadWhy1 = rwi1_ancestor_int_import
+            ; ReadWhy1 = rwi1_ancestor_imp_import
+            ),
+            IntImportLocn = import_locn_import_by_ancestor,
+            IntNeedQual = may_be_unqualified
+        ;
+            ( ReadWhy1 = rwi1_ancestor_int_use
+            ; ReadWhy1 = rwi1_ancestor_imp_use
+            ),
+            IntImportLocn = import_locn_import_by_ancestor,
+            IntNeedQual = must_be_qualified
+        ;
             ReadWhy1 = rwi1_int_import,
             IntImportLocn = import_locn_interface,
             IntNeedQual = may_be_unqualified
diff --git a/compiler/module_baggage.m b/compiler/module_baggage.m
index ae221ac217..f2bc2a472c 100644
--- a/compiler/module_baggage.m
+++ b/compiler/module_baggage.m
@@ -188,25 +188,27 @@
 
 :- type recomp_avail
     --->    recomp_avail_src
-            % The module is the souurce module.
+            % The module is the source module.
     ;       recomp_avail_int_import
             % There was an ":- import_module" in the interface section,
-            % or in an ancestor module. In either case, references to
-            % items defined by the read-in module may be made anywhere
-            % in the source module.
+            % or in the interface section of an ancestor module. In either
+            % case, references to items defined by the read-in module may be
+            % made anywhere in the source module.
     ;       recomp_avail_imp_import
             % There was an ":- import_module" in the implementation section,
-            % or in an optimization file. In either case, references to
+            % or in the implementation section of an ancestor module,
+            % or in an optimization file. In all three cases, references to
             % items defined by the read-in module may be made only in
             % in the implementation section of the source module.
     ;       recomp_avail_int_use
             % There was an ":- use_module" in the interface section,
-            % or in an ancestor module. In either case, references to
-            % items defined by the read-in module may be made anywhere
-            % in the source module.
+            % or in the interface section of an ancestor module. In either
+            % case, references to items defined by the read-in module may be
+            % made anywhere in the source module.
     ;       recomp_avail_imp_use
             % There was an ":- use_module" in the implementation section,
-            % or in an optimization file. In either case, references to
+            % or in the implementation section of an ancestor module,
+            % or in an optimization file. In all three cases, references to
             % items defined by the read-in module may be made only in
             % in the implementation section of the source module.
     ;       recomp_avail_int_use_imp_import.
diff --git a/compiler/module_qual.collect_mq_info.m b/compiler/module_qual.collect_mq_info.m
index 075be800d3..dad225487a 100644
--- a/compiler/module_qual.collect_mq_info.m
+++ b/compiler/module_qual.collect_mq_info.m
@@ -1,7 +1,7 @@
 %---------------------------------------------------------------------------%
 % vim: ft=mercury ts=4 sw=4 et
 %---------------------------------------------------------------------------%
-% Copyright (C) 2015-2024 The Mercury team.
+% Copyright (C) 2015-2024, 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.
 %---------------------------------------------------------------------------%
@@ -86,7 +86,9 @@ collect_mq_info_in_parse_tree_module_src(ParseTreeModuleSrc, !Info) :-
         ImpPromises, _ImpInitialises, _ImpFinalises, _ImpMutables),
 
     mq_info_get_modules(!.Info, Modules0),
-    map.foldl(collect_mq_info_in_included_module_info(IntPermissions),
+    map.foldl(
+        collect_mq_info_in_included_module_info(IntPermissions,
+            ImpPermissions),
         InclMap, Modules0, Modules),
     mq_info_set_modules(Modules, !Info),
 
@@ -241,7 +243,9 @@ collect_mq_info_in_parse_tree_int0(ReadWhy0, ParseTreeInt0, !Info) :-
         _ImpDeclPragmas, _ImpDeclMarkers, ImpPromises),
 
     mq_info_get_modules(!.Info, Modules0),
-    map.foldl(collect_mq_info_in_included_module_info(IntPermissions),
+    map.foldl(
+        collect_mq_info_in_included_module_info(IntPermissions,
+            ImpPermissions),
         InclMap, Modules0, Modules),
     mq_info_set_modules(Modules, !Info),
 
@@ -286,19 +290,27 @@ collect_mq_info_in_parse_tree_int0(ReadWhy0, ParseTreeInt0, !Info) :-
 
 collect_mq_info_in_parse_tree_int1(ReadWhy1, ParseTreeInt1, !Info) :-
     (
-        ReadWhy1 = rwi1_int_import,
+        ( ReadWhy1 = rwi1_ancestor_int_import
+        ; ReadWhy1 = rwi1_int_import
+        ),
         IntPermInInt = may_use_in_int(may_be_unqualified),
         IntPermInImp = may_use_in_imp(may_be_unqualified)
     ;
-        ReadWhy1 = rwi1_imp_import,
+        ( ReadWhy1 = rwi1_ancestor_imp_import
+        ; ReadWhy1 = rwi1_imp_import
+        ),
         IntPermInInt = may_not_use_in_int,
         IntPermInImp = may_use_in_imp(may_be_unqualified)
     ;
-        ReadWhy1 = rwi1_int_use,
+        ( ReadWhy1 = rwi1_ancestor_int_use
+        ; ReadWhy1 = rwi1_int_use
+        ),
         IntPermInInt = may_use_in_int(must_be_qualified),
         IntPermInImp = may_use_in_imp(must_be_qualified)
     ;
-        ReadWhy1 = rwi1_imp_use,
+        ( ReadWhy1 = rwi1_ancestor_imp_use
+        ; ReadWhy1 = rwi1_imp_use
+        ),
         IntPermInInt = may_not_use_in_int,
         IntPermInImp = may_use_in_imp(must_be_qualified)
     ;
@@ -320,6 +332,7 @@ collect_mq_info_in_parse_tree_int1(ReadWhy1, ParseTreeInt1, !Info) :-
     % The implementation section of a .int1 file is abstract imported,
     % which means we have no permission for any item defined there.
     % We therefore do not need any ImpPermissions.
+    ImpPermissions = IntPermissions,
 
     ParseTreeInt1 = parse_tree_int1(_ModuleName, _ModuleNameContext,
         _MaybeVersionNumbers, InclMap,
@@ -330,7 +343,9 @@ collect_mq_info_in_parse_tree_int1(ReadWhy1, ParseTreeInt1, !Info) :-
         _ImpTypeClasses),
 
     mq_info_get_modules(!.Info, Modules0),
-    map.foldl(collect_mq_info_in_included_module_info(IntPermissions),
+    map.foldl(
+        collect_mq_info_in_included_module_info(IntPermissions,
+            ImpPermissions),
         InclMap, Modules0, Modules),
     mq_info_set_modules(Modules, !Info),
 
@@ -602,24 +617,27 @@ collect_mq_info_in_parse_tree_int3(Role, ParseTreeInt3, !Info) :-
     ;
         Role = int3_as_direct_int(ReadWhy3),
         (
-            ( ReadWhy3 = rwi3_direct_ancestor_import
+            ( ReadWhy3 = rwi3_direct_ancestor_int_import
             ; ReadWhy3 = rwi3_direct_int_import
             ),
             PermInInt = may_use_in_int(may_be_unqualified),
             PermInImp = may_use_in_imp(may_be_unqualified)
         ;
-            ( ReadWhy3 = rwi3_direct_ancestor_use
+            ( ReadWhy3 = rwi3_direct_ancestor_int_use
             ; ReadWhy3 = rwi3_direct_int_use
             ; ReadWhy3 = rwi3_indirect_int_use
             ),
             PermInInt = may_use_in_int(must_be_qualified),
             PermInImp = may_use_in_imp(must_be_qualified)
         ;
-            ReadWhy3 = rwi3_direct_imp_import,
+            ( ReadWhy3 = rwi3_direct_ancestor_imp_import
+            ; ReadWhy3 = rwi3_direct_imp_import
+            ),
             PermInInt = may_not_use_in_int,
             PermInImp = may_use_in_imp(may_be_unqualified)
         ;
-            ( ReadWhy3 = rwi3_direct_imp_use
+            ( ReadWhy3 = rwi3_direct_ancestor_imp_use
+            ; ReadWhy3 = rwi3_direct_imp_use
             ; ReadWhy3 = rwi3_indirect_imp_use
             ),
             PermInInt = may_not_use_in_int,
@@ -689,13 +707,12 @@ mode_ctor_to_mq_id(ModeCtor) = Id :-
 %---------------------------------------------------------------------------%
 
 :- pred collect_mq_info_in_included_module_info(module_permissions::in,
-    module_name::in, include_module_info::in,
+    module_permissions::in, module_name::in, include_module_info::in,
     module_id_set::in, module_id_set::out) is det.
 
-collect_mq_info_in_included_module_info(IntPermissions, ModuleName, InclInfo,
-        !Modules) :-
+collect_mq_info_in_included_module_info(IntPermissions, ImpPermissions,
+        ModuleName, InclInfo, !Modules) :-
     InclInfo = include_module_info(Section, _Context),
-    % XXX Why do we test Section if we do the same thing for both int and imp?
     (
         Section = ms_interface,
         Arity = 0,
@@ -703,7 +720,7 @@ collect_mq_info_in_included_module_info(IntPermissions, ModuleName, InclInfo,
     ;
         Section = ms_implementation,
         Arity = 0,
-        id_set_insert(IntPermissions, mq_id(ModuleName, Arity), !Modules)
+        id_set_insert(ImpPermissions, mq_id(ModuleName, Arity), !Modules)
     ).
 
 :- pred collect_mq_info_in_int_incl_context(module_permissions::in,
diff --git a/compiler/module_qual.qualify_items.m b/compiler/module_qual.qualify_items.m
index 6922618199..390ff5e34c 100644
--- a/compiler/module_qual.qualify_items.m
+++ b/compiler/module_qual.qualify_items.m
@@ -135,7 +135,7 @@ module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
     % the errors not from the current version !.Info, but from the version
     % that parse_tree_to_hlds has built on top of !.Info by adding all
     % the contents of AugCompUnit to the HLDS. Therefore that call
-    % will occur at the end of the body of inparse_tree_to_hlds.
+    % will occur at the end of the body of parse_tree_to_hlds.
 
     map.to_assoc_list(EventSpecMap0, EventSpecList0),
     qualify_event_specs(mq_not_used_in_interface, EventSpecFileName,
@@ -184,6 +184,7 @@ module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
         ModuleName = ParseTreeModuleSrc0 ^ ptms_module_name,
         init_mq_info(Globals, ModuleName, should_report_errors, !:Info),
         collect_mq_info_in_parse_tree_module_src(ParseTreeModuleSrc0, !Info),
+        % XXX rwi0_section doesn't distinguish the import location
         list.foldl(collect_mq_info_in_parse_tree_int0(rwi0_section),
             map.values(AncestorInt0s), !Info),
         list.foldl(collect_mq_info_in_direct_int3_spec,
@@ -199,11 +200,11 @@ module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
             NonBlockingUndefSpecs ++ !.Specs,
 
         globals.lookup_bool_option(Globals, warn_unused_interface_imports,
-            WarnInterfaceImports),
+            WarnUnusedInterfaceImports),
         (
-            WarnInterfaceImports = no
+            WarnUnusedInterfaceImports = no
         ;
-            WarnInterfaceImports = yes,
+            WarnUnusedInterfaceImports = yes,
             get_unused_imports_map(!.Info, UnusedImportsContextsMap),
             map.map_values(warn_unused_interface_import(ModuleName),
                 UnusedImportsContextsMap, UnusedImportsSpecsMap),
diff --git a/compiler/prog_parse_tree.m b/compiler/prog_parse_tree.m
index e542c551a4..25d67f278b 100644
--- a/compiler/prog_parse_tree.m
+++ b/compiler/prog_parse_tree.m
@@ -161,7 +161,7 @@
     % was *made* available. If a module had redundant import_module
     % and/or use_module declarations, each of these has had a warning
     % generated for it and was then discarded. One of these declarations
-    % can be made redundant redundant not only by another declaration
+    % can be made redundant not only by another declaration
     % of the same kind in the same section, but also by more permissive
     % declarations; import_module declarations grant more permissions
     % than use_module declarations, and declarations in the interface
@@ -883,30 +883,44 @@
             % Add the parse tree to the set of read-int-for-opt interfaces.
 
 :- type read_why_int1
-    --->    rwi1_int_import
+    --->    rwi1_ancestor_int_import
+    ;       rwi1_int_import
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_int_import as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_int_import, yet).
+
+    ;       rwi1_ancestor_int_use
     ;       rwi1_int_use
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_int_use as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_int_use, yet).
+
+    ;       rwi1_ancestor_imp_import
     ;       rwi1_imp_import
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_imp_import as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_imp_import, yet).
+
+    ;       rwi1_ancestor_imp_use
     ;       rwi1_imp_use
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_imp_use as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_imp_use, yet).
+
     ;       rwi1_int_use_imp_import
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_int_use_imp_import as recompilation reason.
+
     ;       rwi1_opt
             % Add the parse tree to the set of read-int-for-opt interfaces.
             %
             % Record recomp_avail_imp_use as recompilation reason.
+
     ;       rwi1_type_repn.
             % The only items that should be paid attention to from this
             % .int file are the type_repn items. They don't need any
@@ -934,41 +948,45 @@
             % XXX TYPE_REPN Do we need a rwi2_type_repn?
 
 :- type read_why_int3
-    --->    rwi3_direct_ancestor_import
-            % Add the parse tree to the set of directly-read interfaces.
-            %
-            % Record recomp_avail_int_import as recompilation reason.
-            % (Since there is no recomp_avail_ancestor_import, yet).
+    --->    rwi3_direct_ancestor_int_import
     ;       rwi3_direct_int_import
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_int_import as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_int_import, yet).
+
+    ;       rwi3_direct_ancestor_imp_import
     ;       rwi3_direct_imp_import
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_imp_import as recompilation reason.
-    ;       rwi3_direct_ancestor_use
-            % Add the parse tree to the set of directly-read interfaces.
-            %
-            % Record recomp_avail_int_use as recompilation reason.
-            % (Since there is no recomp_avail_ancestor_use, yet).
+            % (Since there is no recomp_avail_ancestor_imp_import, yet).
+
+    ;       rwi3_direct_ancestor_int_use
     ;       rwi3_direct_int_use
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_int_use as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_int_use, yet).
+
+    ;       rwi3_direct_ancestor_imp_use
     ;       rwi3_direct_imp_use
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_imp_use as recompilation reason.
+            % (Since there is no recomp_avail_ancestor_imp_use, yet).
+
     ;       rwi3_direct_int_use_imp_import
             % Add the parse tree to the set of directly-read interfaces.
             %
             % Record recomp_avail_int_use_imp_import as recompilation reason.
+
     ;       rwi3_indirect_int_use
             % Add the parse tree to the set of indirectly-read interfaces.
             %
             % Record recomp_avail_int_use as recompilation reason.
             % (Since there is no recomp_avail_indirect_use_int, yet).
+
     ;       rwi3_indirect_imp_use.
             % Add the parse tree to the set of indirectly-read interfaces.
             %
diff --git a/doc/mercury_reference_manual.texi b/doc/mercury_reference_manual.texi
index f7d5e18566..ebed23b191 100644
--- a/doc/mercury_reference_manual.texi
+++ b/doc/mercury_reference_manual.texi
@@ -6804,7 +6804,7 @@ A module may not contain more than one submodule with the same name.
 @menu
 * Nested submodules::
 * Separate submodules::
-* Visibility rules::
+* Submodule visibility rules::
 * Implementation bugs and limitations::
 @end menu
 
@@ -6937,30 +6937,56 @@ is equivalent to
 :- end_module x.
 @end example
 
-@node Visibility rules
-@subsection Visibility rules
+@node Submodule visibility rules
+@subsection Submodule visibility rules
 
 Any declarations in the parent module,
 including those in the parent module's implementation section,
 are visible in the parent's submodules,
 including indirect submodules (i.e.@: sub-submodules, etc.).
-Similarly, declarations in the interfaces of any modules
-imported using an @samp{:- import_module} or a @samp{:- use_module}
-in the parent module
-are visible in the parent's submodules, including indirect submodules.
 
-Declarations in a child module are not visible in the parent module,
+Declarations in a submodule are not visible
+in the submodule's ancestor modules,
 or in ``sibling'' modules (other children of the same parent),
-or in other unrelated modules
-unless the child is explicitly imported using
+or in other unrelated modules,
+unless the submodule is explicitly imported using
 an @samp{:- import_module} or @samp{:- use_module} declaration.
-It is an error to import a module without importing all of its parent modules.
+It is an error to import a module without importing all of its
+ancestor modules.
 
-Note that a submodule for which
+A submodule for which
 the @samp{:- module} or @samp{:- include_module} declaration
 occurs only in the implementation section of the parent module
 may only be imported or used by its parent module
 or by submodules of its parent module.
+@c Note: we do not prevent a submodule declared in the implementation section
+@c from being imported in an interface section. One use for this is to
+@c have submodules that present a public interface to unrelated modules,
+@c but share a private interface amongst themselves.
+
+If a submodule contains
+@samp{:- import_module} or @samp{:- use_module} declarations
+for a module @samp{x},
+then the entities exported by @samp{x}
+are visible in the submodule in the usual way.
+
+Otherwise,
+if a submodule does not import or use @samp{x} directly,
+but @samp{x} is imported by one or more of its ancestor modules through
+@samp{:- import_module} or @samp{:- use_module} declarations,
+then the submodule inherits visibility of
+the entities exported by @samp{x}
+as follows:
+@itemize
+@item
+if @samp{x} is imported in an ancestor module's interface section,
+then the entities exported by @samp{x} are visible to
+both sections of the submodule;
+@item
+if @samp{x} is imported in an ancestor module's implementation section,
+then the entities exported by @samp{x} are visible to
+the implementation section of the submodule.
+@end itemize
 
 As mentioned previously,
 all @samp{:- import_module} and @samp{:- use_module} declarations
diff --git a/library/bit_buffer.read.m b/library/bit_buffer.read.m
index 46faa9d0e1..ab8ed43494 100644
--- a/library/bit_buffer.read.m
+++ b/library/bit_buffer.read.m
@@ -37,6 +37,7 @@
 :- interface.
 
 :- import_module bitmap.
+:- import_module bool.
 :- import_module io.
 
 :- type read_buffer(Stream, State, Error).
diff --git a/library/bit_buffer.write.m b/library/bit_buffer.write.m
index 2f9f17ca6d..228465444b 100644
--- a/library/bit_buffer.write.m
+++ b/library/bit_buffer.write.m
@@ -2,7 +2,7 @@
 % vim: ts=4 sw=4 et ft=mercury
 %---------------------------------------------------------------------------%
 % Copyright (C) 2007, 2011 The University of Melbourne
-% Copyright (C) 2014-2016, 2018, 2024-2025 The Mercury team.
+% Copyright (C) 2014-2016, 2018, 2024-2026 The Mercury team.
 % This file is distributed under the terms specified in COPYING.LIB.
 %---------------------------------------------------------------------------%
 %
@@ -27,6 +27,7 @@
 :- module bit_buffer.write.
 :- interface.
 
+:- import_module bool.
 :- import_module io.
 
 :- type write_buffer(Stream, State).
diff --git a/library/io.text_read.m b/library/io.text_read.m
index 7cf056cd6a..8b50a1d198 100644
--- a/library/io.text_read.m
+++ b/library/io.text_read.m
@@ -18,11 +18,6 @@
 :- module io.text_read.
 :- interface.
 
-:- import_module bitmap.
-:- import_module list.
-
-%---------------------------------------------------------------------------%
-
 :- pred read_word_2(io.text_input_stream::in, io.result(list(char))::out,
     io::di, io::uo) is det.
 
@@ -58,7 +53,6 @@
 :- implementation.
 
 :- import_module array.
-:- import_module char.
 :- import_module int.
 :- import_module int64.
 :- import_module io.primitives_read.
diff --git a/library/string.builder.m b/library/string.builder.m
index 2c49fe84ef..5ea3c91d5f 100644
--- a/library/string.builder.m
+++ b/library/string.builder.m
@@ -2,7 +2,7 @@
 % vim: ft=mercury ts=4 sw=4 et
 %---------------------------------------------------------------------------%
 % Copyright (C) 2006-2007 The University of Melbourne.
-% Copyright (C) 2014-2015, 2018, 2022-2025 The Mercury team.
+% Copyright (C) 2014-2015, 2018, 2022-2026 The Mercury team.
 % This file is distributed under the terms specified in COPYING.LIB.
 %---------------------------------------------------------------------------%
 %
@@ -111,11 +111,6 @@
 
 :- implementation.
 
-:- import_module int.
-:- import_module list.
-
-%---------------------------------------------------------------------------%
-
 :- type state
     --->    state(list(string)).
             % A reversed list of the strings that, when unreversed
diff --git a/tests/invalid_submodules/Mmakefile b/tests/invalid_submodules/Mmakefile
index 275b1668f7..c0937f50f4 100644
--- a/tests/invalid_submodules/Mmakefile
+++ b/tests/invalid_submodules/Mmakefile
@@ -30,6 +30,27 @@ MAKE_DEP_ONLY_PROGS = \
 	func_class \
 	nested_impl_in_int
 
+BUG584_PROGS = \
+	bug584
+
+SUB_VISIBILITY_PROGS = \
+	sub_visibility_a1 \
+	sub_visibility_a2 \
+	sub_visibility_a3 \
+	sub_visibility_a4 \
+	sub_visibility_b1 \
+	sub_visibility_b2 \
+	sub_visibility_b3 \
+	sub_visibility_b4 \
+	sub_visibility_c1 \
+	sub_visibility_c2 \
+	sub_visibility_c3 \
+	sub_visibility_c4 \
+	sub_visibility_d1 \
+	sub_visibility_d2 \
+	sub_visibility_d3 \
+	sub_visibility_d4
+
 # XXX The test cases import_in_parent and subtype_submodule are
 # currently disabled, because
 #
@@ -45,11 +66,15 @@ MAKE_DEP_ONLY_PROGS = \
 
 #-----------------------------------------------------------------------------#
 
-PROGS = $(STD_PROGS) $(MAKE_DEP_ONLY_PROGS)
+PROGS = $(STD_PROGS) $(MAKE_DEP_ONLY_PROGS) $(BUG584_PROGS) \
+	$(SUB_VISIBILITY_PROGS)
 # For the MAKE_DEP_ONLY_PROGS, we want to make the dependencies
 # using our own rule below, not the usual rule, which is why we disable
 # the usual rule for them via the -nodepend suffix.
-TESTS = $(sort $(STD_PROGS) $(MAKE_DEP_ONLY_PROGS:%=%-nodepend))
+TESTS = $(sort $(STD_PROGS) \
+		$(MAKE_DEP_ONLY_PROGS:%=%-nodepend) \
+		$(BUG584_PROGS:%=%-nodepend) \
+		$(SUB_VISIBILITY_PROGS:%=%-nodepend))
 include ../Mmake.common
 
 # Module-specific options should go in Mercury.options so they can be found
@@ -97,6 +122,27 @@ $(MAKE_DEP_ONLY_PROGS:%=%.err): %.err: %.m
 	else true; \
 	fi
 
+# For this test case, the bug is caught when generating the interface for the
+# helper module.
+bug584.err: %.err: %.m
+	$(MC) --make-short-interface $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) \
+		bug584_helper_1
+	$(MC) --make-private-interface $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) \
+		bug584_helper_1
+	if $(MC) --make-interface $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) \
+		bug584_helper_1 > $*.err 2>&1; \
+	then false; \
+	else true; \
+	fi
+
+$(SUB_VISIBILITY_PROGS:%=%.err): %.err: %.m
+	{ \
+	$(MC) --make-short-interface $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) $< && \
+	$(MC) --make-private-interface $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) $< && \
+	$(MC) --make-interface $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) $< && \
+	$(MC) -C $(ALL_GRADEFLAGS) $(ALL_MCFLAGS) $<; \
+	} > $@ 2>&1 || true
+
 $(dates_subdir)undef_mod_qual.date: $(int0s_subdir)undef_mod_qual.int0
 
 clean_local: clean_invalid_submodules
diff --git a/tests/invalid_submodules/bug584.err_exp b/tests/invalid_submodules/bug584.err_exp
new file mode 100644
index 0000000000..95b33055c3
--- /dev/null
+++ b/tests/invalid_submodules/bug584.err_exp
@@ -0,0 +1,12 @@
+bug584_helper_1.m:018: In the second argument of function symbol `struct'
+bug584_helper_1.m:018:   (field name `f2') of the type `struct'/0:
+bug584_helper_1.m:018:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+bug584_helper_1.m:018:   (The module [38;5;87m`bug584_helper_1.sub2'[39;49m [38;5;203mhas not been[39;49m
+bug584_helper_1.m:018:   [38;5;203mimported in the interface.)[39;49m
+bug584_helper_1.m:019: In the third argument of function symbol `struct' (field
+bug584_helper_1.m:019:   name `f3') of the type `struct'/0:
+bug584_helper_1.m:019:   error: the type [38;5;87m`bug584_helper_1.sub2.foo'/0[39;49m is
+bug584_helper_1.m:019:   [38;5;203mundefined.[39;49m
+bug584_helper_1.m:019:   (The module [38;5;87m`bug584_helper_1.sub2'[39;49m [38;5;203mhas not been[39;49m
+bug584_helper_1.m:019:   [38;5;203mimported in the interface.)[39;49m
+`bug584_helper_1.sub1.int' and `bug584_helper_1.sub1.int2' not written.
diff --git a/tests/invalid_submodules/bug584.err_exp2 b/tests/invalid_submodules/bug584.err_exp2
new file mode 100644
index 0000000000..250e60a2ef
--- /dev/null
+++ b/tests/invalid_submodules/bug584.err_exp2
@@ -0,0 +1,13 @@
+bug584_helper_1.m:018: In the second argument of function symbol `struct'
+bug584_helper_1.m:018:   (field name `f2') of the type `struct'/0:
+bug584_helper_1.m:018:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+bug584_helper_1.m:018:   (The module [38;5;87m`bug584_helper_1.sub2'[39;49m [38;5;203mhas not been[39;49m
+bug584_helper_1.m:018:   [38;5;203mimported in the interface.)[39;49m
+bug584_helper_1.m:019: In the third argument of function symbol `struct' (field
+bug584_helper_1.m:019:   name `f3') of the type `struct'/0:
+bug584_helper_1.m:019:   error: the type [38;5;87m`bug584_helper_1.sub2.foo'/0[39;49m is
+bug584_helper_1.m:019:   [38;5;203mundefined.[39;49m
+bug584_helper_1.m:019:   (The module [38;5;87m`bug584_helper_1.sub2'[39;49m [38;5;203mhas not been[39;49m
+bug584_helper_1.m:019:   [38;5;203mimported in the interface.)[39;49m
+`Mercury/ints/bug584_helper_1.sub1.int' and
+  `Mercury/int2s/bug584_helper_1.sub1.int2' not written.
diff --git a/tests/invalid_submodules/bug584.m b/tests/invalid_submodules/bug584.m
new file mode 100644
index 0000000000..ea0f2d28ae
--- /dev/null
+++ b/tests/invalid_submodules/bug584.m
@@ -0,0 +1,23 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module bug584.
+:- interface.
+
+:- import_module bug584_helper_1.
+:- import_module bug584_helper_1.sub1.
+
+:- pred get_field1(struct::in, int::out) is det.
+
+:- implementation.
+
+get_field1(Struct, F1) :-
+    F1 = Struct ^ f1.
+
+:- end_module bug584.
diff --git a/tests/invalid_submodules/bug584_helper_1.m b/tests/invalid_submodules/bug584_helper_1.m
new file mode 100644
index 0000000000..78a0c4b04c
--- /dev/null
+++ b/tests/invalid_submodules/bug584_helper_1.m
@@ -0,0 +1,36 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module bug584_helper_1.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    % By the old rules, foo would be visible in this interface section due to
+    % the `import_module' declaration in the implementation section
+    % of the parent module.
+
+    :- type struct
+        --->    struct(
+                    f1 :: int,
+                    f2 :: foo,
+                    f3 :: bug584_helper_1.sub2.foo
+                ).
+
+    :- end_module sub1.
+
+:- implementation.
+
+    :- import_module bug584_helper_1.sub2.
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo
+        --->    foo.
+
+    :- end_module sub2.
+
+:- end_module bug584_helper_1.
diff --git a/tests/invalid_submodules/sub_visibility_a1.err_exp b/tests/invalid_submodules/sub_visibility_a1.err_exp
new file mode 100644
index 0000000000..6773c2c320
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a1.err_exp
@@ -0,0 +1,4 @@
+sub_visibility_a1.m:008: In module `sub_visibility_a1':
+sub_visibility_a1.m:008:   warning: module [38;5;87m`sub_visibility_a1.sub2'[39;49m is imported
+sub_visibility_a1.m:008:   in the interface, but it is [38;5;203mnot used in the[39;49m
+sub_visibility_a1.m:008:   [38;5;203minterface.[39;49m
diff --git a/tests/invalid_submodules/sub_visibility_a1.m b/tests/invalid_submodules/sub_visibility_a1.m
new file mode 100644
index 0000000000..72112a1a6b
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a1.m
@@ -0,0 +1,44 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_a1.
+:- interface.
+
+:- import_module sub_visibility_a1.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- import_module sub_visibility_a1.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % ok
+    :- type int_fq ---> int_fq(sub_visibility_a1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_a1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_a1.
diff --git a/tests/invalid_submodules/sub_visibility_a2.err_exp b/tests/invalid_submodules/sub_visibility_a2.err_exp
new file mode 100644
index 0000000000..b4377a7d3c
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a2.err_exp
@@ -0,0 +1,13 @@
+sub_visibility_a2.m:022: In the first argument of function symbol `int_uq' of
+sub_visibility_a2.m:022:   the type `int_uq'/0:
+sub_visibility_a2.m:022:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a2.m:022:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_a2.m:022:   entities defined in module [38;5;87m[39;49m
+sub_visibility_a2.m:022:   [38;5;87m`sub_visibility_a2.sub2'.[39;49m)
+sub_visibility_a2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_a2.m:035:   the type `imp_uq'/0:
+sub_visibility_a2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_a2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_a2.m:035:   [38;5;87m`sub_visibility_a2.sub2'.[39;49m)
+`sub_visibility_a2.sub1.int' and `sub_visibility_a2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_a2.err_exp2 b/tests/invalid_submodules/sub_visibility_a2.err_exp2
new file mode 100644
index 0000000000..b83c2ff272
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a2.err_exp2
@@ -0,0 +1,14 @@
+sub_visibility_a2.m:022: In the first argument of function symbol `int_uq' of
+sub_visibility_a2.m:022:   the type `int_uq'/0:
+sub_visibility_a2.m:022:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a2.m:022:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_a2.m:022:   entities defined in module [38;5;87m[39;49m
+sub_visibility_a2.m:022:   [38;5;87m`sub_visibility_a2.sub2'.[39;49m)
+sub_visibility_a2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_a2.m:035:   the type `imp_uq'/0:
+sub_visibility_a2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_a2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_a2.m:035:   [38;5;87m`sub_visibility_a2.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_a2.sub1.int' and
+  `Mercury/int2s/sub_visibility_a2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_a2.m b/tests/invalid_submodules/sub_visibility_a2.m
new file mode 100644
index 0000000000..79f007385e
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a2.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_a2.
+:- interface.
+
+:- import_module sub_visibility_a2.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- use_module sub_visibility_a2.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_a2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_a2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_a2.
diff --git a/tests/invalid_submodules/sub_visibility_a3.err_exp b/tests/invalid_submodules/sub_visibility_a3.err_exp
new file mode 100644
index 0000000000..9a1971e1d5
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a3.err_exp
@@ -0,0 +1,12 @@
+sub_visibility_a3.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_a3.m:020:   the type `int_uq'/0:
+sub_visibility_a3.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a3.m:020:   (The module [38;5;87m`sub_visibility_a3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a3.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_a3.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_a3.m:021:   the type `int_fq'/0:
+sub_visibility_a3.m:021:   error: the type [38;5;87m`sub_visibility_a3.sub2.foo'/0[39;49m is
+sub_visibility_a3.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_a3.m:021:   (The module [38;5;87m`sub_visibility_a3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a3.m:021:   [38;5;203mimported in the interface.)[39;49m
+`sub_visibility_a3.sub1.int' and `sub_visibility_a3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_a3.err_exp2 b/tests/invalid_submodules/sub_visibility_a3.err_exp2
new file mode 100644
index 0000000000..443e19bdf9
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a3.err_exp2
@@ -0,0 +1,13 @@
+sub_visibility_a3.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_a3.m:020:   the type `int_uq'/0:
+sub_visibility_a3.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a3.m:020:   (The module [38;5;87m`sub_visibility_a3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a3.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_a3.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_a3.m:021:   the type `int_fq'/0:
+sub_visibility_a3.m:021:   error: the type [38;5;87m`sub_visibility_a3.sub2.foo'/0[39;49m is
+sub_visibility_a3.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_a3.m:021:   (The module [38;5;87m`sub_visibility_a3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a3.m:021:   [38;5;203mimported in the interface.)[39;49m
+`Mercury/ints/sub_visibility_a3.sub1.int' and
+  `Mercury/int2s/sub_visibility_a3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_a3.m b/tests/invalid_submodules/sub_visibility_a3.m
new file mode 100644
index 0000000000..acd3637198
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a3.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_a3.
+:- interface.
+
+:- import_module sub_visibility_a3.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_a3.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- import_module sub_visibility_a3.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_a3.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_a3.
diff --git a/tests/invalid_submodules/sub_visibility_a4.err_exp b/tests/invalid_submodules/sub_visibility_a4.err_exp
new file mode 100644
index 0000000000..ceee8197b0
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a4.err_exp
@@ -0,0 +1,18 @@
+sub_visibility_a4.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_a4.m:020:   the type `int_uq'/0:
+sub_visibility_a4.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a4.m:020:   (The module [38;5;87m`sub_visibility_a4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a4.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_a4.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_a4.m:021:   the type `int_fq'/0:
+sub_visibility_a4.m:021:   error: the type [38;5;87m`sub_visibility_a4.sub2.foo'/0[39;49m is
+sub_visibility_a4.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_a4.m:021:   (The module [38;5;87m`sub_visibility_a4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a4.m:021:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_a4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_a4.m:035:   the type `imp_uq'/0:
+sub_visibility_a4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_a4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_a4.m:035:   [38;5;87m`sub_visibility_a4.sub2'.[39;49m)
+`sub_visibility_a4.sub1.int' and `sub_visibility_a4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_a4.err_exp2 b/tests/invalid_submodules/sub_visibility_a4.err_exp2
new file mode 100644
index 0000000000..8b33cbc1d1
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a4.err_exp2
@@ -0,0 +1,19 @@
+sub_visibility_a4.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_a4.m:020:   the type `int_uq'/0:
+sub_visibility_a4.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a4.m:020:   (The module [38;5;87m`sub_visibility_a4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a4.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_a4.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_a4.m:021:   the type `int_fq'/0:
+sub_visibility_a4.m:021:   error: the type [38;5;87m`sub_visibility_a4.sub2.foo'/0[39;49m is
+sub_visibility_a4.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_a4.m:021:   (The module [38;5;87m`sub_visibility_a4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_a4.m:021:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_a4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_a4.m:035:   the type `imp_uq'/0:
+sub_visibility_a4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_a4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_a4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_a4.m:035:   [38;5;87m`sub_visibility_a4.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_a4.sub1.int' and
+  `Mercury/int2s/sub_visibility_a4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_a4.m b/tests/invalid_submodules/sub_visibility_a4.m
new file mode 100644
index 0000000000..e6a778b2f4
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_a4.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_a4.
+:- interface.
+
+:- import_module sub_visibility_a4.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_a4.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- use_module sub_visibility_a4.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_a4.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_a4.
diff --git a/tests/invalid_submodules/sub_visibility_b1.err_exp b/tests/invalid_submodules/sub_visibility_b1.err_exp
new file mode 100644
index 0000000000..8653a594d2
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b1.err_exp
@@ -0,0 +1,4 @@
+sub_visibility_b1.m:008: In module `sub_visibility_b1':
+sub_visibility_b1.m:008:   warning: module [38;5;87m`sub_visibility_b1.sub2'[39;49m is imported
+sub_visibility_b1.m:008:   in the interface, but it is [38;5;203mnot used in the[39;49m
+sub_visibility_b1.m:008:   [38;5;203minterface.[39;49m
diff --git a/tests/invalid_submodules/sub_visibility_b1.m b/tests/invalid_submodules/sub_visibility_b1.m
new file mode 100644
index 0000000000..a204895b20
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b1.m
@@ -0,0 +1,44 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_b1.
+:- interface.
+
+:- use_module sub_visibility_b1.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- import_module sub_visibility_b1.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % ok
+    :- type int_fq ---> int_fq(sub_visibility_b1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_b1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_b1.
diff --git a/tests/invalid_submodules/sub_visibility_b2.err_exp b/tests/invalid_submodules/sub_visibility_b2.err_exp
new file mode 100644
index 0000000000..32009818a2
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b2.err_exp
@@ -0,0 +1,13 @@
+sub_visibility_b2.m:022: In the first argument of function symbol `int_uq' of
+sub_visibility_b2.m:022:   the type `int_uq'/0:
+sub_visibility_b2.m:022:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b2.m:022:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_b2.m:022:   entities defined in module [38;5;87m[39;49m
+sub_visibility_b2.m:022:   [38;5;87m`sub_visibility_b2.sub2'.[39;49m)
+sub_visibility_b2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_b2.m:035:   the type `imp_uq'/0:
+sub_visibility_b2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_b2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_b2.m:035:   [38;5;87m`sub_visibility_b2.sub2'.[39;49m)
+`sub_visibility_b2.sub1.int' and `sub_visibility_b2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_b2.err_exp2 b/tests/invalid_submodules/sub_visibility_b2.err_exp2
new file mode 100644
index 0000000000..ddcf62fd77
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b2.err_exp2
@@ -0,0 +1,14 @@
+sub_visibility_b2.m:022: In the first argument of function symbol `int_uq' of
+sub_visibility_b2.m:022:   the type `int_uq'/0:
+sub_visibility_b2.m:022:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b2.m:022:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_b2.m:022:   entities defined in module [38;5;87m[39;49m
+sub_visibility_b2.m:022:   [38;5;87m`sub_visibility_b2.sub2'.[39;49m)
+sub_visibility_b2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_b2.m:035:   the type `imp_uq'/0:
+sub_visibility_b2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_b2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_b2.m:035:   [38;5;87m`sub_visibility_b2.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_b2.sub1.int' and
+  `Mercury/int2s/sub_visibility_b2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_b2.m b/tests/invalid_submodules/sub_visibility_b2.m
new file mode 100644
index 0000000000..57ac8adc07
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b2.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_b2.
+:- interface.
+
+:- use_module sub_visibility_b2.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- use_module sub_visibility_b2.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_b2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_b2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_b2.
diff --git a/tests/invalid_submodules/sub_visibility_b3.err_exp b/tests/invalid_submodules/sub_visibility_b3.err_exp
new file mode 100644
index 0000000000..eb2ab23cdf
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b3.err_exp
@@ -0,0 +1,12 @@
+sub_visibility_b3.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_b3.m:020:   the type `int_uq'/0:
+sub_visibility_b3.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b3.m:020:   (The module [38;5;87m`sub_visibility_b3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b3.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_b3.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_b3.m:021:   the type `int_fq'/0:
+sub_visibility_b3.m:021:   error: the type [38;5;87m`sub_visibility_b3.sub2.foo'/0[39;49m is
+sub_visibility_b3.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_b3.m:021:   (The module [38;5;87m`sub_visibility_b3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b3.m:021:   [38;5;203mimported in the interface.)[39;49m
+`sub_visibility_b3.sub1.int' and `sub_visibility_b3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_b3.err_exp2 b/tests/invalid_submodules/sub_visibility_b3.err_exp2
new file mode 100644
index 0000000000..5df9c2481f
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b3.err_exp2
@@ -0,0 +1,13 @@
+sub_visibility_b3.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_b3.m:020:   the type `int_uq'/0:
+sub_visibility_b3.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b3.m:020:   (The module [38;5;87m`sub_visibility_b3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b3.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_b3.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_b3.m:021:   the type `int_fq'/0:
+sub_visibility_b3.m:021:   error: the type [38;5;87m`sub_visibility_b3.sub2.foo'/0[39;49m is
+sub_visibility_b3.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_b3.m:021:   (The module [38;5;87m`sub_visibility_b3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b3.m:021:   [38;5;203mimported in the interface.)[39;49m
+`Mercury/ints/sub_visibility_b3.sub1.int' and
+  `Mercury/int2s/sub_visibility_b3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_b3.m b/tests/invalid_submodules/sub_visibility_b3.m
new file mode 100644
index 0000000000..2b75736200
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b3.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_b3.
+:- interface.
+
+:- use_module sub_visibility_b3.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_b3.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- import_module sub_visibility_b3.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_b3.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_b3.
diff --git a/tests/invalid_submodules/sub_visibility_b4.err_exp b/tests/invalid_submodules/sub_visibility_b4.err_exp
new file mode 100644
index 0000000000..fb5f72108d
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b4.err_exp
@@ -0,0 +1,18 @@
+sub_visibility_b4.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_b4.m:020:   the type `int_uq'/0:
+sub_visibility_b4.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b4.m:020:   (The module [38;5;87m`sub_visibility_b4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b4.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_b4.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_b4.m:021:   the type `int_fq'/0:
+sub_visibility_b4.m:021:   error: the type [38;5;87m`sub_visibility_b4.sub2.foo'/0[39;49m is
+sub_visibility_b4.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_b4.m:021:   (The module [38;5;87m`sub_visibility_b4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b4.m:021:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_b4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_b4.m:035:   the type `imp_uq'/0:
+sub_visibility_b4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_b4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_b4.m:035:   [38;5;87m`sub_visibility_b4.sub2'.[39;49m)
+`sub_visibility_b4.sub1.int' and `sub_visibility_b4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_b4.err_exp2 b/tests/invalid_submodules/sub_visibility_b4.err_exp2
new file mode 100644
index 0000000000..27a459ae8e
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b4.err_exp2
@@ -0,0 +1,19 @@
+sub_visibility_b4.m:020: In the first argument of function symbol `int_uq' of
+sub_visibility_b4.m:020:   the type `int_uq'/0:
+sub_visibility_b4.m:020:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b4.m:020:   (The module [38;5;87m`sub_visibility_b4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b4.m:020:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_b4.m:021: In the first argument of function symbol `int_fq' of
+sub_visibility_b4.m:021:   the type `int_fq'/0:
+sub_visibility_b4.m:021:   error: the type [38;5;87m`sub_visibility_b4.sub2.foo'/0[39;49m is
+sub_visibility_b4.m:021:   [38;5;203mundefined.[39;49m
+sub_visibility_b4.m:021:   (The module [38;5;87m`sub_visibility_b4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_b4.m:021:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_b4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_b4.m:035:   the type `imp_uq'/0:
+sub_visibility_b4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_b4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_b4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_b4.m:035:   [38;5;87m`sub_visibility_b4.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_b4.sub1.int' and
+  `Mercury/int2s/sub_visibility_b4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_b4.m b/tests/invalid_submodules/sub_visibility_b4.m
new file mode 100644
index 0000000000..71153c7a6f
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_b4.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_b4.
+:- interface.
+
+:- use_module sub_visibility_b4.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_b4.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+    :- module sub1.
+    :- implementation.
+
+    :- use_module sub_visibility_b4.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_b4.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_b4.
diff --git a/tests/invalid_submodules/sub_visibility_c1.err_exp b/tests/invalid_submodules/sub_visibility_c1.err_exp
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/invalid_submodules/sub_visibility_c1.m b/tests/invalid_submodules/sub_visibility_c1.m
new file mode 100644
index 0000000000..c86db0028a
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c1.m
@@ -0,0 +1,44 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_c1.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- import_module sub_visibility_c1.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % ok
+    :- type int_fq ---> int_fq(sub_visibility_c1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module sub_visibility_c1.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_c1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_c1.
diff --git a/tests/invalid_submodules/sub_visibility_c2.err_exp b/tests/invalid_submodules/sub_visibility_c2.err_exp
new file mode 100644
index 0000000000..cefbc5e377
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c2.err_exp
@@ -0,0 +1,13 @@
+sub_visibility_c2.m:018: In the first argument of function symbol `int_uq' of
+sub_visibility_c2.m:018:   the type `int_uq'/0:
+sub_visibility_c2.m:018:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c2.m:018:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_c2.m:018:   entities defined in module [38;5;87m[39;49m
+sub_visibility_c2.m:018:   [38;5;87m`sub_visibility_c2.sub2'.[39;49m)
+sub_visibility_c2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_c2.m:035:   the type `imp_uq'/0:
+sub_visibility_c2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_c2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_c2.m:035:   [38;5;87m`sub_visibility_c2.sub2'.[39;49m)
+`sub_visibility_c2.sub1.int' and `sub_visibility_c2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_c2.err_exp2 b/tests/invalid_submodules/sub_visibility_c2.err_exp2
new file mode 100644
index 0000000000..11643160bb
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c2.err_exp2
@@ -0,0 +1,14 @@
+sub_visibility_c2.m:018: In the first argument of function symbol `int_uq' of
+sub_visibility_c2.m:018:   the type `int_uq'/0:
+sub_visibility_c2.m:018:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c2.m:018:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_c2.m:018:   entities defined in module [38;5;87m[39;49m
+sub_visibility_c2.m:018:   [38;5;87m`sub_visibility_c2.sub2'.[39;49m)
+sub_visibility_c2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_c2.m:035:   the type `imp_uq'/0:
+sub_visibility_c2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_c2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_c2.m:035:   [38;5;87m`sub_visibility_c2.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_c2.sub1.int' and
+  `Mercury/int2s/sub_visibility_c2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_c2.m b/tests/invalid_submodules/sub_visibility_c2.m
new file mode 100644
index 0000000000..85ca169518
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c2.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_c2.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- use_module sub_visibility_c2.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_c2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module sub_visibility_c2.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_c2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_c2.
diff --git a/tests/invalid_submodules/sub_visibility_c3.err_exp b/tests/invalid_submodules/sub_visibility_c3.err_exp
new file mode 100644
index 0000000000..f86c53d6ea
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c3.err_exp
@@ -0,0 +1,12 @@
+sub_visibility_c3.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_c3.m:016:   the type `int_uq'/0:
+sub_visibility_c3.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c3.m:016:   (The module [38;5;87m`sub_visibility_c3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c3.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_c3.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_c3.m:017:   the type `int_fq'/0:
+sub_visibility_c3.m:017:   error: the type [38;5;87m`sub_visibility_c3.sub2.foo'/0[39;49m is
+sub_visibility_c3.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_c3.m:017:   (The module [38;5;87m`sub_visibility_c3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c3.m:017:   [38;5;203mimported in the interface.)[39;49m
+`sub_visibility_c3.sub1.int' and `sub_visibility_c3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_c3.err_exp2 b/tests/invalid_submodules/sub_visibility_c3.err_exp2
new file mode 100644
index 0000000000..95c02136e6
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c3.err_exp2
@@ -0,0 +1,13 @@
+sub_visibility_c3.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_c3.m:016:   the type `int_uq'/0:
+sub_visibility_c3.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c3.m:016:   (The module [38;5;87m`sub_visibility_c3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c3.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_c3.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_c3.m:017:   the type `int_fq'/0:
+sub_visibility_c3.m:017:   error: the type [38;5;87m`sub_visibility_c3.sub2.foo'/0[39;49m is
+sub_visibility_c3.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_c3.m:017:   (The module [38;5;87m`sub_visibility_c3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c3.m:017:   [38;5;203mimported in the interface.)[39;49m
+`Mercury/ints/sub_visibility_c3.sub1.int' and
+  `Mercury/int2s/sub_visibility_c3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_c3.m b/tests/invalid_submodules/sub_visibility_c3.m
new file mode 100644
index 0000000000..1d0037f225
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c3.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_c3.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_c3.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module sub_visibility_c3.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- import_module sub_visibility_c3.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_c3.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_c3.
diff --git a/tests/invalid_submodules/sub_visibility_c4.err_exp b/tests/invalid_submodules/sub_visibility_c4.err_exp
new file mode 100644
index 0000000000..f8df6177c8
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c4.err_exp
@@ -0,0 +1,18 @@
+sub_visibility_c4.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_c4.m:016:   the type `int_uq'/0:
+sub_visibility_c4.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c4.m:016:   (The module [38;5;87m`sub_visibility_c4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c4.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_c4.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_c4.m:017:   the type `int_fq'/0:
+sub_visibility_c4.m:017:   error: the type [38;5;87m`sub_visibility_c4.sub2.foo'/0[39;49m is
+sub_visibility_c4.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_c4.m:017:   (The module [38;5;87m`sub_visibility_c4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c4.m:017:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_c4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_c4.m:035:   the type `imp_uq'/0:
+sub_visibility_c4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_c4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_c4.m:035:   [38;5;87m`sub_visibility_c4.sub2'.[39;49m)
+`sub_visibility_c4.sub1.int' and `sub_visibility_c4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_c4.err_exp2 b/tests/invalid_submodules/sub_visibility_c4.err_exp2
new file mode 100644
index 0000000000..748c72c05f
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c4.err_exp2
@@ -0,0 +1,19 @@
+sub_visibility_c4.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_c4.m:016:   the type `int_uq'/0:
+sub_visibility_c4.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c4.m:016:   (The module [38;5;87m`sub_visibility_c4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c4.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_c4.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_c4.m:017:   the type `int_fq'/0:
+sub_visibility_c4.m:017:   error: the type [38;5;87m`sub_visibility_c4.sub2.foo'/0[39;49m is
+sub_visibility_c4.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_c4.m:017:   (The module [38;5;87m`sub_visibility_c4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_c4.m:017:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_c4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_c4.m:035:   the type `imp_uq'/0:
+sub_visibility_c4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_c4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_c4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_c4.m:035:   [38;5;87m`sub_visibility_c4.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_c4.sub1.int' and
+  `Mercury/int2s/sub_visibility_c4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_c4.m b/tests/invalid_submodules/sub_visibility_c4.m
new file mode 100644
index 0000000000..b03c74297e
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_c4.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_c4.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_c4.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module sub_visibility_c4.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- use_module sub_visibility_c4.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_c4.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_c4.
diff --git a/tests/invalid_submodules/sub_visibility_d1.err_exp b/tests/invalid_submodules/sub_visibility_d1.err_exp
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/invalid_submodules/sub_visibility_d1.m b/tests/invalid_submodules/sub_visibility_d1.m
new file mode 100644
index 0000000000..afd4be16e2
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d1.m
@@ -0,0 +1,44 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_d1.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- import_module sub_visibility_d1.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % ok
+    :- type int_fq ---> int_fq(sub_visibility_d1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- use_module sub_visibility_d1.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_d1.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_d1.
diff --git a/tests/invalid_submodules/sub_visibility_d2.err_exp b/tests/invalid_submodules/sub_visibility_d2.err_exp
new file mode 100644
index 0000000000..018c3002c1
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d2.err_exp
@@ -0,0 +1,13 @@
+sub_visibility_d2.m:018: In the first argument of function symbol `int_uq' of
+sub_visibility_d2.m:018:   the type `int_uq'/0:
+sub_visibility_d2.m:018:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d2.m:018:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_d2.m:018:   entities defined in module [38;5;87m[39;49m
+sub_visibility_d2.m:018:   [38;5;87m`sub_visibility_d2.sub2'.[39;49m)
+sub_visibility_d2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_d2.m:035:   the type `imp_uq'/0:
+sub_visibility_d2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_d2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_d2.m:035:   [38;5;87m`sub_visibility_d2.sub2'.[39;49m)
+`sub_visibility_d2.sub1.int' and `sub_visibility_d2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_d2.err_exp2 b/tests/invalid_submodules/sub_visibility_d2.err_exp2
new file mode 100644
index 0000000000..604c0dbf7e
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d2.err_exp2
@@ -0,0 +1,14 @@
+sub_visibility_d2.m:018: In the first argument of function symbol `int_uq' of
+sub_visibility_d2.m:018:   the type `int_uq'/0:
+sub_visibility_d2.m:018:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d2.m:018:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_d2.m:018:   entities defined in module [38;5;87m[39;49m
+sub_visibility_d2.m:018:   [38;5;87m`sub_visibility_d2.sub2'.[39;49m)
+sub_visibility_d2.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_d2.m:035:   the type `imp_uq'/0:
+sub_visibility_d2.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d2.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_d2.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_d2.m:035:   [38;5;87m`sub_visibility_d2.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_d2.sub1.int' and
+  `Mercury/int2s/sub_visibility_d2.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_d2.m b/tests/invalid_submodules/sub_visibility_d2.m
new file mode 100644
index 0000000000..5d4756e9af
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d2.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_d2.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- use_module sub_visibility_d2.sub2. % overrides decl in parent
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_d2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- use_module sub_visibility_d2.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_d2.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_d2.
diff --git a/tests/invalid_submodules/sub_visibility_d3.err_exp b/tests/invalid_submodules/sub_visibility_d3.err_exp
new file mode 100644
index 0000000000..2d4e9975b7
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d3.err_exp
@@ -0,0 +1,12 @@
+sub_visibility_d3.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_d3.m:016:   the type `int_uq'/0:
+sub_visibility_d3.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d3.m:016:   (The module [38;5;87m`sub_visibility_d3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d3.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_d3.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_d3.m:017:   the type `int_fq'/0:
+sub_visibility_d3.m:017:   error: the type [38;5;87m`sub_visibility_d3.sub2.foo'/0[39;49m is
+sub_visibility_d3.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_d3.m:017:   (The module [38;5;87m`sub_visibility_d3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d3.m:017:   [38;5;203mimported in the interface.)[39;49m
+`sub_visibility_d3.sub1.int' and `sub_visibility_d3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_d3.err_exp2 b/tests/invalid_submodules/sub_visibility_d3.err_exp2
new file mode 100644
index 0000000000..3b896356c8
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d3.err_exp2
@@ -0,0 +1,13 @@
+sub_visibility_d3.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_d3.m:016:   the type `int_uq'/0:
+sub_visibility_d3.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d3.m:016:   (The module [38;5;87m`sub_visibility_d3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d3.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_d3.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_d3.m:017:   the type `int_fq'/0:
+sub_visibility_d3.m:017:   error: the type [38;5;87m`sub_visibility_d3.sub2.foo'/0[39;49m is
+sub_visibility_d3.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_d3.m:017:   (The module [38;5;87m`sub_visibility_d3.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d3.m:017:   [38;5;203mimported in the interface.)[39;49m
+`Mercury/ints/sub_visibility_d3.sub1.int' and
+  `Mercury/int2s/sub_visibility_d3.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_d3.m b/tests/invalid_submodules/sub_visibility_d3.m
new file mode 100644
index 0000000000..a835529198
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d3.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_d3.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_d3.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- use_module sub_visibility_d3.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- import_module sub_visibility_d3.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % ok
+    :- type imp_fq ---> imp_fq(sub_visibility_d3.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_d3.
diff --git a/tests/invalid_submodules/sub_visibility_d4.err_exp b/tests/invalid_submodules/sub_visibility_d4.err_exp
new file mode 100644
index 0000000000..6f2178472f
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d4.err_exp
@@ -0,0 +1,18 @@
+sub_visibility_d4.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_d4.m:016:   the type `int_uq'/0:
+sub_visibility_d4.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d4.m:016:   (The module [38;5;87m`sub_visibility_d4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d4.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_d4.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_d4.m:017:   the type `int_fq'/0:
+sub_visibility_d4.m:017:   error: the type [38;5;87m`sub_visibility_d4.sub2.foo'/0[39;49m is
+sub_visibility_d4.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_d4.m:017:   (The module [38;5;87m`sub_visibility_d4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d4.m:017:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_d4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_d4.m:035:   the type `imp_uq'/0:
+sub_visibility_d4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_d4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_d4.m:035:   [38;5;87m`sub_visibility_d4.sub2'.[39;49m)
+`sub_visibility_d4.sub1.int' and `sub_visibility_d4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_d4.err_exp2 b/tests/invalid_submodules/sub_visibility_d4.err_exp2
new file mode 100644
index 0000000000..7ec0e45955
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d4.err_exp2
@@ -0,0 +1,19 @@
+sub_visibility_d4.m:016: In the first argument of function symbol `int_uq' of
+sub_visibility_d4.m:016:   the type `int_uq'/0:
+sub_visibility_d4.m:016:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d4.m:016:   (The module [38;5;87m`sub_visibility_d4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d4.m:016:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_d4.m:017: In the first argument of function symbol `int_fq' of
+sub_visibility_d4.m:017:   the type `int_fq'/0:
+sub_visibility_d4.m:017:   error: the type [38;5;87m`sub_visibility_d4.sub2.foo'/0[39;49m is
+sub_visibility_d4.m:017:   [38;5;203mundefined.[39;49m
+sub_visibility_d4.m:017:   (The module [38;5;87m`sub_visibility_d4.sub2'[39;49m [38;5;203mhas not been[39;49m
+sub_visibility_d4.m:017:   [38;5;203mimported in the interface.)[39;49m
+sub_visibility_d4.m:035: In the first argument of function symbol `imp_uq' of
+sub_visibility_d4.m:035:   the type `imp_uq'/0:
+sub_visibility_d4.m:035:   error: the type [38;5;87m`foo'/0[39;49m is [38;5;203mundefined.[39;49m
+sub_visibility_d4.m:035:   (Only [38;5;226mfully module qualified names[39;49m may refer to the
+sub_visibility_d4.m:035:   entities defined in module [38;5;87m[39;49m
+sub_visibility_d4.m:035:   [38;5;87m`sub_visibility_d4.sub2'.[39;49m)
+`Mercury/ints/sub_visibility_d4.sub1.int' and
+  `Mercury/int2s/sub_visibility_d4.sub1.int2' not written.
diff --git a/tests/invalid_submodules/sub_visibility_d4.m b/tests/invalid_submodules/sub_visibility_d4.m
new file mode 100644
index 0000000000..1557cda6e2
--- /dev/null
+++ b/tests/invalid_submodules/sub_visibility_d4.m
@@ -0,0 +1,49 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+%
+% The .err_exp file is for --no-use-subdirs.
+% The .err_exp2 file is for --use-subdirs.
+%
+%---------------------------------------------------------------------------%
+
+:- module sub_visibility_d4.
+:- interface.
+
+    :- module sub1.
+    :- interface.
+
+    :- type int_uq ---> int_uq(foo). % error
+    :- type int_fq ---> int_fq(sub_visibility_d4.sub2.foo). % error
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- use_module sub_visibility_d4.sub2.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub1.
+    :- implementation.
+
+    :- use_module sub_visibility_d4.sub2. % overrides decl in parent
+
+    :- type imp_uq ---> imp_uq(foo). % error
+    :- type imp_fq ---> imp_fq(sub_visibility_d4.sub2.foo). % ok
+
+    :- end_module sub1.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+:- end_module sub_visibility_d4.
diff --git a/tests/invalid_submodules/test_visibility.err_exp b/tests/invalid_submodules/test_visibility.err_exp
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/submodules/Mmakefile b/tests/submodules/Mmakefile
index 0180079e9b..98b4bfbf5f 100644
--- a/tests/submodules/Mmakefile
+++ b/tests/submodules/Mmakefile
@@ -17,6 +17,7 @@ MAYBE_J1 = -j1
 SUB_MODULE_PROGS = \
 	accessibility_t1 \
 	accessibility_t2 \
+	accessibility_t3 \
 	backquoted_qualified_ops \
 	class \
 	daf_bug \
diff --git a/tests/submodules/accessibility_t3.exp b/tests/submodules/accessibility_t3.exp
new file mode 100644
index 0000000000..18832d3511
--- /dev/null
+++ b/tests/submodules/accessibility_t3.exp
@@ -0,0 +1 @@
+Hello.
diff --git a/tests/submodules/accessibility_t3.m b/tests/submodules/accessibility_t3.m
new file mode 100644
index 0000000000..1633b32042
--- /dev/null
+++ b/tests/submodules/accessibility_t3.m
@@ -0,0 +1,68 @@
+%---------------------------------------------------------------------------%
+% vim: ts=4 sw=4 et ft=mercury
+%---------------------------------------------------------------------------%
+
+:- module accessibility_t3.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+    :- module child.
+    :- interface.
+
+    :- type dummy ---> dummy.
+
+        :- module grandchild.
+        :- interface.
+
+        :- type dummy ---> dummy.
+
+        :- end_module grandchild.
+
+    :- end_module child.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module accessibility_t3.sub2.
+
+    :- module child.
+    :- implementation.
+
+    :- use_module accessibility_t3.sub2.
+
+    % The `use_module' in this module means foo must be qualified here.
+    :- pred child_pred(accessibility_t3.sub2.foo::in) is det.
+
+    child_pred(_).
+
+        :- module grandchild.
+        :- implementation.
+
+        % This sees both the `import_module' and `use_module' from ancestors,
+        % so foo can be unqualified here.
+        :- pred grandchild_pred(foo::in) is det.
+
+        grandchild_pred(_).
+
+        :- end_module grandchild.
+
+    :- end_module child.
+
+%---------------------------------------------------------------------------%
+
+    :- module sub2.
+    :- interface.
+
+    :- type foo ---> foo.
+
+    :- end_module sub2.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+    io.write_string("Hello.\n", !IO).
diff --git a/tests/submodules/parent_t2.parent_t2_helper_1.m b/tests/submodules/parent_t2.parent_t2_helper_1.m
index 098d64b9ad..1723f96a64 100644
--- a/tests/submodules/parent_t2.parent_t2_helper_1.m
+++ b/tests/submodules/parent_t2.parent_t2_helper_1.m
@@ -7,7 +7,9 @@
 :- module parent_t2.parent_t2_helper_1.
 :- interface.
 
-% module `io' is imported in parent_t2
+% module `io' is imported in the implementation section of parent_t2
+% but that is no longer enough.
+:- import_module io.
 
 :- type t1 == foo.
 :- type t2 == parent_t2.foo.
diff --git a/tests/valid_seq/nested_module_ambiguity.m b/tests/valid_seq/nested_module_ambiguity.m
index d7cb7fca1f..595f5cec68 100644
--- a/tests/valid_seq/nested_module_ambiguity.m
+++ b/tests/valid_seq/nested_module_ambiguity.m
@@ -30,6 +30,8 @@ main(!IO) :-
 
     :- interface.
 
+    :- import_module list.
+
     :- pred parse_tokens(string::in, list(int)::in, list(int)::out) is det.
 
     :- implementation.
diff --git a/tests/valid_seq/spurious_match.m b/tests/valid_seq/spurious_match.m
index 4b73e8100b..4de9a97e11 100644
--- a/tests/valid_seq/spurious_match.m
+++ b/tests/valid_seq/spurious_match.m
@@ -28,6 +28,8 @@ main(!IO) :-
     :- module spurious_match.spurious_match_helper_1.
     :- interface.
 
+    :- import_module list.
+
     :- pred parse_tokens(string::in, list(int)::in, list(int)::out) is det.
 
     :- implementation.
-- 
2.54.0