%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% 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.
%---------------------------------------------------------------------------%
%
% This module implements the second pass of module_qual.m;
% it module qualifies everything that needs to be module qualified
% in the item blocks given to it. If something cannot be module qualified,
% either because it refers to an undefined entity (type, inst etc) or
% to an entity that has more than one matching definition, it calls
% module_qual.qual_error.m to generate an error message.
%

:- module parse_tree.module_qual.qualify_items.
:- interface.

:- import_module libs.
:- import_module libs.globals.
:- import_module mdbcomp.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.error_spec.
:- import_module parse_tree.module_qual.id_set.
:- import_module parse_tree.module_qual.mq_info.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_data_event.
:- import_module parse_tree.prog_parse_tree.

:- import_module list.
:- import_module map.
:- import_module set_tree234.

%---------------------------------------------------------------------------%

    % module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
    %   EventSpecMap0, EventSpecMap, MaybeContext, EventSpecFileName, MQ_Info,
    %   UnusedImportsSet, UnusedImportsSpecsMap):
    %
    % AugCompUnit is AugCompUnit0 with all items module qualified
    % as much as possible; likewise for EventSpecMap0 and EventSpecMap.
    %
    % Errors in EventSpecMap0 will be reported as being for EventSpecFileName.
    %
:- pred module_qualify_aug_comp_unit(globals::in,
    aug_compilation_unit::in, aug_compilation_unit::out,
    event_spec_map::in, event_spec_map::out, string::in, mq_info::out,
    set_tree234(module_name)::out, map(module_name, warn_spec)::out) is det.

:- pred module_qualify_aug_make_int_unit(globals::in,
    aug_make_int_unit::in, aug_make_int_unit::out,
    list(err_spec)::in, list(err_spec)::out,
    list(warn_spec)::in, list(warn_spec)::out) is det.

    % module_qualify_parse_tree_int3(Globals, OrigParseTreeInt3, ParseTreeInt3,
    %   !Specs):
    %
    % ParseTreeInt3 is OrigParseTreeInt3 with all items in the .int3 file
    % module qualified as much as possible.
    %
:- pred module_qualify_parse_tree_int3(globals::in,
    parse_tree_int3::in, parse_tree_int3::out,
    list(err_spec)::in, list(err_spec)::out) is det.

%---------------------------------------------------------------------------%

    % This is called from qual_info.m to qualify explicit type qualifications.
    %
:- pred qualify_type_qualification(mq_in_interface::in, prog_context::in,
    mer_type::in, mer_type::out, mq_info::in, mq_info::out) is det.

    % This is called from add_clause.m to qualify the modes
    % in mode-specific clauses.
    %
:- pred qualify_clause_mode_list(mq_in_interface::in, prog_context::in,
    list(mer_mode)::in, list(mer_mode)::out, mq_info::in, mq_info::out) is det.

    % This is called from superhomogeneous.m to qualify the modes of arguments
    % in lambda expressions.
    %
:- pred qualify_lambda_mode(mq_in_interface::in, prog_context::in,
    mer_mode::in, mer_mode::out, mq_info::in, mq_info::out) is det.

%---------------------------------------------------------------------------%

:- implementation.

:- import_module libs.options.
:- import_module parse_tree.module_qual.collect_mq_info.
:- import_module parse_tree.module_qual.qual_errors.
:- import_module parse_tree.prog_data_foreign.
:- import_module parse_tree.prog_data_pragma.
:- import_module parse_tree.prog_item.
:- import_module parse_tree.prog_type_test.
:- import_module parse_tree.prog_util.
:- import_module recompilation.
:- import_module recompilation.item_types.
:- import_module recompilation.record_uses.

:- import_module assoc_list.
:- import_module bool.
:- import_module int.
:- import_module maybe.
:- import_module one_or_more.
:- import_module one_or_more_map.
:- import_module pair.
:- import_module require.
:- import_module term_context.

%---------------------------------------------------------------------------%

module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
        EventSpecMap0, EventSpecMap, EventSpecFileName, !:Info,
        UnusedImportsSet, UnusedImportsSpecsMap) :-
    AugCompUnit0 = aug_compilation_unit(ParseTreeModuleSrc0,
        AncestorIntSpecs, DirectInt1Specs, IndirectInt2Specs,
        PlainOptSpecs, TransOptSpecs, IntForOptSpecs, TypeRepnSpecs,
        ModuleVersionNumbers),

    ModuleName = ParseTreeModuleSrc0 ^ ptms_module_name,
    init_mq_info(Globals, ModuleName, should_report_errors, !:Info),
    collect_mq_info_in_parse_tree_module_src(ParseTreeModuleSrc0, !Info),
    list.foldl(collect_mq_info_in_ancestor_int_spec,
        map.values(AncestorIntSpecs), !Info),
    list.foldl(collect_mq_info_in_direct_int1_spec,
        map.values(DirectInt1Specs), !Info),
    qualify_parse_tree_module_src(ParseTreeModuleSrc0, ParseTreeModuleSrc,
        !Info),
    AugCompUnit = aug_compilation_unit(ParseTreeModuleSrc,
        AncestorIntSpecs, DirectInt1Specs, IndirectInt2Specs,
        PlainOptSpecs, TransOptSpecs, IntForOptSpecs, TypeRepnSpecs,
        ModuleVersionNumbers),
    % Note that unlike module_qualify_aug_make_int_unit, we do not call
    % get_diag_specs_in_mq_info here. This is because we want to retrieve
    % 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.

    map.to_assoc_list(EventSpecMap0, EventSpecList0),
    qualify_event_specs(mq_not_used_in_interface, EventSpecFileName,
        EventSpecList0, EventSpecList, !Info),
    map.from_assoc_list(EventSpecList, EventSpecMap),

    globals.lookup_bool_option(Globals, warn_unused_interface_imports,
        WarnUnusedInterfaceImports),
    globals.lookup_bool_option(Globals, warn_unused_imports,
        WarnUnusedImports),
    ( if
        ( WarnUnusedInterfaceImports = yes
        ; WarnUnusedImports = yes
        )
    then
        get_unused_imports_map(!.Info, UnusedImportsContextMap),
        map.keys(UnusedImportsContextMap, UnusedImports),
        set_tree234.sorted_list_to_set(UnusedImports, UnusedImportsSet),
        (
            WarnUnusedImports = yes,
            % The unused imports will be reported later by unused_imports.m.
            % That is why we return UnusedImportsSet to our caller, to be
            % stored in the HLDS until unused_imports.m can look at it.
            map.init(UnusedImportsSpecsMap)
        ;
            WarnUnusedImports = no,
            % We can get here only if WarnUnusedInterfaceImports is yes.
            get_unused_imports_map(!.Info, UnusedImportsContextsMap),
            map.map_values(warn_unused_interface_import(ModuleName),
                UnusedImportsContextsMap, UnusedImportsSpecsMap)
        )
    else
        UnusedImportsSet = set_tree234.init,
        map.init(UnusedImportsSpecsMap)
    ).

%---------------------%

module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
        !ErrSpecs, !WarnSpecs) :-
    AugMakeIntUnit0 = aug_make_int_unit(ParseTreeModuleSrc0, DelayedSpecs0,
        AncestorInt0s, DirectInt3Specs, IndirectInt3Specs,
        ModuleVersionNumbers),

    some [!Info] (
        ModuleName = ParseTreeModuleSrc0 ^ ptms_module_name,
        init_mq_info(Globals, ModuleName, should_report_errors, !:Info),
        collect_mq_info_in_parse_tree_module_src(ParseTreeModuleSrc0, !Info),
        list.foldl(collect_mq_info_in_parse_tree_int0(rwi0_section),
            map.values(AncestorInt0s), !Info),
        list.foldl(collect_mq_info_in_direct_int3_spec,
            map.values(DirectInt3Specs), !Info),
        qualify_parse_tree_module_src(ParseTreeModuleSrc0, ParseTreeModuleSrc,
            !Info),
        AugMakeIntUnit = aug_make_int_unit(ParseTreeModuleSrc, DelayedSpecs0,
            AncestorInt0s, DirectInt3Specs, IndirectInt3Specs,
            ModuleVersionNumbers),
        get_err_specs_in_mq_info(!.Info,
            InvalidTypeSpecs, InvalidInstModeSpecs, NonBlockingUndefSpecs),
        !:ErrSpecs = InvalidTypeSpecs ++ InvalidInstModeSpecs ++
            NonBlockingUndefSpecs ++ !.ErrSpecs,

        globals.lookup_bool_option(Globals, warn_unused_interface_imports,
            WarnInterfaceImports),
        (
            WarnInterfaceImports = no
        ;
            WarnInterfaceImports = yes,
            get_unused_imports_map(!.Info, UnusedImportsContextsMap),
            map.map_values(warn_unused_interface_import(ModuleName),
                UnusedImportsContextsMap, UnusedImportsSpecsMap),
            map.values(UnusedImportsSpecsMap, UnusedImportsSpecs),
            !:WarnSpecs = UnusedImportsSpecs ++ !.WarnSpecs
        )
    ).

%---------------------%

    % Compute the set of unused module imports in the interface,
    % so we can warn about them.
    %
    % There is a special case involving type class instances that
    % we need to handle here. Consider:
    %
    %   :- module foo.
    %   :- interface.
    %
    %   :- import_module bar.
    %   :- typeclass tc1(T) <= tc2(T).
    %   :- instance tc1(unit).
    %
    % where module bar exports the instance tc2(unit). We must import
    % the module bar in the interface of the module foo in order for
    % the superclass constraint on the instance tc1(unit) to be satisfied.
    % However, at this stage of compilation we do not know that the
    % instance tc2(unit) needs to be visible. (Knowing this would require
    % a more extensive analysis of type classes and instances to be done
    % in this module.)
    %
    % In order to prevent the import of the module bar being erroneously
    % reported as unused, we make the conservative assumption that any
    % imported module that exports a type class instance is used in
    % the interface of the importing module, except if the importing
    % module itself exports _no_ type class instances.
    %
:- pred get_unused_imports_map(mq_info::in, module_names_contexts::out) is det.

get_unused_imports_map(Info, UnusedImportsMap) :-
    mq_info_get_as_yet_unused_interface_modules(Info, UnusedImportsMap0),
    mq_info_get_exported_instances_flag(Info, ModuleExportsInstances),
    (
        ModuleExportsInstances = yes,
        mq_info_get_imported_instance_modules(Info, InstanceImports),
        map.delete_list(set_tree234.to_sorted_list(InstanceImports),
            UnusedImportsMap0, UnusedImportsMap)
    ;
        ModuleExportsInstances = no,
        UnusedImportsMap = UnusedImportsMap0
    ).

%---------------------%

module_qualify_parse_tree_int3(Globals, OrigParseTreeInt3, ParseTreeInt3,
        !ErrSpecs) :-
    ModuleName = OrigParseTreeInt3 ^ pti3_module_name,
    init_mq_info(Globals, ModuleName, should_not_report_errors, Info0),
    collect_mq_info_in_parse_tree_int3(int3_as_src, OrigParseTreeInt3,
        Info0, Info1),
    qualify_parse_tree_int3(OrigParseTreeInt3, ParseTreeInt3,
        Info1, Info),
    get_err_specs_in_mq_info(Info,
        InvalidTypeSpecs, InvalidInstModeSpecs, NonBlockingUndefSpecs),
    !:ErrSpecs = InvalidTypeSpecs ++ InvalidInstModeSpecs ++
        NonBlockingUndefSpecs ++ !.ErrSpecs.

%---------------------------------------------------------------------------%

    % Module qualify the given parse tree.
    %
:- pred qualify_parse_tree_module_src(
    parse_tree_module_src::in, parse_tree_module_src::out,
    mq_info::in, mq_info::out) is det.

qualify_parse_tree_module_src(ParseTreeModuleSrc0, ParseTreeModuleSrc,
        !Info) :-
    ParseTreeModuleSrc0 = parse_tree_module_src(ModuleName, ModuleNameContext,
        InclMap, ImportUseMap,
        IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,

        TypeCtorCheckedMap0, InstCtorCheckedMap0, ModeCtorCheckedMap0,
        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,

        IntTypeClasses0, IntInstances0, IntPredDecls0, IntModeDecls0,
        IntDeclPragmas0, IntDeclMarkers0, IntPromises0, IntBadPreds,

        ImpTypeClasses0, ImpInstances0, ImpPredDecls0, ImpModeDecls0,
        ImpClauses0, ImpForeignProcs0, ImpForeignExportEnums0,
        ImpDeclPragmas0, ImpDeclMarkers0, ImpImplPragmas0, ImpImplMarkers0,
        ImpPromises0, ImpInitialises0, ImpFinalises0, ImpMutables0),

    map.map_values_foldl(module_qualify_type_ctor_checked_defn,
        TypeCtorCheckedMap0, TypeCtorCheckedMap, !Info),
    map.map_values_foldl(module_qualify_inst_ctor_checked_defn,
        InstCtorCheckedMap0, InstCtorCheckedMap, !Info),
    map.map_values_foldl(module_qualify_mode_ctor_checked_defn,
        ModeCtorCheckedMap0, ModeCtorCheckedMap, !Info),

    InInt = mq_used_in_interface,
    list.map_foldl(module_qualify_item_typeclass(InInt),
        IntTypeClasses0, IntTypeClasses, !Info),
    list.map_foldl(module_qualify_item_instance(InInt),
        IntInstances0, IntInstances, !Info),
    list.map_foldl(module_qualify_item_pred_decl(InInt),
        IntPredDecls0, IntPredDecls, !Info),
    list.map_foldl(module_qualify_item_mode_decl(InInt),
        IntModeDecls0, IntModeDecls, !Info),
    list.map_foldl(module_qualify_item_decl_pragma(InInt),
        IntDeclPragmas0, IntDeclPragmas, !Info),
    % Promises don't need to be qualified.
    IntPromises = IntPromises0,

    InImp = mq_not_used_in_interface,
    list.map_foldl(module_qualify_item_typeclass(InImp),
        ImpTypeClasses0, ImpTypeClasses, !Info),
    list.map_foldl(module_qualify_item_instance(InImp),
        ImpInstances0, ImpInstances, !Info),
    list.map_foldl(module_qualify_item_pred_decl(InImp),
        ImpPredDecls0, ImpPredDecls, !Info),
    list.map_foldl(module_qualify_item_mode_decl(InImp),
        ImpModeDecls0, ImpModeDecls, !Info),
    % Clauses don't need to be qualified.
    ImpClauses = ImpClauses0,
    list.map_foldl(module_qualify_item_foreign_proc(InImp),
        ImpForeignProcs0, ImpForeignProcs, !Info),
    list.map_foldl(module_qualify_item_foreign_export_enum(InImp),
        ImpForeignExportEnums0, ImpForeignExportEnums, !Info),
    list.map_foldl(module_qualify_item_decl_pragma(InImp),
        ImpDeclPragmas0, ImpDeclPragmas, !Info),
    list.map_foldl(module_qualify_item_impl_pragma(InImp),
        ImpImplPragmas0, ImpImplPragmas, !Info),
    % Initialise and finalise items and promises don't need to be qualified.
    ImpInitialises = ImpInitialises0,
    ImpFinalises = ImpFinalises0,
    ImpPromises = ImpPromises0,
    list.map_foldl(module_qualify_item_mutable(InImp),
        ImpMutables0, ImpMutables, !Info),

    ParseTreeModuleSrc = parse_tree_module_src(ModuleName, ModuleNameContext,
        InclMap, ImportUseMap,
        IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,

        TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,

        IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
        IntDeclPragmas, IntDeclMarkers0, IntPromises, IntBadPreds,

        ImpTypeClasses, ImpInstances, ImpPredDecls, ImpModeDecls,
        ImpClauses, ImpForeignProcs, ImpForeignExportEnums,
        ImpDeclPragmas, ImpDeclMarkers0, ImpImplPragmas, ImpImplMarkers0,
        ImpPromises, ImpInitialises, ImpFinalises, ImpMutables).

%---------------------------------------------------------------------------%

:- pred qualify_parse_tree_int3(parse_tree_int3::in, parse_tree_int3::out,
    mq_info::in, mq_info::out) is det.

qualify_parse_tree_int3(OrigParseTreeInt3, ParseTreeInt3, !Info) :-
    OrigParseTreeInt3 = parse_tree_int3(ModuleName, ModuleNameContext,
        InclMap, ImportUseMap,
        IntTypeDefnMap0, IntInstDefnMap0, IntModeDefnMap0,
        IntTypeClasses0, IntInstances0, IntTypeRepns0),

    InInt = mq_used_in_interface,
    map.map_values_foldl(module_qualify_type_ctor_checked_defn,
        IntTypeDefnMap0, IntTypeDefnMap, !Info),
    map.map_values_foldl(module_qualify_inst_ctor_checked_defn,
        IntInstDefnMap0, IntInstDefnMap, !Info),
    map.map_values_foldl(module_qualify_mode_ctor_checked_defn,
        IntModeDefnMap0, IntModeDefnMap, !Info),
    list.map_foldl(module_qualify_item_abstract_typeclass(InInt),
        IntTypeClasses0, IntTypeClasses, !Info),
    list.map_foldl(module_qualify_item_abstract_instance(InInt),
        IntInstances0, IntInstances, !Info),
    map.map_values_foldl(module_qualify_item_type_repn(ModuleName, InInt),
        IntTypeRepns0, IntTypeRepns, !Info),

    ParseTreeInt3 = parse_tree_int3(ModuleName, ModuleNameContext,
        InclMap, ImportUseMap,
        IntTypeDefnMap, IntInstDefnMap, IntModeDefnMap,
        IntTypeClasses, IntInstances, IntTypeRepns).

%---------------------------------------------------------------------------%
%
% Module qualify the checked type, inst and mode definition maps.
%
% Each entry in each of these checked maps contains
%
% - the actual definition of the type, inst or mode, together with its status,
%   and
%
% - the definition's source items (i.e. the items from which that definition
%   was derived) in the interface and the implementation sections.
%
% When we module qualify those items, we pass mq_not_used_in_interface
% or mq_used_in_interface as appropriate to the section, and we keep
% any error specs the qualification process generates. This is obviously
% the right thing to do.
%
% When we process the actual definitions, we *always* pass
% mq_not_used_in_interface, and we *always* throw away the resulting
% error specs. This is also the right thing to do, but the reason is
% not obvious.
%
% The reason for passing mq_not_used_in_interface when processing the
% definitions themselves is that the definitions are derived from
% *both interface and implementation items*. If we passed mq_used_in_interface,
% then we could record that mq_id was used in the interface just because
% we used it to resolve a reference to a part of a definition that came from
% the implementation section, which would be incorrect. Any mq_ids used by
% parts of the definition that came from the interface section will not be
% recorded as such when we process the definition itself, but it *will* be
% recorded as such when we process the interface source items.
%
% Likewise, any errors we generate while module qualifying the definitions
% but then throw away *will* be generated when we module qualify the
% source items. The difference is that the source items include the context
% we want for each error message, while the definitions themselves do not.
% We could add a context to the definitions, but, given the above, there is
% no point.
%

:- pred module_qualify_type_ctor_checked_defn(
    type_ctor_checked_defn::in, type_ctor_checked_defn::out,
    mq_info::in, mq_info::out) is det.

module_qualify_type_ctor_checked_defn(CheckedDefn0, CheckedDefn, !Info) :-
    (
        CheckedDefn0 = checked_defn_solver(SolverDefn0, SrcDefns0),
        (
            SolverDefn0 = solver_type_abstract(_AbsSolverStatus, _AbsDefn0),
            % Abstract definitions do not need qualification.
            SolverDefn = SolverDefn0
        ;
            SolverDefn0 = solver_type_full(MaybeAbsDefn0, FullDefn0),
            % Non-abstract definitions can occur only in the implementation
            % section.
            InInt = mq_not_used_in_interface,
            module_qualify_item_type_defn(qualify_type_defn_solver,
                InInt, FullDefn0, FullDefn, !Info),
            SolverDefn = solver_type_full(MaybeAbsDefn0, FullDefn)
        ),
        SrcDefns0 = src_defns_solver(MaybeIntDefn0, MaybeImpDefn0),
        QualifyPred = module_qualify_item_type_defn(qualify_type_defn),
        maybe_qualify_defn(QualifyPred, mq_used_in_interface,
            MaybeIntDefn0, MaybeIntDefn, !Info),
        maybe_qualify_defn(QualifyPred, mq_not_used_in_interface,
            MaybeImpDefn0, MaybeImpDefn, !Info),
        SrcDefns = src_defns_solver(MaybeIntDefn, MaybeImpDefn),
        CheckedDefn = checked_defn_solver(SolverDefn, SrcDefns)
    ;
        CheckedDefn0 = checked_defn_std(StdDefn0, SrcDefns0),
        (
            StdDefn0 = std_mer_type_eqv(EqvStatus, EqvDefn0),
            InInt = std_eqv_status_section(EqvStatus),
            module_qualify_item_type_defn(qualify_type_defn_eqv,
                InInt, EqvDefn0, EqvDefn, !Info),
            StdDefn = std_mer_type_eqv(EqvStatus, EqvDefn)
        ;
            StdDefn0 = std_mer_type_subtype(SubStatus, SubDefn0),
            InInt = std_sub_status_section(SubStatus),
            module_qualify_item_type_defn(qualify_type_defn_sub,
                InInt, SubDefn0, SubDefn, !Info),
            StdDefn = std_mer_type_subtype(SubStatus, SubDefn)
        ;
            StdDefn0 = std_mer_type_du_all_plain_constants(DuStatus, DuDefn0,
                HeadCtor, TailCtors, CJCsDefnOrEnum),
            InInt = std_du_status_section(DuStatus),
            module_qualify_item_type_defn(qualify_type_defn_du,
                InInt, DuDefn0, DuDefn, !Info),
            % Foreign types and foreign enums need no qualification.
            StdDefn = std_mer_type_du_all_plain_constants(DuStatus, DuDefn,
                HeadCtor, TailCtors, CJCsDefnOrEnum)
        ;
            StdDefn0 = std_mer_type_du_not_all_plain_constants(DuStatus,
                DuDefn0, CJCsDefnOrEnum),
            InInt = std_du_status_section(DuStatus),
            module_qualify_item_type_defn(qualify_type_defn_du,
                InInt, DuDefn0, DuDefn, !Info),
            % Foreign types and foreign enums need no qualification.
            StdDefn = std_mer_type_du_not_all_plain_constants(DuStatus,
                DuDefn, CJCsDefnOrEnum)
        ;
            StdDefn0 = std_mer_type_abstract(_AbsStatus, _AbsDefn,
                _CJCsDefnOrEnum),
            % Abstract types, foreign types and foreign enums
            % need no qualification.
            StdDefn = StdDefn0
        ),
        SrcDefns0 = src_defns_std(IntDefns0, ImpDefns0, ImpForeignEnums0),
        list.map_foldl(
            module_qualify_item_type_defn(qualify_type_defn,
                mq_used_in_interface),
            IntDefns0, IntDefns, !Info),
        list.map_foldl(
            module_qualify_item_type_defn(qualify_type_defn,
                mq_not_used_in_interface),
            ImpDefns0, ImpDefns, !Info),
        list.map_foldl(
            module_qualify_item_foreign_enum(mq_not_used_in_interface),
            ImpForeignEnums0, ImpForeignEnums, !Info),
        SrcDefns = src_defns_std(IntDefns, ImpDefns, ImpForeignEnums),
        CheckedDefn = checked_defn_std(StdDefn, SrcDefns)
    ).

:- pred module_qualify_inst_ctor_checked_defn(
    inst_ctor_checked_defn::in, inst_ctor_checked_defn::out,
    mq_info::in, mq_info::out) is det.

module_qualify_inst_ctor_checked_defn(CheckedDefn0, CheckedDefn, !Info) :-
    CheckedDefn0 = checked_defn_inst(StdInstDefn0, SrcDefns0),
    StdInstDefn0 = std_inst_defn(Status, MaybeAbstractDefn0),
    % Because of the inst_for_type_constructor field,
    % even abstract inst definitions need qualifying.
    InInt = std_inst_status_section(Status),
    module_qualify_item_inst_defn(qualify_inst_defn, InInt,
        MaybeAbstractDefn0, MaybeAbstractDefn, !Info),
    StdInstDefn = std_inst_defn(Status, MaybeAbstractDefn),
    SrcDefns0 = src_defns_inst(MaybeIntDefn0, MaybeImpDefn0),
    QualifyPred = module_qualify_item_inst_defn(qualify_inst_defn),
    maybe_qualify_defn(QualifyPred, mq_used_in_interface,
        MaybeIntDefn0, MaybeIntDefn, !Info),
    maybe_qualify_defn(QualifyPred, mq_not_used_in_interface,
        MaybeImpDefn0, MaybeImpDefn, !Info),
    SrcDefns = src_defns_inst(MaybeIntDefn, MaybeImpDefn),
    CheckedDefn = checked_defn_inst(StdInstDefn, SrcDefns).

:- pred module_qualify_mode_ctor_checked_defn(
    mode_ctor_checked_defn::in, mode_ctor_checked_defn::out,
    mq_info::in, mq_info::out) is det.

module_qualify_mode_ctor_checked_defn(CheckedDefn0, CheckedDefn, !Info) :-
    CheckedDefn0 = checked_defn_mode(StdModeDefn0, SrcDefns0),
    StdModeDefn0 = std_mode_defn(Status, MaybeAbstractDefn0),
    % Abstract mode definitions don't need qualifying NOW, but will
    % in the future when we add a new mode_for_type_constructor field.
    InInt = std_mode_status_section(Status),
    module_qualify_item_mode_defn(qualify_mode_defn, InInt,
        MaybeAbstractDefn0, MaybeAbstractDefn, !Info),
    StdModeDefn = std_mode_defn(Status, MaybeAbstractDefn),
    SrcDefns0 = src_defns_mode(MaybeIntDefn0, MaybeImpDefn0),
    QualifyPred = module_qualify_item_mode_defn(qualify_mode_defn),
    maybe_qualify_defn(QualifyPred, mq_used_in_interface,
        MaybeIntDefn0, MaybeIntDefn, !Info),
    maybe_qualify_defn(QualifyPred, mq_not_used_in_interface,
        MaybeImpDefn0, MaybeImpDefn, !Info),
    SrcDefns = src_defns_mode(MaybeIntDefn, MaybeImpDefn),
    CheckedDefn = checked_defn_mode(StdModeDefn, SrcDefns).

:- pred maybe_qualify_defn(
    pred(mq_in_interface, T, T, mq_info, mq_info)
    :: in(pred(in, in, out, in, out) is det),
    mq_in_interface::in, maybe(T)::in, maybe(T)::out,
    mq_info::in, mq_info::out) is det.

maybe_qualify_defn(QualifyPred, InInt, MaybeDefn0, MaybeDefn, !Info) :-
    (
        MaybeDefn0 = no,
        MaybeDefn = no
    ;
        MaybeDefn0 = yes(Defn0),
        QualifyPred(InInt, Defn0, Defn, !Info),
        MaybeDefn = yes(Defn)
    ).

%---------------------------------------------------------------------------%

:- func std_eqv_status_section(std_eqv_type_status) = mq_in_interface.

std_eqv_status_section(std_eqv_type_mer_exported) = mq_used_in_interface.
std_eqv_status_section(std_eqv_type_abstract_exported) =
    mq_not_used_in_interface.
std_eqv_status_section(std_eqv_type_all_private) = mq_not_used_in_interface.

:- func std_du_status_section(std_du_type_status) = mq_in_interface.

std_du_status_section(std_du_type_mer_ft_exported) = mq_used_in_interface.
std_du_status_section(std_du_type_mer_exported) = mq_used_in_interface.
std_du_status_section(std_du_type_abstract_exported) =
    mq_not_used_in_interface.
std_du_status_section(std_du_type_all_private) = mq_not_used_in_interface.

:- func std_sub_status_section(std_subtype_status) = mq_in_interface.

std_sub_status_section(std_sub_type_mer_exported) = mq_used_in_interface.
std_sub_status_section(std_sub_type_abstract_exported) =
    mq_not_used_in_interface.
std_sub_status_section(std_sub_type_all_private) = mq_not_used_in_interface.

:- func std_inst_status_section(std_inst_status) = mq_in_interface.

std_inst_status_section(std_inst_exported) = mq_used_in_interface.
std_inst_status_section(std_inst_abstract_exported) = mq_not_used_in_interface.
std_inst_status_section(std_inst_all_private) = mq_not_used_in_interface.

:- func std_mode_status_section(std_mode_status) = mq_in_interface.

std_mode_status_section(std_mode_exported) = mq_used_in_interface.
std_mode_status_section(std_mode_abstract_exported) = mq_not_used_in_interface.
std_mode_status_section(std_mode_all_private) = mq_not_used_in_interface.

%---------------------------------------------------------------------------%

:- pred module_qualify_item_type_defn(
    pred(mq_in_interface, prog_context, type_ctor, T, T, mq_info, mq_info)
    :: in(pred(in, in, in, in, out, in, out) is det),
    mq_in_interface::in,
    item_type_defn_info_general(T)::in, item_type_defn_info_general(T)::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_type_defn(QualDefn, InInt, ItemTypeDefn0, ItemTypeDefn,
        !Info) :-
    ItemTypeDefn0 = item_type_defn_info(SymName, Params, TypeDefn0,
        TVarSet, Context, SeqNum),
    list.length(Params, Arity),
    TypeCtor = type_ctor(SymName, Arity),
    QualDefn(InInt, Context, TypeCtor, TypeDefn0, TypeDefn, !Info),
    ItemTypeDefn = item_type_defn_info(SymName, Params, TypeDefn,
        TVarSet, Context, SeqNum).

:- pred module_qualify_item_inst_defn(
    pred(mq_in_interface, prog_context, inst_ctor, T, T, mq_info, mq_info)
    :: in(pred(in, in, in, in, out, in, out) is det),
    mq_in_interface::in,
    item_inst_defn_info_general(T)::in, item_inst_defn_info_general(T)::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_inst_defn(QualDefn, InInt, ItemInstDefn0, ItemInstDefn,
        !Info) :-
    ItemInstDefn0 = item_inst_defn_info(SymName, Params, MaybeForTypeCtor0,
        MaybeAbstractInstDefn0, InstVarSet, Context, SeqNum),
    list.length(Params, Arity),
    InstCtor = inst_ctor(SymName, Arity),
    ErrorContext = mqec_inst_defn(Context, InstCtor),
    QualDefn(InInt, Context, InstCtor,
        MaybeAbstractInstDefn0, MaybeAbstractInstDefn, !Info),
    (
        MaybeForTypeCtor0 = yes(ForTypeCtor0),
        qualify_type_ctor(InInt, ErrorContext, ForTypeCtor0, ForTypeCtor,
            !Info),
        MaybeForTypeCtor = yes(ForTypeCtor)
    ;
        MaybeForTypeCtor0 = no,
        MaybeForTypeCtor = no
    ),
    ItemInstDefn = item_inst_defn_info(SymName, Params, MaybeForTypeCtor,
        MaybeAbstractInstDefn, InstVarSet, Context, SeqNum).

:- pred module_qualify_item_mode_defn(
    pred(mq_in_interface, prog_context, mode_ctor, T, T, mq_info, mq_info)
    :: in(pred(in, in, in, in, out, in, out) is det),
    mq_in_interface::in,
    item_mode_defn_info_general(T)::in, item_mode_defn_info_general(T)::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_mode_defn(QualDefn, InInt, ItemModeDefn0, ItemModeDefn,
        !Info) :-
    ItemModeDefn0 = item_mode_defn_info(SymName, Params,
        MaybeAbstractModeDefn0, InstVarSet, Context, SeqNum),
    list.length(Params, Arity),
    ModeCtor = mode_ctor(SymName, Arity),
    QualDefn(InInt, Context, ModeCtor,
        MaybeAbstractModeDefn0, MaybeAbstractModeDefn, !Info),
    ItemModeDefn = item_mode_defn_info(SymName, Params,
        MaybeAbstractModeDefn, InstVarSet, Context, SeqNum).

:- pred module_qualify_item_typeclass(mq_in_interface::in,
    item_typeclass_info::in, item_typeclass_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_typeclass(InInt, ItemTypeClass0, ItemTypeClass, !Info) :-
    % The definition of this predicate differs from the definition
    % of module_qualify_item_abstract_typeclass only in that it updates
    % Interface.
    ItemTypeClass0 = item_typeclass_info(Name, Vars, Constraints0, FunDeps,
        Interface0, VarSet, Context, SeqNum),
    list.length(Vars, Arity),
    ClassId = class_id(Name, Arity),
    ConstraintErrorContext = mqcec_class_defn(Context, ClassId),
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info),
    (
        Interface0 = class_interface_abstract,
        Interface = class_interface_abstract
    ;
        Interface0 = class_interface_concrete(Methods0),
        qualify_class_decls(InInt, ClassId, Methods0, Methods,
            !Info),
        Interface = class_interface_concrete(Methods)
    ),
    ItemTypeClass = item_typeclass_info(Name, Vars, Constraints, FunDeps,
        Interface, VarSet, Context, SeqNum).

:- pred module_qualify_item_abstract_typeclass(mq_in_interface::in,
    item_abstract_typeclass_info::in, item_abstract_typeclass_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_abstract_typeclass(InInt, ItemTypeClass0, ItemTypeClass,
        !Info) :-
    % The definition of this predicate differs from the definition
    % of module_qualify_item_typeclass only in that it does not update
    % Interface.
    ItemTypeClass0 = item_typeclass_info(Name, Vars, Constraints0, FunDeps,
        Interface0, VarSet, Context, SeqNum),
    list.length(Vars, Arity),
    ClassId = class_id(Name, Arity),
    ConstraintErrorContext = mqcec_class_defn(Context, ClassId),
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info),
    ItemTypeClass = item_typeclass_info(Name, Vars, Constraints, FunDeps,
        Interface0, VarSet, Context, SeqNum).

:- pred module_qualify_item_instance(mq_in_interface::in,
    item_instance_info::in, item_instance_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_instance(InInt, ItemInstance0, ItemInstance, !Info) :-
    % The definition of this predicate differs from the definition
    % of module_qualify_item_abstract_instance only in that it updates Body.
    ItemInstance0 = item_instance_info(Name0, Types0, OrigTypes0,
        Constraints0, Body0, VarSet, ModName, Context, SeqNum),
    list.length(Types0, Arity),
    ErrorContext = mqec_instance(Context, class_id(Name0, Arity)),
    (
        InInt = mq_used_in_interface,
        mq_info_set_exported_instances_flag(yes, !Info)
    ;
        InInt = mq_not_used_in_interface
    ),
    % We don't qualify the implementation yet, since that requires
    % us to resolve overloading.
    ConstraintErrorContext = mqcec_instance_defn(Context, Name0, OrigTypes0),
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info),
    Id0 = mq_id(Name0, Arity),
    qualify_class_name(InInt, ErrorContext, Id0, Name, !Info),
    % XXX We don't want to keep the errors from the expansion of both
    % forms of the instance types, since printing two error messages about
    % one instance definition that make apparently contradictory
    % assumptions about whether the instance types are equiv-type-expanded
    % or not would be confusing. However, I (zs) cannot think of any
    % compelling reason right now for preferring the error messages
    % from one version of the types over the other.
    qualify_type_list(InInt, ErrorContext, Types0, Types, !Info),
    % WAS_IGNORED We used to ignore diag_specs from OrigTypes.
    qualify_type_list(InInt, ErrorContext, OrigTypes0, OrigTypes, !Info),
    qualify_instance_body(Name, Body0, Body),
    ItemInstance = item_instance_info(Name, Types, OrigTypes,
        Constraints, Body, VarSet, ModName, Context, SeqNum).

:- pred module_qualify_item_abstract_instance(mq_in_interface::in,
    item_abstract_instance_info::in, item_abstract_instance_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_abstract_instance(InInt, ItemInstance0, ItemInstance,
        !Info) :-
    % The definition of this predicate differs from the definition
    % of module_qualify_item_instance only in that it does not update Body.
    ItemInstance0 = item_instance_info(Name0, Types0, OrigTypes0,
        Constraints0, Body, VarSet, ModName, Context, SeqNum),
    list.length(Types0, Arity),
    ErrorContext = mqec_instance(Context, class_id(Name0, Arity)),
    (
        InInt = mq_used_in_interface,
        mq_info_set_exported_instances_flag(yes, !Info)
    ;
        InInt = mq_not_used_in_interface
    ),
    % We don't qualify the implementation yet, since that requires
    % us to resolve overloading.
    ConstraintErrorContext = mqcec_instance_defn(Context, Name0, OrigTypes0),
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info),
    Id0 = mq_id(Name0, Arity),
    qualify_class_name(InInt, ErrorContext, Id0, Name, !Info),
    % XXX We don't want to keep the errors from the expansion of both
    % forms of the instance types, since printing two error messages about
    % one instance definition that make apparently contradictory
    % assumptions about whether the instance types are equiv-type-expanded
    % or not would be confusing. However, I (zs) cannot think of any
    % compelling reason right now for preferring the error messages
    % from one version of the types over the other.
    qualify_type_list(InInt, ErrorContext, Types0, Types, !Info),
    % WAS_IGNORED We used to ignore diag_specs from OrigTypes.
    qualify_type_list(InInt, ErrorContext, OrigTypes0, OrigTypes, !Info),
    ItemInstance = item_instance_info(Name, Types, OrigTypes,
        Constraints, Body, VarSet, ModName, Context, SeqNum).

:- pred module_qualify_item_pred_decl(mq_in_interface::in,
    item_pred_decl_info::in, item_pred_decl_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_pred_decl(InInt, ItemPredDecl0, ItemPredDecl, !Info) :-
    ItemPredDecl0 = item_pred_decl_info(SymName, PredOrFunc,
        TypesAndMaybeModes0, MaybeWithType0, MaybeWithInst0, MaybeDetism,
        Origin, TypeVarSet, InstVarSet, ExistQVars, Purity,
        Constraints0, Context, SeqNum),
    PredFormArity = types_and_maybe_modes_arity(TypesAndMaybeModes0),
    PFSymNameArity = pf_sym_name_arity(PredOrFunc, SymName, PredFormArity),
    PredFormArity = pred_form_arity(PredFormArityInt),
    ErrorContext = mqec_pred_or_func(Context, PredOrFunc,
        mq_id(SymName, PredFormArityInt)),
    qualify_types_and_maybe_modes(InInt, ErrorContext,
        TypesAndMaybeModes0, TypesAndMaybeModes, !Info),
    ConstraintErrorContext = mqcec_pred_decl(Context, PFSymNameArity),
    qualify_prog_constraints(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info),
    (
        MaybeWithType0 = yes(WithType0),
        % XXX We could pass a more specific error context.
        qualify_type(InInt, ErrorContext, WithType0, WithType,
            !Info),
        MaybeWithType = yes(WithType)
    ;
        MaybeWithType0 = no,
        MaybeWithType = no
    ),
    (
        MaybeWithInst0 = yes(WithInst0),
        % XXX We could pass a more specific error context.
        qualify_inst(InInt, ErrorContext, WithInst0, WithInst, !Info),
        MaybeWithInst = yes(WithInst)
    ;
        MaybeWithInst0 = no,
        MaybeWithInst = no
    ),
    ItemPredDecl = item_pred_decl_info(SymName, PredOrFunc,
        TypesAndMaybeModes, MaybeWithType, MaybeWithInst, MaybeDetism,
        Origin, TypeVarSet, InstVarSet, ExistQVars, Purity,
        Constraints, Context, SeqNum).

:- pred module_qualify_item_mode_decl(mq_in_interface::in,
    item_mode_decl_info::in, item_mode_decl_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_mode_decl(InInt, ItemModeDecl0, ItemModeDecl, !Info) :-
    ItemModeDecl0 = item_mode_decl_info(SymName, PredOrFunc, Modes0,
        MaybeWithInst0, MaybeDetism, InstVarSet, Context, SeqNum),
    list.length(Modes0, Arity),
    ErrorContext = mqec_pred_or_func_mode(Context, PredOrFunc,
        mq_id(SymName, Arity)),
    qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
    (
        MaybeWithInst0 = yes(WithInst0),
        % XXX We could pass a more specific error context.
        qualify_inst(InInt, ErrorContext, WithInst0, WithInst, !Info),
        MaybeWithInst = yes(WithInst)
    ;
        MaybeWithInst0 = no,
        MaybeWithInst = no
    ),
    ItemModeDecl = item_mode_decl_info(SymName, PredOrFunc, Modes,
        MaybeWithInst, MaybeDetism, InstVarSet, Context, SeqNum).

:- pred module_qualify_item_foreign_proc(mq_in_interface::in,
    item_foreign_proc_info::in, item_foreign_proc_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_foreign_proc(InInt, FPInfo0, FPInfo, !Info) :-
    FPInfo0 = item_foreign_proc_info(Attrs0, Name, PredOrFunc,
        Vars0, Varset, InstVarset, Impl, Context, SeqNum),
    ErrorContext = mqec_foreign_proc(Context),
    qualify_pragma_vars(InInt, ErrorContext, Vars0, Vars, !Info),
    UserSharing0 = get_user_annotated_sharing(Attrs0),
    qualify_user_sharing(InInt, ErrorContext, UserSharing0, UserSharing,
        !Info),
    set_user_annotated_sharing(UserSharing, Attrs0, Attrs),
    FPInfo = item_foreign_proc_info(Attrs, Name, PredOrFunc,
        Vars, Varset, InstVarset, Impl, Context, SeqNum).

:- pred module_qualify_item_foreign_enum(mq_in_interface::in,
    item_foreign_enum_info::in, item_foreign_enum_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_foreign_enum(InInt, ItemForeignEnum0, ItemForeignEnum,
        !Info) :-
    ItemForeignEnum0 = item_foreign_enum_info(Lang, TypeCtor0, Values,
        Context, SeqNum),
    ErrorContext = mqec_foreign_enum(Context),
    qualify_type_ctor(InInt, ErrorContext, TypeCtor0, TypeCtor, !Info),
    ItemForeignEnum = item_foreign_enum_info(Lang, TypeCtor, Values,
        Context, SeqNum).

:- pred module_qualify_item_foreign_export_enum(mq_in_interface::in,
    item_foreign_export_enum_info::in, item_foreign_export_enum_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_foreign_export_enum(InInt, ItemFEE0, ItemFEE, !Info) :-
    ItemFEE0 = item_foreign_export_enum_info(Lang, TypeCtor0, Attributes,
        Overrides, Context, SeqNum),
    ErrorContext = mqec_foreign_export_enum(Context),
    mq_info_get_is_undef_blocking(!.Info, OldUndefBlocking),
    mq_info_set_is_undef_blocking(undef_is_not_blocking, !Info),
    qualify_type_ctor(InInt, ErrorContext, TypeCtor0, TypeCtor, !Info),
    mq_info_set_is_undef_blocking(OldUndefBlocking, !Info),
    ItemFEE = item_foreign_export_enum_info(Lang, TypeCtor, Attributes,
        Overrides, Context, SeqNum).

% Generated pragmas are always generated fully qualified.

:- pred module_qualify_item_type_repn(module_name::in, mq_in_interface::in,
    item_type_repn_info::in, item_type_repn_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_type_repn(ModuleName, InInt,
        ItemTypeRepnInfo0, ItemTypeRepnInfo, !Info) :-
    ItemTypeRepnInfo0 = item_type_repn_info(TypeCtorSymName0, ArgTVars,
        RepInfo0, TVarSet, Context, SeqNum),
    % We currently put type constructors names into type_repn items
    % in unqualified form because (a) the module name is implicit in the
    % identity of the module whose interface file the type_repn item
    % appears in, and therefore *can* be omitted; and (b) actually omitting
    % the module qualification makes the interface file smaller. However,
    % since we previously module qualified type constructors names, we accept
    % that form as well.
    ( TypeCtorSymName0 = qualified(_, TypeCtorName)
    ; TypeCtorSymName0 = unqualified(TypeCtorName)
    ),
    TypeCtorSymName = qualified(ModuleName, TypeCtorName),
    (
        ( RepInfo0 = tcrepn_is_word_aligned_ptr
        ; RepInfo0 = tcrepn_du(_)
        ; RepInfo0 = tcrepn_foreign(_)
        ),
        RepInfo = RepInfo0
    ;
        RepInfo0 = tcrepn_is_eqv_to(EqvType0),
        list.length(ArgTVars, TypeCtorArity),
        TypeCtor = type_ctor(TypeCtorSymName, TypeCtorArity),
        ErrorContext = mqec_type_repn(Context, TypeCtor),
        qualify_type(InInt, ErrorContext, EqvType0, EqvType, !Info),
        RepInfo = tcrepn_is_eqv_to(EqvType)
    ;
        RepInfo0 = tcrepn_is_subtype_of(SuperTypeCtor0),
        list.length(ArgTVars, TypeCtorArity),
        TypeCtor = type_ctor(TypeCtorSymName, TypeCtorArity),
        ErrorContext = mqec_type_repn(Context, TypeCtor),
        qualify_type_ctor(InInt, ErrorContext, SuperTypeCtor0, SuperTypeCtor,
            !Info),
        RepInfo = tcrepn_is_subtype_of(SuperTypeCtor)
    ),
    ItemTypeRepnInfo = item_type_repn_info(TypeCtorSymName, ArgTVars,
        RepInfo, TVarSet, Context, SeqNum).

%---------------------------------------------------------------------------%
%
% Module qualify type definitions and types.
%

    % Qualify the data constructors and/or arguments' types
    % in a type definition.
    %
:- pred qualify_type_defn(mq_in_interface::in, prog_context::in,
    type_ctor::in, type_defn::in, type_defn::out,
    mq_info::in, mq_info::out) is det.

qualify_type_defn(InInt, Context, TypeCtor, TypeDefn0, TypeDefn, !Info) :-
    (
        TypeDefn0 = parse_tree_solver_type(DetailsSolver0),
        qualify_type_defn_solver(InInt, Context, TypeCtor,
            DetailsSolver0, DetailsSolver, !Info),
        TypeDefn = parse_tree_solver_type(DetailsSolver)
    ;
        TypeDefn0 = parse_tree_eqv_type(DetailsEqv0),
        qualify_type_defn_eqv(InInt, Context, TypeCtor,
            DetailsEqv0, DetailsEqv, !Info),
        TypeDefn = parse_tree_eqv_type(DetailsEqv)
    ;
        TypeDefn0 = parse_tree_du_type(DetailsDu0),
        qualify_type_defn_du(InInt, Context, TypeCtor,
            DetailsDu0, DetailsDu, !Info),
        TypeDefn = parse_tree_du_type(DetailsDu)
    ;
        TypeDefn0 = parse_tree_sub_type(DetailsSub0),
        qualify_type_defn_sub(InInt, Context, TypeCtor,
            DetailsSub0, DetailsSub, !Info),
        TypeDefn = parse_tree_sub_type(DetailsSub)
    ;
        ( TypeDefn0 = parse_tree_abstract_type(_)
        ; TypeDefn0 = parse_tree_foreign_type(_)
        ),
        TypeDefn = TypeDefn0
    ).

:- pred qualify_type_defn_solver(mq_in_interface::in, prog_context::in,
    type_ctor::in, type_details_solver::in, type_details_solver::out,
    mq_info::in, mq_info::out) is det.

qualify_type_defn_solver(InInt, Context, TypeCtor,
        DetailsSolver0, DetailsSolver, !Info) :-
    DetailsSolver0 = type_details_solver(SolverTypeDetails0, MaybeUserEqComp),
    SolverTypeDetails0 = solver_type_details(RepnType0, GroundInst0, AnyInst0,
        Mutables0),
    ErrorContext = mqec_type_defn(Context, TypeCtor),
    qualify_type(InInt, ErrorContext, RepnType0, RepnType, !Info),
    qualify_inst(InInt, ErrorContext, GroundInst0, GroundInst, !Info),
    qualify_inst(InInt, ErrorContext, AnyInst0, AnyInst, !Info),
    qualify_constraint_stores(InInt, Mutables0, Mutables, !Info),
    SolverTypeDetails  = solver_type_details(RepnType, GroundInst, AnyInst,
        Mutables),
    DetailsSolver = type_details_solver(SolverTypeDetails, MaybeUserEqComp).

:- pred qualify_constraint_stores(mq_in_interface::in,
    list(item_mutable_info)::in, list(item_mutable_info)::out,
    mq_info::in, mq_info::out) is det.

qualify_constraint_stores(_InInt, [], [], !Info).
qualify_constraint_stores(InInt,
        [Mutable0 | Mutables0], [Mutable | Mutables], !Info) :-
    module_qualify_item_mutable(InInt, Mutable0, Mutable, !Info),
    qualify_constraint_stores(InInt, Mutables0, Mutables, !Info).

:- pred qualify_type_defn_eqv(mq_in_interface::in, prog_context::in,
    type_ctor::in, type_details_eqv::in, type_details_eqv::out,
    mq_info::in, mq_info::out) is det.

qualify_type_defn_eqv(InInt, Context, TypeCtor, DetailsEqv0, DetailsEqv,
        !Info) :-
    DetailsEqv0 = type_details_eqv(Type0),
    ErrorContext = mqec_type_defn(Context, TypeCtor),
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    DetailsEqv = type_details_eqv(Type).

:- pred qualify_type_defn_du(mq_in_interface::in, prog_context::in,
    type_ctor::in, type_details_du::in, type_details_du::out,
    mq_info::in, mq_info::out) is det.

qualify_type_defn_du(InInt, _Context, TypeCtor, DetailsDu0, DetailsDu,
        !Info) :-
    DetailsDu0 = type_details_du(OoMCtors0, MaybeUserEqComp0,
        MaybeDirectArgCtors0),
    OoMCtors0 = one_or_more(HeadCtor0, TailCtors0),
    qualify_constructor(InInt, TypeCtor, HeadCtor0, HeadCtor, !Info),
    qualify_constructors(InInt, TypeCtor, TailCtors0, TailCtors, !Info),
    OoMCtors = one_or_more(HeadCtor, TailCtors),
    % User-defined equality pred names will be converted into predicate
    % calls and then module-qualified after type analysis (during mode
    % analysis). That way, they get full type overloading resolution, etc.
    % Thus we don't module-qualify them here.
    MaybeUserEqComp = MaybeUserEqComp0,
    MaybeDirectArgCtors = MaybeDirectArgCtors0,
    DetailsDu = type_details_du(OoMCtors, MaybeUserEqComp,
        MaybeDirectArgCtors).

:- pred qualify_type_defn_sub(mq_in_interface::in, prog_context::in,
    type_ctor::in, type_details_sub::in, type_details_sub::out,
    mq_info::in, mq_info::out) is det.

qualify_type_defn_sub(InInt, Context, TypeCtor, DetailsSub0, DetailsSub,
        !Info) :-
    DetailsSub0 = type_details_sub(SuperType0, OoMCtors0),
    ErrorContext = mqec_type_defn(Context, TypeCtor),
    % Note that this will not prevent a subtype defined in an interface
    % section from referring to an abstract type as its supertype.
    % That will be checked while checking other subtype conditions.
    qualify_type(InInt, ErrorContext, SuperType0, SuperType,
        !Info),
    OoMCtors0 = one_or_more(HeadCtor0, TailCtors0),
    qualify_constructor(InInt, TypeCtor, HeadCtor0, HeadCtor, !Info),
    qualify_constructors(InInt, TypeCtor, TailCtors0, TailCtors, !Info),
    OoMCtors = one_or_more(HeadCtor, TailCtors),
    DetailsSub = type_details_sub(SuperType, OoMCtors).

:- pred qualify_constructors(mq_in_interface::in, type_ctor::in,
    list(constructor)::in, list(constructor)::out,
    mq_info::in, mq_info::out) is det.

qualify_constructors(_InInt, _ContainingTypeCtor, [], [], !Info).
qualify_constructors(InInt, ContainingTypeCtor,
        [Ctor0 | Ctors0], [Ctor | Ctors], !Info) :-
    qualify_constructor(InInt, ContainingTypeCtor, Ctor0, Ctor, !Info),
    qualify_constructors(InInt, ContainingTypeCtor, Ctors0, Ctors, !Info).

:- pred qualify_constructor(mq_in_interface::in, type_ctor::in,
    constructor::in, constructor::out,
    mq_info::in, mq_info::out) is det.

qualify_constructor(InInt, ContainingTypeCtor, Ctor0, Ctor, !Info) :-
    Ctor0 = ctor(Ordinal, MaybeExistConstraints0, FunctionSymbolSymName, Args0,
        Arity, Context),
    FunctionSymbolName = unqualify_name(FunctionSymbolSymName),
    (
        MaybeExistConstraints0 = no_exist_constraints,
        MaybeExistConstraints = no_exist_constraints
    ;
        MaybeExistConstraints0 = exist_constraints(ExistConstraints0),
        ExistConstraints0 = cons_exist_constraints(ExistQVars, Constraints0,
            UnconstrainedExistQVars, ConstrainedExistQVars),
        ConstraintErrorContext = mqcec_type_defn_constructor(Context,
            ContainingTypeCtor, FunctionSymbolName, Arity),
        qualify_prog_constraint_list(InInt, ConstraintErrorContext,
            Constraints0, Constraints, !Info),
        ExistConstraints = cons_exist_constraints(ExistQVars, Constraints,
            UnconstrainedExistQVars, ConstrainedExistQVars),
        MaybeExistConstraints = exist_constraints(ExistConstraints)
    ),
    qualify_constructor_args(InInt, ContainingTypeCtor, FunctionSymbolName,
        0, Args0, Args, !Info),
    Ctor = ctor(Ordinal, MaybeExistConstraints, FunctionSymbolSymName, Args,
        Arity, Context).

:- pred qualify_constructor_args(mq_in_interface::in,
    type_ctor::in, string::in, int::in,
    list(constructor_arg)::in, list(constructor_arg)::out,
    mq_info::in, mq_info::out) is det.

qualify_constructor_args(_InInt, _, _, _, [], [], !Info).
qualify_constructor_args(InInt, ContainingTypeCtor, FunctionSymbol,
        LastArgNum, [Arg0 | Args0], [Arg | Args], !Info) :-
    CurArgNum = LastArgNum + 1,
    qualify_constructor_arg(InInt, ContainingTypeCtor, FunctionSymbol,
        CurArgNum, Arg0, Arg, !Info),
    qualify_constructor_args(InInt, ContainingTypeCtor, FunctionSymbol,
        CurArgNum, Args0, Args, !Info).

:- pred qualify_constructor_arg(mq_in_interface::in,
    type_ctor::in, string::in, int::in,
    constructor_arg::in, constructor_arg::out,
    mq_info::in, mq_info::out) is det.

qualify_constructor_arg(InInt, ContainingTypeCtor, FunctionSymbol, ArgNum,
        Arg0, Arg, !Info) :-
    Arg0 = ctor_arg(MaybeFieldName, Type0, Context),
    ErrorContext = mqec_constructor_arg(Context, ContainingTypeCtor,
        FunctionSymbol, ArgNum, MaybeFieldName),
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    Arg = ctor_arg(MaybeFieldName, Type, Context).

:- pred qualify_type_list(mq_in_interface::in, mq_error_context::in,
    list(mer_type)::in, list(mer_type)::out, mq_info::in, mq_info::out) is det.

qualify_type_list(_InInt, _ErrorContext, [], [], !Info).
qualify_type_list(InInt, ErrorContext, [Type0 | Types0], [Type | Types],
        !Info) :-
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    qualify_type_list(InInt, ErrorContext, Types0, Types, !Info).

qualify_type_qualification(InInt, Context, Type0, Type, !Info) :-
    ErrorContext = mqec_type_qual(Context),
    qualify_type(InInt, ErrorContext, Type0, Type, !Info).

    % Qualify a type and its argument types.
    %
:- pred qualify_type(mq_in_interface::in, mq_error_context::in,
    mer_type::in, mer_type::out, mq_info::in, mq_info::out) is det.

qualify_type(InInt, ErrorContext, Type0, Type, !Info) :-
    (
        Type0 = type_variable(_Var, _Kind),
        Type = Type0
    ;
        Type0 = defined_type(SymName0, Args0, Kind),
        Arity = list.length(Args0),
        TypeCtorId0 = mq_id(SymName0, Arity),
        mq_info_get_types(!.Info, Types),
        find_unique_match(InInt, ErrorContext, Types, qual_id_type,
            TypeCtorId0, SymName, !Info),
        % XXX We could pass a more specific error context.
        qualify_type_list(InInt, ErrorContext, Args0, Args, !Info),
        Type = defined_type(SymName, Args, Kind)
    ;
        Type0 = builtin_type(BuiltinType),
        % The types `int', `float', and `string' are builtin types,
        % defined by the compiler, but arguably they ought to be defined
        % in int.m, float.m, and string.m, and so if someone uses the type
        % `int' in the interface, then we don't want to warn about
        % `import_module int' in the interface. We don't do the same for
        % `character', since the corresponding library module `char'
        % will be flagged as used in the interface if the type `char' is used.
        (
            BuiltinType = builtin_type_int(IntType),
            int_type_module_name(IntType, IntModule),
            mq_info_set_module_used(InInt, unqualified(IntModule), !Info)
        ;
            BuiltinType = builtin_type_float,
            mq_info_set_module_used(InInt, unqualified("float"), !Info)
        ;
            BuiltinType = builtin_type_string,
            mq_info_set_module_used(InInt, unqualified("string"), !Info)
        ;
            BuiltinType = builtin_type_char
        ),
        Type = Type0
    ;
        Type0 = higher_order_type(PorF, Args0, HOInstInfo0, Purity),
        % XXX We could pass a more specific error context.
        qualify_type_list(InInt, ErrorContext, Args0, Args, !Info),
        % XXX We could pass a more specific error context.
        qualify_ho_inst_info(InInt, ErrorContext, HOInstInfo0, HOInstInfo,
            !Info),
        Type = higher_order_type(PorF, Args, HOInstInfo, Purity)
    ;
        Type0 = tuple_type(Args0, Kind),
        % XXX We could pass a more specific error context.
        qualify_type_list(InInt, ErrorContext, Args0, Args, !Info),
        Type = tuple_type(Args, Kind)
    ;
        Type0 = apply_n_type(Var, Args0, Kind),
        % XXX We could pass a more specific error context.
        qualify_type_list(InInt, ErrorContext, Args0, Args, !Info),
        Type = apply_n_type(Var, Args, Kind)
    ;
        Type0 = kinded_type(SubType0, Kind),
        % XXX We could pass a more specific error context.
        qualify_type(InInt, ErrorContext, SubType0, SubType, !Info),
        Type = kinded_type(SubType, Kind)
    ).

:- pred qualify_type_ctor(mq_in_interface::in, mq_error_context::in,
    type_ctor::in, type_ctor::out, mq_info::in, mq_info::out) is det.

qualify_type_ctor(InInt, ErrorContext, TypeCtor0, TypeCtor, !Info) :-
    TypeCtor0 = type_ctor(SymName0, Arity),
    ( if is_builtin_atomic_type(TypeCtor0) then
        TypeCtor = TypeCtor0
    else
        TypeCtorId0 = mq_id(SymName0, Arity),
        mq_info_get_types(!.Info, Types),
        % XXX We could pass a more specific error context.
        find_unique_match(InInt, ErrorContext, Types, qual_id_type,
            TypeCtorId0, SymName, !Info),
        TypeCtor = type_ctor(SymName, Arity)
    ).

    % is_builtin_atomic_type(TypeCtor):
    %
    % Succeeds iff 'TypeCtor' is the type_ctor of a builtin atomic type.
    %
:- pred is_builtin_atomic_type(type_ctor::in) is semidet.

is_builtin_atomic_type(TypeCtor) :-
    TypeCtor = type_ctor(SymName, 0),
    is_builtin_type_sym_name(SymName).

%---------------------------------------------------------------------------%
%
% Module qualify inst definitions and insts.
%

    % Qualify the right hand side of an inst definition.
    %
:- pred qualify_inst_defn(mq_in_interface::in, prog_context::in,
    inst_ctor::in, maybe_abstract_inst_defn::in, maybe_abstract_inst_defn::out,
    mq_info::in, mq_info::out) is det.

qualify_inst_defn(InInt, Context, InstCtor,
        MaybeAbstractInstDefn0, MaybeAbstractInstDefn, !Info) :-
    (
        MaybeAbstractInstDefn0 = abstract_inst_defn,
        MaybeAbstractInstDefn = abstract_inst_defn
    ;
        MaybeAbstractInstDefn0 = nonabstract_inst_defn(InstDefn0),
        ErrorContext = mqec_inst_defn(Context, InstCtor),
        InstDefn0 = eqv_inst(Inst0),
        qualify_inst(InInt, ErrorContext, Inst0, Inst, !Info),
        InstDefn = eqv_inst(Inst),
        MaybeAbstractInstDefn = nonabstract_inst_defn(InstDefn)
    ).

    % Qualify a single inst.
    %
:- pred qualify_inst(mq_in_interface::in, mq_error_context::in,
    mer_inst::in, mer_inst::out, mq_info::in, mq_info::out) is det.

qualify_inst(InInt, ErrorContext, Inst0, Inst, !Info) :-
    (
        Inst0 = any(Uniq, HOInstInfo0),
        qualify_ho_inst_info(InInt, ErrorContext, HOInstInfo0, HOInstInfo,
            !Info),
        Inst = any(Uniq, HOInstInfo)
    ;
        ( Inst0 = free
        ; Inst0 = not_reached
        ; Inst0 = inst_var(_)
        ),
        Inst = Inst0
    ;
        Inst0 = bound(Uniq, InstResults0, BoundFunctors0),
        (
            ( InstResults0 = inst_test_results_fgtc
            ; InstResults0 = inst_test_no_results
            )
        ;
            InstResults0 = inst_test_results(_, _, _, _, _, _),
            unexpected($pred, "compiler generated inst not expected")
        ),
        % XXX We could pass a more specific error context.
        qualify_bound_functors(InInt, ErrorContext,
            BoundFunctors0, BoundFunctors, !Info),
        Inst = bound(Uniq, InstResults0, BoundFunctors)
    ;
        Inst0 = ground(Uniq, HOInstInfo0),
        % XXX We could pass a more specific error context.
        qualify_ho_inst_info(InInt, ErrorContext, HOInstInfo0, HOInstInfo,
            !Info),
        Inst = ground(Uniq, HOInstInfo)
    ;
        Inst0 = constrained_inst_vars(Vars, SubInst0),
        % XXX We could pass a more specific error context.
        qualify_inst(InInt, ErrorContext, SubInst0, SubInst, !Info),
        Inst = constrained_inst_vars(Vars, SubInst)
    ;
        Inst0 = defined_inst(InstName0),
        % XXX We could pass a more specific error context.
        qualify_inst_name(InInt, ErrorContext, InstName0, InstName, !Info),
        Inst = defined_inst(InstName)
    ).

:- pred qualify_inst_list(mq_in_interface::in, mq_error_context::in,
    list(mer_inst)::in, list(mer_inst)::out, mq_info::in, mq_info::out) is det.

qualify_inst_list(_InInt, _ErrorContext, [], [], !Info).
qualify_inst_list(InInt, ErrorContext, [Inst0 | Insts0], [Inst | Insts],
        !Info) :-
    qualify_inst(InInt, ErrorContext, Inst0, Inst, !Info),
    qualify_inst_list(InInt, ErrorContext, Insts0, Insts, !Info).

:- pred qualify_ho_inst_info(mq_in_interface::in, mq_error_context::in,
    ho_inst_info::in, ho_inst_info::out, mq_info::in, mq_info::out) is det.

qualify_ho_inst_info(InInt, ErrorContext, HOInstInfo0, HOInstInfo, !Info) :-
    (
        HOInstInfo0 = higher_order(pred_inst_info(PredOrFunc, Modes0,
            MaybeArgRegs, Detism)),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        HOInstInfo = higher_order(pred_inst_info(PredOrFunc, Modes,
            MaybeArgRegs, Detism))
    ;
        HOInstInfo0 = none_or_default_func,
        HOInstInfo = none_or_default_func
    ).

    % Find the unique qual_id_inst that matches this inst, and qualify
    % the argument insts.
    %
:- pred qualify_inst_name(mq_in_interface::in, mq_error_context::in,
    inst_name::in, inst_name::out, mq_info::in, mq_info::out) is det.

qualify_inst_name(InInt, ErrorContext, InstName0, InstName, !Info) :-
    (
        InstName0 = user_inst(SymName0, Insts0),
        qualify_inst_list(InInt, ErrorContext, Insts0, Insts, !Info),
        ( if
            % Check for a variable inst constructor.
            SymName0 = unqualified("")
        then
            report_invalid_user_inst(SymName0, Insts, ErrorContext, Spec),
            InstCtor = inst_ctor(SymName0, list.length(Insts0)),
            mq_info_get_undef_insts(!.Info, UndefInsts0),
            one_or_more_map.add(InstCtor, Spec, UndefInsts0, UndefInsts),
            mq_info_set_undef_insts(UndefInsts, !Info),
            SymName = SymName0
        else
            list.length(Insts0, Arity),
            mq_info_get_insts(!.Info, InstIdSet),
            find_unique_match(InInt, ErrorContext, InstIdSet, qual_id_inst,
                mq_id(SymName0, Arity), SymName, !Info)
        ),
        InstName = user_inst(SymName, Insts)
    ;
        ( InstName0 = unify_inst(_, _, _, _)
        ; InstName0 = merge_inst(_, _)
        ; InstName0 = ground_inst(_, _, _, _)
        ; InstName0 = any_inst(_, _, _, _)
        ; InstName0 = shared_inst(_)
        ; InstName0 = mostly_uniq_inst(_)
        ; InstName0 = typed_ground(_, _)
        ; InstName0 = typed_inst(_, _)
        ),
        unexpected($pred, "unexpected compiler generated inst_name")
    ).

:- pred qualify_bound_functors(mq_in_interface::in, mq_error_context::in,
    list(bound_functor)::in, list(bound_functor)::out,
    mq_info::in, mq_info::out) is det.

qualify_bound_functors(_InInt, _ErrorContext, [], [], !Info).
qualify_bound_functors(InInt, ErrorContext,
        [BoundFunctor0 | BoundFunctors0], [BoundFunctor | BoundFunctors],
        !Info) :-
    qualify_bound_functor(InInt, ErrorContext, BoundFunctor0, BoundFunctor,
        !Info),
    qualify_bound_functors(InInt, ErrorContext, BoundFunctors0, BoundFunctors,
        !Info).

    % Qualify an inst of the form bound(functor(...)).
    %
:- pred qualify_bound_functor(mq_in_interface::in, mq_error_context::in,
    bound_functor::in, bound_functor::out, mq_info::in, mq_info::out) is det.

qualify_bound_functor(InInt, ErrorContext, BoundFunctor0, BoundFunctor,
        !Info) :-
    BoundFunctor0 = bound_functor(ConsId, Insts0),
    (
        ConsId = du_data_ctor(du_ctor(Name, Arity, _)),
        Id = recomp_item_name(Name, Arity),
        update_recompilation_info(record_used_item(used_functor, Id, Id),
            !Info)
    ;
        ( ConsId = tuple_cons(_)
        ; ConsId = closure_cons(_)
        ; ConsId = some_int_const(_)
        ; ConsId = float_const(_)
        ; ConsId = char_const(_)
        ; ConsId = string_const(_)
        ; ConsId = impl_defined_const(_)
        ; ConsId = type_ctor_info_const(_, _, _)
        ; ConsId = base_typeclass_info_const(_, _, _, _)
        ; ConsId = type_info_cell_constructor(_)
        ; ConsId = typeclass_info_cell_constructor
        ; ConsId = type_info_const(_)
        ; ConsId = typeclass_info_const(_)
        ; ConsId = ground_term_const(_, _)
        ; ConsId = tabling_info_const(_)
        ; ConsId = table_io_entry_desc(_)
        ; ConsId = deep_profiling_proc_layout(_)
        )
    ),
    qualify_inst_list(InInt, ErrorContext, Insts0, Insts, !Info),
    BoundFunctor = bound_functor(ConsId, Insts).

%---------------------------------------------------------------------------%
%
% Module qualify mode definitions and modes.
%

    % Qualify the right hand side of a mode definition.
    %
:- pred qualify_mode_defn(mq_in_interface::in, prog_context::in,
    mode_ctor::in, maybe_abstract_mode_defn::in, maybe_abstract_mode_defn::out,
    mq_info::in, mq_info::out) is det.

qualify_mode_defn(InInt, Context, ModeCtor,
        MaybeAbstractModeDefn0, MaybeAbstractModeDefn, !Info) :-
    (
        MaybeAbstractModeDefn0 = abstract_mode_defn,
        MaybeAbstractModeDefn = abstract_mode_defn
    ;
        MaybeAbstractModeDefn0 = nonabstract_mode_defn(ModeDefn0),
        ErrorContext = mqec_mode_defn(Context, ModeCtor),
        ModeDefn0 = eqv_mode(Mode0),
        qualify_mode(InInt, ErrorContext, Mode0, Mode, !Info),
        ModeDefn = eqv_mode(Mode),
        MaybeAbstractModeDefn = nonabstract_mode_defn(ModeDefn)
    ).

qualify_clause_mode_list(InInt, Context, Modes0, Modes, !Info) :-
    ErrorContext = mqec_clause_mode_annotation(Context),
    qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info).

:- pred qualify_mode_list(mq_in_interface::in, mq_error_context::in,
    list(mer_mode)::in, list(mer_mode)::out, mq_info::in, mq_info::out) is det.

qualify_mode_list(_InInt, _ErrorContext, [], [], !Info).
qualify_mode_list(InInt, ErrorContext, [Mode0 | Modes0], [Mode | Modes],
        !Info) :-
    qualify_mode(InInt, ErrorContext, Mode0, Mode, !Info),
    qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info).

qualify_lambda_mode(InInt, Context, Mode0, Mode, !Info) :-
    ErrorContext = mqec_lambda_expr(Context),
    qualify_mode(InInt, ErrorContext, Mode0, Mode, !Info).

:- pred qualify_mode(mq_in_interface::in, mq_error_context::in,
    mer_mode::in, mer_mode::out, mq_info::in, mq_info::out) is det.

qualify_mode(InInt, ErrorContext, Mode0, Mode, !Info) :-
    (
        Mode0 = from_to_mode(InstA0, InstB0),
        qualify_inst(InInt, ErrorContext, InstA0, InstA, !Info),
        qualify_inst(InInt, ErrorContext, InstB0, InstB, !Info),
        Mode = from_to_mode(InstA, InstB)
    ;
        Mode0 = user_defined_mode(SymName0, Insts0),
        qualify_inst_list(InInt, ErrorContext, Insts0, Insts, !Info),
        list.length(Insts, Arity),
        mq_info_get_modes(!.Info, Modes),
        find_unique_match(InInt, ErrorContext, Modes, qual_id_mode,
            mq_id(SymName0, Arity), SymName, !Info),
        Mode = user_defined_mode(SymName, Insts)
    ).

%---------------------------------------------------------------------------%
%
% Module qualify the components of predicate declarations.
%

:- pred qualify_types_and_maybe_modes(mq_in_interface::in,
    mq_error_context::in,
    types_and_maybe_modes::in, types_and_maybe_modes::out,
    mq_info::in, mq_info::out) is det.

qualify_types_and_maybe_modes(InInt, ErrorContext,
        TypesAndMaybeModes0, TypesAndMaybeModes, !Info) :-
    (
        TypesAndMaybeModes0 = no_types_arity_zero,
        TypesAndMaybeModes = no_types_arity_zero
    ;
        TypesAndMaybeModes0 = types_only(Types0),
        qualify_types(InInt, ErrorContext, Types0, Types, !Info),
        TypesAndMaybeModes = types_only(Types)
    ;
        TypesAndMaybeModes0 = types_and_modes(TypesAndModes0),
        qualify_types_and_modes(InInt, ErrorContext,
            TypesAndModes0, TypesAndModes, !Info),
        TypesAndMaybeModes = types_and_modes(TypesAndModes)
    ).

    % Qualify a list of types.
    %
:- pred qualify_types(mq_in_interface::in, mq_error_context::in,
    list(mer_type)::in, list(mer_type)::out, mq_info::in, mq_info::out) is det.

qualify_types(_InInt, _ErrorContext, [], [], !Info).
qualify_types(InInt, ErrorContext, [Type0 | Types0], [Type | Types], !Info) :-
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    qualify_types(InInt, ErrorContext, Types0, Types, !Info).

    % Qualify a list of items of the form Type::Mode, as in a
    % predicate declaration.
    %
:- pred qualify_types_and_modes(mq_in_interface::in, mq_error_context::in,
    list(type_and_mode)::in, list(type_and_mode)::out,
    mq_info::in, mq_info::out) is det.

qualify_types_and_modes(_InInt, _ErrorContext, [], [], !Info).
qualify_types_and_modes(InInt, ErrorContext,
        [TypeAndMode0 | TypesAndModes0], [TypeAndMode | TypesAndModes],
        !Info) :-
    qualify_type_and_mode(InInt, ErrorContext,
        TypeAndMode0, TypeAndMode, !Info),
    qualify_types_and_modes(InInt, ErrorContext,
        TypesAndModes0, TypesAndModes, !Info).

:- pred qualify_type_and_mode(mq_in_interface::in, mq_error_context::in,
    type_and_mode::in, type_and_mode::out, mq_info::in, mq_info::out) is det.

qualify_type_and_mode(InInt, ErrorContext, TypeAndMode0, TypeAndMode,
        !Info) :-
    TypeAndMode0 = type_and_mode(Type0, Mode0),
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    qualify_mode(InInt, ErrorContext, Mode0, Mode, !Info),
    TypeAndMode = type_and_mode(Type, Mode).

%---------------------------------------------------------------------------%
%
% Module qualify the components of typeclass declarations and typeclass
% constraints.
%

:- pred qualify_prog_constraints(mq_in_interface::in,
    mq_constraint_error_context::in,
    univ_exist_constraints::in, univ_exist_constraints::out,
    mq_info::in, mq_info::out) is det.

qualify_prog_constraints(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info) :-
    Constraints0 = univ_exist_constraints(UnivCs0, ExistCs0),
    % XXX We could pass a more specific error context.
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        UnivCs0, UnivCs, !Info),
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        ExistCs0, ExistCs, !Info),
    Constraints = univ_exist_constraints(UnivCs, ExistCs).

%---------------------%

:- pred qualify_prog_constraint_list(mq_in_interface::in,
    mq_constraint_error_context::in,
    list(prog_constraint)::in, list(prog_constraint)::out,
    mq_info::in, mq_info::out) is det.

qualify_prog_constraint_list(_InInt, _ConstraintErrorContext,
        [], [], !Info).
qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        [Constraint0 | Constraints0], [Constraint | Constraints], !Info) :-
    qualify_prog_constraint(InInt, ConstraintErrorContext,
        Constraint0, Constraint, !Info),
    qualify_prog_constraint_list(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info).

:- pred qualify_prog_constraint(mq_in_interface::in,
    mq_constraint_error_context::in,
    prog_constraint::in, prog_constraint::out,
    mq_info::in, mq_info::out) is det.

qualify_prog_constraint(InInt, ContainingErrorContext,
        Constraint0, Constraint, !Info) :-
    Constraint0 = constraint(ClassName0, Types0),
    list.length(Types0, Arity),
    OutsideContext = mqec_typeclass_constraint_name(ContainingErrorContext),
    qualify_class_name(InInt, OutsideContext,
        mq_id(ClassName0, Arity), ClassName, !Info),
    ErrorContext = mqec_typeclass_constraint(ClassName0, Arity,
        ContainingErrorContext),
    qualify_type_list(InInt, ErrorContext, Types0, Types, !Info),
    Constraint = constraint(ClassName, Types).

%---------------------%

:- pred qualify_var_or_ground_constraint_list(mq_in_interface::in,
    mq_constraint_error_context::in,
    list(var_or_ground_constraint)::in, list(var_or_ground_constraint)::out,
    mq_info::in, mq_info::out) is det.

qualify_var_or_ground_constraint_list(_InInt, _ConstraintErrorContext,
        [], [], !Info).
qualify_var_or_ground_constraint_list(InInt, ConstraintErrorContext,
        [Constraint0 | Constraints0], [Constraint | Constraints], !Info) :-
    qualify_var_or_ground_constraint(InInt, ConstraintErrorContext,
        Constraint0, Constraint, !Info),
    qualify_var_or_ground_constraint_list(InInt, ConstraintErrorContext,
        Constraints0, Constraints, !Info).

:- pred qualify_var_or_ground_constraint(mq_in_interface::in,
    mq_constraint_error_context::in,
    var_or_ground_constraint::in, var_or_ground_constraint::out,
    mq_info::in, mq_info::out) is det.

qualify_var_or_ground_constraint(InInt, ContainingErrorContext,
        Constraint0, Constraint, !Info) :-
    Constraint0 = var_or_ground_constraint(ClassName0, Types0, Context),
    list.length(Types0, Arity),
    OutsideContext = mqec_typeclass_constraint_name(ContainingErrorContext),
    qualify_class_name(InInt, OutsideContext,
        mq_id(ClassName0, Arity), ClassName, !Info),
    ErrorContext = mqec_typeclass_constraint(ClassName0, Arity,
        ContainingErrorContext),
    qualify_var_or_ground_type_list(InInt, ErrorContext, Types0, Types,
        !Info),
    Constraint = var_or_ground_constraint(ClassName, Types, Context).

:- pred qualify_var_or_ground_type_list(mq_in_interface::in,
    mq_error_context::in,
    list(var_or_ground_type)::in, list(var_or_ground_type)::out,
    mq_info::in, mq_info::out) is det.

qualify_var_or_ground_type_list(_, _, [], [], !Info).
qualify_var_or_ground_type_list(InInt, ErrorContext,
        [Arg0 | Args0], [Arg | Args], !Info) :-
    (
        Arg0 = type_var_name(_, _),
        Arg = Arg0
    ;
        Arg0 = ground_type(GroundType0),
        Type0 = coerce(GroundType0),
        qualify_type(InInt, ErrorContext, Type0, Type, !Info),
        ( if type_is_ground(Type, GroundType) then
            Arg = ground_type(GroundType)
        else
            unexpected($pred, "qualified ground type is not ground")
        )
    ),
    qualify_var_or_ground_type_list(InInt, ErrorContext,
        Args0, Args, !Info).

%---------------------%

:- pred qualify_class_name(mq_in_interface::in, mq_error_context::in,
    mq_id::in, sym_name::out, mq_info::in, mq_info::out) is det.

qualify_class_name(InInt, ErrorContext, Class0, Name, !Info) :-
    mq_info_get_classes(!.Info, ClassIdSet),
    find_unique_match(InInt, ErrorContext, ClassIdSet, qual_id_class,
        Class0, Name, !Info).

%---------------------%

:- pred qualify_class_decls(mq_in_interface::in, class_id::in,
    list(class_decl)::in, list(class_decl)::out,
    mq_info::in, mq_info::out) is det.

qualify_class_decls(_InInt, _ClassId, [], [], !Info).
qualify_class_decls(InInt, ClassId, [Decl0 | Decls0], [Decl | Decls], !Info) :-
    qualify_class_decl(InInt, ClassId, Decl0, Decl, !Info),
    qualify_class_decls(InInt, ClassId, Decls0, Decls, !Info).

:- pred qualify_class_decl(mq_in_interface::in, class_id::in,
    class_decl::in, class_decl::out, mq_info::in, mq_info::out) is det.

qualify_class_decl(InInt, ClassId, Decl0, Decl, !Info) :-
    % There is no need to qualify the method name, since that is done
    % when the item is parsed.
    (
        Decl0 = class_decl_pred_or_func(PredOrFuncInfo0),
        PredOrFuncInfo0 = class_pred_or_func_info(SymName, PredOrFunc,
            TypesAndMaybeModes0, MaybeWithType0, MaybeWithInst0, MaybeDetism,
            TypeVarset, InstVarset, ExistQVars, Purity, Constraints0, Context),
        Name = unqualify_name(SymName),
        (
            MaybeWithType0 = yes(_),
            UserArityIfKnown = user_arity_unknown
        ;
            MaybeWithType0 = no,
            (
                TypesAndMaybeModes0 = no_types_arity_zero,
                PredFormArity = pred_form_arity(0)
            ;
                TypesAndMaybeModes0 = types_only(Types),
                PredFormArity = arg_list_arity(Types)
            ;
                TypesAndMaybeModes0 = types_and_modes(TypesAndModes),
                PredFormArity = arg_list_arity(TypesAndModes)
            ),
            user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity),
            UserArityIfKnown = user_arity_known(UserArity)
        ),
        ErrorContext = mqec_class_method(Context, ClassId,
            PredOrFunc, Name, UserArityIfKnown),
        qualify_types_and_maybe_modes(InInt, ErrorContext,
            TypesAndMaybeModes0, TypesAndMaybeModes, !Info),
        ConstraintErrorContext = mqcec_class_method(Context, ClassId,
            PredOrFunc, Name, UserArityIfKnown),
        qualify_prog_constraints(InInt, ConstraintErrorContext,
            Constraints0, Constraints, !Info),
        (
            MaybeWithType0 = yes(WithType0),
            % XXX We could pass a more specific error context.
            qualify_type(InInt, ErrorContext, WithType0, WithType, !Info),
            MaybeWithType = yes(WithType)
        ;
            MaybeWithType0 = no,
            MaybeWithType = no
        ),
        (
            MaybeWithInst0 = yes(WithInst0),
            % XXX We could pass a more specific error context.
            qualify_inst(InInt, ErrorContext, WithInst0, WithInst, !Info),
            MaybeWithInst = yes(WithInst)
        ;
            MaybeWithInst0 = no,
            MaybeWithInst = no
        ),
        PredOrFuncInfo = class_pred_or_func_info(SymName, PredOrFunc,
            TypesAndMaybeModes, MaybeWithType, MaybeWithInst, MaybeDetism,
            TypeVarset, InstVarset, ExistQVars, Purity, Constraints, Context),
        Decl = class_decl_pred_or_func(PredOrFuncInfo)
    ;
        Decl0 = class_decl_mode(ModeInfo0),
        ModeInfo0 = class_mode_info(SymName, MaybePredOrFunc, Modes0,
            MaybeWithInst0, MaybeDetism, Varset, Context),
        Name = unqualify_name(SymName),
        (
            MaybePredOrFunc = no,
            UserArityIfKnown = user_arity_unknown
        ;
            MaybePredOrFunc = yes(PredOrFunc),
            (
                MaybeWithInst0 = yes(_),
                UserArityIfKnown = user_arity_unknown
            ;
                MaybeWithInst0 = no,
                PredFormArity = arg_list_arity(Modes0),
                user_arity_pred_form_arity(PredOrFunc,
                    UserArity, PredFormArity),
                UserArityIfKnown = user_arity_known(UserArity)
            )
        ),
        ErrorContext = mqec_class_method_mode(Context, ClassId,
            MaybePredOrFunc, Name, UserArityIfKnown),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        (
            MaybeWithInst0 = yes(WithInst0),
            % XXX We could pass a more specific error context.
            qualify_inst(InInt, ErrorContext, WithInst0, WithInst,
                !Info),
            MaybeWithInst = yes(WithInst)
        ;
            MaybeWithInst0 = no,
            MaybeWithInst = no
        ),
        ModeInfo = class_mode_info(SymName, MaybePredOrFunc, Modes,
            MaybeWithInst, MaybeDetism, Varset, Context),
        Decl = class_decl_mode(ModeInfo)
    ).

%---------------------------------------------------------------------------%
%
% Module qualify instance definitions.
%

:- pred qualify_instance_body(sym_name::in,
    instance_body::in, instance_body::out) is det.

qualify_instance_body(ClassName, InstanceBody0, InstanceBody) :-
    (
        InstanceBody0 = instance_body_abstract,
        InstanceBody = instance_body_abstract
    ;
        InstanceBody0 = instance_body_concrete(Methods0),
        (
            ClassName = unqualified(_),
            InstanceBody = InstanceBody0
        ;
            ClassName = qualified(_, _),
            sym_name_get_module_name_default(ClassName, unqualified(""),
                DefaultModuleName),
            list.map(qualify_instance_method(DefaultModuleName),
                Methods0, Methods),
            InstanceBody = instance_body_concrete(Methods)
        )
    ).

:- pred qualify_instance_method(module_name::in,
    instance_method::in, instance_method::out) is det.

qualify_instance_method(DefaultModuleName, InstanceMethod0, InstanceMethod) :-
    % XXX InstanceProcDef may contain a list of clauses.
    % Why aren't those clauses module qualified?
    InstanceMethod0 = instance_method(MethodName0,
        InstanceProcDef, DeclContext),
    MethodName0 = pred_pf_name_arity(PredOrFunc, MethodSymName0, UserArity),
    (
        MethodSymName0 = unqualified(Name),
        MethodSymName = qualified(DefaultModuleName, Name)
    ;
        MethodSymName0 = qualified(MethodModuleName, MethodBaseName),
        ( if
            partial_sym_name_matches_full(MethodModuleName, DefaultModuleName)
        then
            MethodSymName = qualified(DefaultModuleName, MethodBaseName)
        else
            % This case is an error. The user must have written something like
            %   :- instance foo.bar(some_type) where [
            %       pred(baz.p/1) is q
            %   ].
            % where the module qualifier on the pred or func in the instance
            % (baz) does not match the qualifier for the class name (foo).
            %
            % We don't report the error here, we just leave the original
            % module qualifier intact so that the error can be reported
            % later on. XXX METHOD Where is the code that does this reporting?
            MethodSymName = MethodSymName0
        )
    ),
    MethodName = pred_pf_name_arity(PredOrFunc, MethodSymName, UserArity),
    InstanceMethod = instance_method(MethodName,
        InstanceProcDef, DeclContext).

%---------------------------------------------------------------------------%
%
% Module qualify pragmas.
%

:- pred module_qualify_item_decl_pragma(mq_in_interface::in,
    item_decl_pragma_info::in, item_decl_pragma_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_decl_pragma(InInt, Pragma0, Pragma, !Info) :-
    (
        Pragma0 = decl_pragma_type_spec_constr(TypeSpecConstrInfo0),
        TypeSpecConstrInfo0 = decl_pragma_type_spec_constr_info(ModuleName,
            OoMConstraints0, ApplyToSupers, OoMSubsts0, TVarSet, Items,
            Context, SeqNum),
        ConstraintErrorContext = mqcec_type_spec_constr(Context, ModuleName),
        OoMConstraints0 = one_or_more(HeadConstraint0, TailConstraints0),
        qualify_var_or_ground_constraint(InInt, ConstraintErrorContext,
            HeadConstraint0, HeadConstraint, !Info),
        qualify_var_or_ground_constraint_list(InInt, ConstraintErrorContext,
            TailConstraints0, TailConstraints, !Info),
        OoMConstraints = one_or_more(HeadConstraint, TailConstraints),
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        OoMSubsts0 = one_or_more(HeadSubst0, TailSubsts0),
        qualify_type_subst(InInt, ErrorContext, HeadSubst0, HeadSubst, !Info),
        list.map_foldl(qualify_type_subst(InInt, ErrorContext),
            TailSubsts0, TailSubsts, !Info),
        OoMSubsts = one_or_more(HeadSubst, TailSubsts),
        TypeSpecConstrInfo = decl_pragma_type_spec_constr_info(ModuleName,
            OoMConstraints, ApplyToSupers, OoMSubsts, TVarSet, Items,
            Context, SeqNum),
        Pragma = decl_pragma_type_spec_constr(TypeSpecConstrInfo)
    ;
        Pragma0 = decl_pragma_type_spec(TypeSpecInfo0),
        TypeSpecInfo0 = decl_pragma_type_spec_info(PFUMM0, PredName,
            SpecPredName, Subst0, TVarSet, Items, Context, SeqNum),
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        (
            PFUMM0 = pfumm_predicate(ModesOrArity0),
            (
                ModesOrArity0 = moa_modes(Modes0),
                qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
                ModesOrArity = moa_modes(Modes),
                PFUMM = pfumm_predicate(ModesOrArity)
            ;
                ModesOrArity0 = moa_arity(_Arity),
                PFUMM = PFUMM0
            )
        ;
            PFUMM0 = pfumm_function(ModesOrArity0),
            (
                ModesOrArity0 = moa_modes(Modes0),
                qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
                ModesOrArity = moa_modes(Modes),
                PFUMM = pfumm_function(ModesOrArity)
            ;
                ModesOrArity0 = moa_arity(_Arity),
                PFUMM = PFUMM0
            )
        ;
            PFUMM0 = pfumm_unknown(_Arity),
            PFUMM = PFUMM0
        ),
        qualify_type_subst(InInt, ErrorContext, Subst0, Subst, !Info),
        TypeSpecInfo = decl_pragma_type_spec_info(PFUMM, PredName,
            SpecPredName, Subst, TVarSet, Items, Context, SeqNum),
        Pragma = decl_pragma_type_spec(TypeSpecInfo)
    ;
        Pragma0 = decl_pragma_oisu(OISUInfo0),
        OISUInfo0 = decl_pragma_oisu_info(TypeCtor0, CreatorPreds,
            MutatorPreds, DestructorPreds, Context, SeqNum),
        % XXX Preds
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        qualify_type_ctor(InInt, ErrorContext, TypeCtor0, TypeCtor,
            !Info),
        OISUInfo = decl_pragma_oisu_info(TypeCtor, CreatorPreds,
            MutatorPreds, DestructorPreds, Context, SeqNum),
        Pragma = decl_pragma_oisu(OISUInfo)
    ;
        Pragma0 = decl_pragma_termination(TermInfo0),
        TermInfo0 = decl_pragma_termination_info(PredNameModesPF0, Args, Term,
            Context, SeqNum),
        PredNameModesPF0 = proc_pf_name_modes(PredOrFunc, SymName, Modes0),
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, Modes),
        TermInfo = decl_pragma_termination_info(PredNameModesPF, Args, Term,
            Context, SeqNum),
        Pragma = decl_pragma_termination(TermInfo)
    ;
        Pragma0 = decl_pragma_termination2(Term2Info0),
        Term2Info0 = decl_pragma_termination2_info(PredNameModesPF0,
            SuccessArgs, FailureArgs, Term, Context, SeqNum),
        PredNameModesPF0 = proc_pf_name_modes(PredOrFunc, SymName, Modes0),
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, Modes),
        Term2Info = decl_pragma_termination2_info(PredNameModesPF,
            SuccessArgs, FailureArgs, Term, Context, SeqNum),
        Pragma = decl_pragma_termination2(Term2Info)
    ;
        Pragma0 = decl_pragma_struct_sharing(SharingInfo0),
        SharingInfo0 = decl_pragma_struct_sharing_info(PredNameModesPF0,
            HeadVars, HeadVarTypes, VarSet, TVarSet, MaybeSharing,
            Context, SeqNum),
        PredNameModesPF0 = proc_pf_name_modes(PredOrFunc, SymName, Modes0),
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, Modes),
        SharingInfo = decl_pragma_struct_sharing_info(PredNameModesPF,
            HeadVars, HeadVarTypes, VarSet, TVarSet, MaybeSharing,
            Context, SeqNum),
        Pragma = decl_pragma_struct_sharing(SharingInfo)
    ;
        Pragma0 = decl_pragma_struct_reuse(ReuseInfo0),
        ReuseInfo0 = decl_pragma_struct_reuse_info(PredNameModesPF0,
            HeadVars, HeadVarTypes, VarSet, TVarSet, MaybeReuse,
            Context, SeqNum),
        PredNameModesPF0 = proc_pf_name_modes(PredOrFunc, SymName, Modes0),
        ErrorContext = mqec_pragma_decl(Context, Pragma0),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, Modes),
        ReuseInfo = decl_pragma_struct_reuse_info(PredNameModesPF,
            HeadVars, HeadVarTypes, VarSet, TVarSet, MaybeReuse,
            Context, SeqNum),
        Pragma = decl_pragma_struct_reuse(ReuseInfo)
    ;
        ( Pragma0 = decl_pragma_obsolete_pred(_)
        ; Pragma0 = decl_pragma_obsolete_proc(_)
        ; Pragma0 = decl_pragma_format_call(_)
        ),
        Pragma = Pragma0
    ).

:- pred module_qualify_item_impl_pragma(mq_in_interface::in,
    item_impl_pragma_info::in, item_impl_pragma_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_impl_pragma(InInt, Pragma0, Pragma, !Info) :-
    (
        ( Pragma0 = impl_pragma_foreign_decl(_)
        ; Pragma0 = impl_pragma_foreign_code(_)
        ; Pragma0 = impl_pragma_external_proc(_)
          % The predicate name in the pragma_external_proc is constructed
          % already qualified.
        ; Pragma0 = impl_pragma_fact_table(_)
        ; Pragma0 = impl_pragma_req_tail_rec(_)
        ; Pragma0 = impl_pragma_req_feature_set(_)
        ),
        Pragma = Pragma0
    ;
        Pragma0 = impl_pragma_tabled(TabledInfo0),
        TabledInfo0 = impl_pragma_tabled_info(EvalMethod, PredOrProcSpec0,
            Attrs, Context, SeqNum),
        PredOrProcSpec0 = pred_or_proc_pfumm_name(PFUMM0, PredSymName),
        (
            PFUMM0 = pfumm_predicate(ModesOrArity0),
            (
                ModesOrArity0 = moa_modes(Modes0),
                ErrorContext = mqec_pragma_impl(Context, Pragma0),
                qualify_mode_list(InInt, ErrorContext, Modes0, Modes,
                    !Info),
                ModesOrArity = moa_modes(Modes),
                PFUMM = pfumm_predicate(ModesOrArity)
            ;
                ModesOrArity0 = moa_arity(_Arity),
                PFUMM = PFUMM0
            )
        ;
            PFUMM0 = pfumm_function(ModesOrArity0),
            (
                ModesOrArity0 = moa_modes(Modes0),
                ErrorContext = mqec_pragma_impl(Context, Pragma0),
                qualify_mode_list(InInt, ErrorContext, Modes0, Modes,
                    !Info),
                ModesOrArity = moa_modes(Modes),
                PFUMM = pfumm_function(ModesOrArity)
            ;
                ModesOrArity0 = moa_arity(_Arity),
                PFUMM = PFUMM0
            )
        ;
            PFUMM0 = pfumm_unknown(_Arity),
            PFUMM = PFUMM0
        ),
        PredOrProcSpec = pred_or_proc_pfumm_name(PFUMM, PredSymName),
        TabledInfo = impl_pragma_tabled_info(EvalMethod, PredOrProcSpec,
            Attrs, Context, SeqNum),
        Pragma = impl_pragma_tabled(TabledInfo)
    ;
        Pragma0 = impl_pragma_fproc_export(FPEInfo0),
        FPEInfo0 = impl_pragma_fproc_export_info(Origin, Lang,
            PredNameModesPF0, CFunc, VarSet, Context, SeqNum),
        PredNameModesPF0 = proc_pf_name_modes(PredOrFunc, Name, Modes0),
        ErrorContext = mqec_pragma_impl(Context, Pragma0),
        qualify_mode_list(InInt, ErrorContext, Modes0, Modes, !Info),
        PredNameModesPF = proc_pf_name_modes(PredOrFunc, Name, Modes),
        FPEInfo = impl_pragma_fproc_export_info(Origin, Lang,
            PredNameModesPF, CFunc, VarSet, Context, SeqNum),
        Pragma = impl_pragma_fproc_export(FPEInfo)
    ).

:- pred qualify_pragma_vars(mq_in_interface::in, mq_error_context::in,
    list(pragma_var)::in, list(pragma_var)::out,
    mq_info::in, mq_info::out) is det.

qualify_pragma_vars(_InInt, _ErrorContext, [], [], !Info).
qualify_pragma_vars(InInt, ErrorContext,
        [PragmaVar0 | PragmaVars0], [PragmaVar | PragmaVars], !Info) :-
    % XXX We could pass a more specific error context.
    qualify_pragma_var(InInt, ErrorContext, PragmaVar0, PragmaVar, !Info),
    qualify_pragma_vars(InInt, ErrorContext, PragmaVars0, PragmaVars, !Info).

:- pred qualify_pragma_var(mq_in_interface::in, mq_error_context::in,
    pragma_var::in, pragma_var::out, mq_info::in, mq_info::out) is det.

qualify_pragma_var(InInt, ErrorContext, PragmaVar0, PragmaVar, !Info) :-
    PragmaVar0 = pragma_var(Var, Name, Mode0, Box),
    % XXX We could pass a more specific error context.
    qualify_mode(InInt, ErrorContext, Mode0, Mode, !Info),
    PragmaVar = pragma_var(Var, Name, Mode, Box).

:- pred qualify_type_subst(mq_in_interface::in, mq_error_context::in,
    type_subst::in, type_subst::out, mq_info::in, mq_info::out) is det.

qualify_type_subst(InInt, ErrorContext, Subst0, Subst, !Info) :-
    Subst0 = one_or_more(HeadSubst0, TailSubsts0),
    qualify_tvar_substs(InInt, ErrorContext,
        HeadSubst0, HeadSubst, TailSubsts0, TailSubsts, !Info),
    Subst = one_or_more(HeadSubst, TailSubsts).

:- pred qualify_tvar_substs(mq_in_interface::in, mq_error_context::in,
    tvar_subst::in, tvar_subst::out,
    list(tvar_subst)::in, list(tvar_subst)::out,
    mq_info::in, mq_info::out) is det.

qualify_tvar_substs(InInt, ErrorContext,
        HeadSubst0, HeadSubst, TailSubsts0, TailSubsts, !Info) :-
    HeadSubst0 = tvar_subst(Var, Type0),
    % XXX We could pass a more specific error context.
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    HeadSubst = tvar_subst(Var, Type),
    (
        TailSubsts0 = [],
        TailSubsts = []
    ;
        TailSubsts0 = [HeadTailSubst0 | TailTailSubsts0],
        qualify_tvar_substs(InInt, ErrorContext,
            HeadTailSubst0, HeadTailSubst, TailTailSubsts0, TailTailSubsts,
            !Info),
        TailSubsts = [HeadTailSubst | TailTailSubsts]
    ).

:- pred qualify_user_sharing(mq_in_interface::in, mq_error_context::in,
    user_annotated_sharing::in, user_annotated_sharing::out,
    mq_info::in, mq_info::out) is det.

qualify_user_sharing(InInt, ErrorContext, UserSharing0, UserSharing, !Info) :-
    (
        UserSharing0 = no_user_annotated_sharing,
        UserSharing = UserSharing0
    ;
        UserSharing0 = user_sharing(Sharing, MaybeTypes0),
        (
            MaybeTypes0 = yes(user_type_info(Types0, TVarset)),
            qualify_type_list(InInt, ErrorContext, Types0, Types, !Info),
            MaybeTypes = yes(user_type_info(Types, TVarset)),
            UserSharing = user_sharing(Sharing, MaybeTypes)
        ;
            MaybeTypes0 = no,
            UserSharing = UserSharing0
        )
    ).

%---------------------------------------------------------------------------%
%
% Module qualify the definitions of mutables.
%

:- pred module_qualify_item_mutable(mq_in_interface::in,
    item_mutable_info::in, item_mutable_info::out,
    mq_info::in, mq_info::out) is det.

module_qualify_item_mutable(InInt, ItemMutable0, ItemMutable, !Info) :-
    ItemMutable0 = item_mutable_info(Name, OrigType0, Type0, OrigInst0, Inst0,
        InitTerm, Attrs, Varset, Context, SeqNum),
    ErrorContext = mqec_mutable(Context, Name),
    % WAS_IGNORED We used to ignore diag_specs from OrigType.
    qualify_type(InInt, ErrorContext, OrigType0, OrigType, !Info),
    qualify_type(InInt, ErrorContext, Type0, Type, !Info),
    % WAS_IGNORED We used to ignore diag_specs from OrigInst.
    qualify_inst(InInt, ErrorContext, OrigInst0, OrigInst, !Info),
    qualify_inst(InInt, ErrorContext, Inst0, Inst, !Info),
    ItemMutable = item_mutable_info(Name, OrigType, Type, OrigInst, Inst,
        InitTerm, Attrs, Varset, Context, SeqNum).

%---------------------------------------------------------------------------%
%
% Module qualify event specifications.
%

    % Module qualify the event specifications of an augmented compilation unit.
    %
:- pred qualify_event_specs(mq_in_interface::in, string::in,
    assoc_list(string, event_spec)::in, assoc_list(string, event_spec)::out,
    mq_info::in, mq_info::out) is det.

qualify_event_specs(_InInt, _, [], [], !Info).
qualify_event_specs(InInt, FileName,
        [Name - Spec0 | NameSpecs0], [Name - Spec | NameSpecs], !Info) :-
    qualify_event_spec(InInt, FileName, Spec0, Spec, !Info),
    qualify_event_specs(InInt, FileName, NameSpecs0, NameSpecs, !Info).

:- pred qualify_event_spec(mq_in_interface::in, string::in,
    event_spec::in, event_spec::out, mq_info::in, mq_info::out) is det.

qualify_event_spec(InInt, FileName, EventSpec0, EventSpec, !Info) :-
    EventSpec0 = event_spec(EventNumber, EventName, EventLineNumber,
        Attrs0, SynthAttrNumOrder),
    list.map_foldl(
        qualify_event_attr(InInt, EventName, FileName, EventLineNumber),
        Attrs0, Attrs, !Info),
    EventSpec = event_spec(EventNumber, EventName, EventLineNumber,
        Attrs, SynthAttrNumOrder).

:- pred qualify_event_attr(mq_in_interface::in,
    string::in, string::in, int::in,
    event_attribute::in, event_attribute::out,
    mq_info::in, mq_info::out) is det.

qualify_event_attr(InInt, EventName, FileName, LineNumber,
        Attr0, Attr, !Info) :-
    Attr0 = event_attribute(AttrNum, AttrName, AttrType0, AttrMode0,
        MaybeSynthCall),
    Context = context(FileName, LineNumber),
    ErrorContext = mqec_event_spec_attr(Context, EventName, AttrName),
    qualify_type(InInt, ErrorContext, AttrType0, AttrType, !Info),
    qualify_mode(InInt, ErrorContext, AttrMode0, AttrMode, !Info),
    Attr = event_attribute(AttrNum, AttrName, AttrType, AttrMode,
        MaybeSynthCall).

%---------------------------------------------------------------------------%
:- end_module parse_tree.module_qual.qualify_items.
%---------------------------------------------------------------------------%
