mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 06:14:59 +00:00
Estimated hours taken: 0.1 Branches: main compiler/module_qual.m: compiler/prog_ctgc.m: compiler/prog_data.m: compiler/prog_item.m: Make some minor formatting and style fixes. Fix a couple of typos.
1929 lines
76 KiB
Mathematica
1929 lines
76 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2006 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: module_qual.m.
|
|
% Main authors: stayl, fjh.
|
|
%
|
|
% Module qualifies types, insts and modes within declaration items. The
|
|
% head of all declarations should be module qualified in prog_io.m.
|
|
% This module qualifies the bodies of the declarations. Checks for
|
|
% undefined types, insts and modes. Uses two passes over the item list,
|
|
% one to collect all type, mode and inst ids and a second to do the
|
|
% qualification and report errors. If the --warn-interface-imports
|
|
% option is set, warns about modules imported in the interface that do
|
|
% not need to be in the interface. The modes of lambda expressions are
|
|
% qualified in modes.m.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.module_qual.
|
|
:- interface.
|
|
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_item.
|
|
:- import_module recompilation.
|
|
|
|
:- import_module bool.
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% module_qualify_items(Items0, Items, ModuleName, ReportUndefErrors,
|
|
% MQ_Info, NumErrors, UndefTypes, UndefModes):
|
|
%
|
|
% Items is Items0 with all items module qualified as much as
|
|
% possible. If ReportUndefErrors is yes, then report undefined
|
|
% types, insts and modes. ReportUndefErrors should be no when
|
|
% module qualifying the short interface.
|
|
%
|
|
:- pred module_qual.module_qualify_items(item_list::in, item_list::out,
|
|
module_name::in, bool::in, mq_info::out, int::out, bool::out,
|
|
bool::out, io::di, io::uo) is det.
|
|
|
|
% This is called from make_hlds.m to qualify the mode of a lambda
|
|
% expression.
|
|
%
|
|
:- pred module_qual.qualify_lambda_mode_list(list(mer_mode)::in,
|
|
list(mer_mode)::out, prog_context::in, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% This is called from make_hlds.m to qualify the modes in a
|
|
% clause mode annotation.
|
|
%
|
|
:- pred module_qual.qualify_clause_mode_list(list(mer_mode)::in,
|
|
list(mer_mode)::out, prog_context::in, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% This is called from make_hlds.m to qualify an
|
|
% explicit type qualification.
|
|
%
|
|
:- pred module_qual.qualify_type_qualification(mer_type::in, mer_type::out,
|
|
prog_context::in, mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
% The type mq_info holds information needed for doing module
|
|
% qualification.
|
|
%
|
|
:- type mq_info.
|
|
|
|
:- pred mq_info_get_num_errors(mq_info::in, int::out) is det.
|
|
:- pred mq_info_get_type_error_flag(mq_info::in, bool::out) is det.
|
|
:- pred mq_info_get_mode_error_flag(mq_info::in, bool::out) is det.
|
|
:- pred mq_info_get_need_qual_flag(mq_info::in, need_qualifier::out) is det.
|
|
:- pred mq_info_get_partial_qualifier_info(mq_info::in,
|
|
partial_qualifier_info::out) is det.
|
|
:- pred mq_info_get_recompilation_info(mq_info::in,
|
|
maybe(recompilation_info)::out) is det.
|
|
|
|
:- pred mq_info_set_need_qual_flag(need_qualifier::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_recompilation_info(maybe(recompilation_info)::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
|
|
% The type partial_qualifier_info holds info need for computing which
|
|
% partial quantifiers are visible -- see get_partial_qualifiers/3.
|
|
%
|
|
:- type partial_qualifier_info.
|
|
|
|
% Suppose we are processing a definition which defines the symbol
|
|
% foo.bar.baz.quux/1. Then we insert the following symbols
|
|
% into the symbol table:
|
|
% - if the current value of the NeedQual flag at this point
|
|
% is `may_be_unqualified',
|
|
% i.e. module `foo.bar.baz' was imported
|
|
% then we insert the fully unqualified symbol quux/1;
|
|
% - if module `foo.bar.baz' occurs in the "imported" section,
|
|
% i.e. if module `foo.bar' was imported,
|
|
% then we insert the partially qualified symbol baz.quux/1;
|
|
% - if module `foo.bar' occurs in the "imported" section,
|
|
% i.e. if module `foo' was imported,
|
|
% then we insert the partially qualified symbol bar.baz.quux/1;
|
|
% - we always insert the fully qualified symbol foo.bar.baz.quux/1.
|
|
%
|
|
% The predicate `get_partial_qualifiers' returns all of the
|
|
% partial qualifiers for which we need to insert definitions,
|
|
% i.e. all the ones which are visible. For example,
|
|
% given as input `foo.bar.baz', it returns a list containing
|
|
% (1) `baz', iff `foo.bar' is imported
|
|
% and (2) `bar.baz', iff `foo' is imported.
|
|
% Note that the caller will still need to handle the fully-qualified
|
|
% and fully-unqualified versions separately.
|
|
%
|
|
:- pred get_partial_qualifiers(module_name::in, partial_qualifier_info::in,
|
|
list(module_name)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.compiler_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.error_util.
|
|
:- import_module parse_tree.mercury_to_mercury.
|
|
:- import_module parse_tree.modules.
|
|
:- import_module parse_tree.prog_io.
|
|
:- import_module parse_tree.prog_out.
|
|
:- import_module parse_tree.prog_type.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module set.
|
|
:- import_module solutions.
|
|
:- import_module string.
|
|
:- import_module svmap.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
module_qual.module_qualify_items(Items0, Items, ModuleName, ReportErrors,
|
|
Info, NumErrors, UndefTypes, UndefModes, !IO) :-
|
|
globals.io_get_globals(Globals, !IO),
|
|
init_mq_info(Items0, Globals, ReportErrors, ModuleName, Info0),
|
|
collect_mq_info(Items0, Info0, Info1),
|
|
do_module_qualify_items(Items0, Items, Info1, Info, !IO),
|
|
mq_info_get_type_error_flag(Info, UndefTypes),
|
|
mq_info_get_mode_error_flag(Info, UndefModes),
|
|
(
|
|
ReportErrors = yes,
|
|
mq_info_get_unused_interface_modules(Info, UnusedImports0),
|
|
set.to_sorted_list(UnusedImports0, UnusedImports),
|
|
maybe_warn_unused_interface_imports(ModuleName, UnusedImports,
|
|
!IO)
|
|
;
|
|
ReportErrors = no
|
|
),
|
|
mq_info_get_num_errors(Info, NumErrors).
|
|
|
|
module_qual.qualify_lambda_mode_list(Modes0, Modes, Context, !Info, !IO) :-
|
|
mq_info_set_error_context(mqec_lambda_expr - Context, !Info),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO).
|
|
|
|
module_qual.qualify_clause_mode_list(Modes0, Modes, Context, !Info, !IO) :-
|
|
mq_info_set_error_context(mqec_clause_mode_annotation - Context, !Info),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO).
|
|
|
|
module_qual.qualify_type_qualification(Type0, Type, Context, !Info, !IO) :-
|
|
mq_info_set_error_context(mqec_type_qual - Context, !Info),
|
|
qualify_type(Type0, Type, !Info, !IO).
|
|
|
|
:- type mq_info
|
|
---> mq_info(
|
|
% Modules which have been imported or used, i.e. the ones
|
|
% for which there was a `:- import_module' or `:- use_module'
|
|
% declaration in this module.
|
|
imported_modules :: set(module_name),
|
|
|
|
% Modules which have been imported or used in the interface.
|
|
interface_visible_modules :: set(module_name),
|
|
|
|
% Sets of all modules, types, insts, modes, and typeclasses
|
|
% visible in this module. Impl_types is the set of all types
|
|
% visible from the implementation of the module.
|
|
modules :: module_id_set,
|
|
types :: type_id_set,
|
|
impl_types :: type_id_set,
|
|
insts :: inst_id_set,
|
|
modes :: mode_id_set,
|
|
classes :: class_id_set,
|
|
|
|
|
|
% Modules imported in the interface that are not definitely
|
|
% needed in the interface.
|
|
unused_interface_modules :: set(module_name),
|
|
|
|
% Import status of the current item.
|
|
import_status :: import_status,
|
|
|
|
% The number of errors found.
|
|
num_errors :: int,
|
|
|
|
% Are there any undefined types or typeclasses.
|
|
type_error_flag :: bool,
|
|
|
|
% Are there any undefined insts or modes.
|
|
mode_error_flag :: bool,
|
|
|
|
% Do we want to report errors.
|
|
report_error_flag :: bool,
|
|
|
|
% The context of the current item.
|
|
error_context :: error_context,
|
|
|
|
% The name of the current module
|
|
this_module :: module_name,
|
|
|
|
% Must uses of the current item be explicitly module qualified.
|
|
need_qual_flag :: need_qualifier,
|
|
|
|
maybe_recompilation_info :: maybe(recompilation_info)
|
|
).
|
|
|
|
:- type partial_qualifier_info
|
|
---> partial_qualifier_info(module_id_set).
|
|
|
|
mq_info_get_partial_qualifier_info(MQInfo, QualifierInfo) :-
|
|
mq_info_get_modules(MQInfo, ModuleIdSet),
|
|
QualifierInfo = partial_qualifier_info(ModuleIdSet).
|
|
|
|
% We only need to keep track of what is exported and what isn't,
|
|
% so we use a simpler data type here than hlds_pred.import_status.
|
|
%
|
|
:- type import_status
|
|
---> exported
|
|
; local
|
|
; imported(import_locn)
|
|
; abstract_imported.
|
|
|
|
% Pass over the item list collecting all defined module, type, mode and
|
|
% inst ids, all module synonym definitions, and the names of all
|
|
% modules imported in the interface.
|
|
%
|
|
:- pred collect_mq_info(item_list::in, mq_info::in, mq_info::out) is det.
|
|
|
|
collect_mq_info([], !Info).
|
|
collect_mq_info([Item - _ | Items], !Info) :-
|
|
( Item = module_defn(_, transitively_imported) ->
|
|
% Don't process the transitively imported items (from `.int2'
|
|
% files). They can't be used in the current module.
|
|
true
|
|
;
|
|
collect_mq_info_2(Item, !Info),
|
|
collect_mq_info(Items, !Info)
|
|
).
|
|
|
|
:- pred collect_mq_info_2(item::in, mq_info::in, mq_info::out) is det.
|
|
|
|
collect_mq_info_2(clause(_, _, _, _, _, _), !Info).
|
|
collect_mq_info_2(type_defn(_, SymName, Params, _, _), !Info) :-
|
|
% This item is not visible in the current module.
|
|
( mq_info_get_import_status(!.Info, abstract_imported) ->
|
|
true
|
|
;
|
|
list.length(Params, Arity),
|
|
mq_info_get_types(!.Info, Types0),
|
|
mq_info_get_impl_types(!.Info, ImplTypes0),
|
|
mq_info_get_need_qual_flag(!.Info, NeedQualifier),
|
|
id_set_insert(NeedQualifier, mq_id(SymName, Arity), Types0, Types),
|
|
id_set_insert(NeedQualifier, mq_id(SymName, Arity),
|
|
ImplTypes0, ImplTypes),
|
|
mq_info_set_types(Types, !Info),
|
|
mq_info_set_impl_types(ImplTypes, !Info)
|
|
).
|
|
collect_mq_info_2(inst_defn(_, SymName, Params, _, _), !Info) :-
|
|
% This item is not visible in the current module.
|
|
( mq_info_get_import_status(!.Info, abstract_imported) ->
|
|
true
|
|
;
|
|
list.length(Params, Arity),
|
|
mq_info_get_insts(!.Info, Insts0),
|
|
mq_info_get_need_qual_flag(!.Info, NeedQualifier),
|
|
id_set_insert(NeedQualifier, mq_id(SymName, Arity), Insts0, Insts),
|
|
mq_info_set_insts(Insts, !Info)
|
|
).
|
|
collect_mq_info_2(mode_defn(_, SymName, Params, _, _), !Info) :-
|
|
% This item is not visible in the current module.
|
|
( mq_info_get_import_status(!.Info, abstract_imported) ->
|
|
true
|
|
;
|
|
list.length(Params, Arity),
|
|
mq_info_get_modes(!.Info, Modes0),
|
|
mq_info_get_need_qual_flag(!.Info, NeedQualifier),
|
|
id_set_insert(NeedQualifier, mq_id(SymName, Arity), Modes0, Modes),
|
|
mq_info_set_modes(Modes, !Info)
|
|
).
|
|
collect_mq_info_2(module_defn(_, ModuleDefn), !Info) :-
|
|
process_module_defn(ModuleDefn, !Info).
|
|
collect_mq_info_2(pred_or_func(_, _, _, _, _, _, _, _, _, _, _, _), !Info).
|
|
collect_mq_info_2(pred_or_func_mode(_, _, _, _, _, _, _), !Info).
|
|
collect_mq_info_2(pragma(_, _), !Info).
|
|
collect_mq_info_2(promise(_PromiseType, Goal, _ProgVarSet, _UnivVars),
|
|
!Info) :-
|
|
process_assert(Goal, SymNames, Success),
|
|
(
|
|
Success = yes,
|
|
list.foldl(collect_mq_info_qualified_symname, SymNames, !Info)
|
|
;
|
|
% Any unqualified symbol in the promise might come
|
|
% from *any* of the imported modules. There's no way
|
|
% for us to tell which ones. So we conservatively
|
|
% assume that it uses all of them.
|
|
Success = no,
|
|
set.init(UnusedInterfaceModules),
|
|
mq_info_set_unused_interface_modules(UnusedInterfaceModules,
|
|
!Info)
|
|
).
|
|
collect_mq_info_2(nothing(_), !Info).
|
|
collect_mq_info_2(typeclass(_, _, SymName, Params, _, _), !Info) :-
|
|
% This item is not visible in the current module.
|
|
( mq_info_get_import_status(!.Info, abstract_imported) ->
|
|
true
|
|
;
|
|
list.length(Params, Arity),
|
|
mq_info_get_classes(!.Info, Classes0),
|
|
mq_info_get_need_qual_flag(!.Info, NeedQualifier),
|
|
id_set_insert(NeedQualifier, mq_id(SymName, Arity),
|
|
Classes0, Classes),
|
|
mq_info_set_classes(Classes, !Info)
|
|
).
|
|
collect_mq_info_2(instance(_, _, _, _, _, _), !Info).
|
|
collect_mq_info_2(initialise(_, _, _), !Info).
|
|
collect_mq_info_2(finalise(_, _, _), !Info).
|
|
collect_mq_info_2(mutable(_, _, _, _, _, _), !Info).
|
|
|
|
:- pred collect_mq_info_qualified_symname(sym_name::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
|
|
collect_mq_info_qualified_symname(SymName, !Info) :-
|
|
( SymName = qualified(ModuleName, _) ->
|
|
mq_info_set_module_used(ModuleName, !Info)
|
|
;
|
|
unexpected(this_file,
|
|
"collect_mq_info_qualified_symname: not qualified.")
|
|
).
|
|
|
|
% process_module_defn:
|
|
%
|
|
% - Update the import status.
|
|
%
|
|
% - For sub-module definitions (whether nested or separate,
|
|
% i.e. either `:- module foo.' or `:- include_module foo.'),
|
|
% add the module id to the module_id_set.
|
|
%
|
|
% - For import declarations (`:- import_module' or `:- use_module'),
|
|
% if we're currently in the interface section, then add the
|
|
% imported modules to the unused_interface_modules list.
|
|
%
|
|
:- pred process_module_defn(module_defn::in, mq_info::in, mq_info::out) is det.
|
|
|
|
process_module_defn(module(ModuleName), !Info) :-
|
|
add_module_defn(ModuleName, !Info).
|
|
process_module_defn(include_module(ModuleNameList), !Info) :-
|
|
list.foldl(add_module_defn, ModuleNameList, !Info).
|
|
process_module_defn(interface, !Info) :-
|
|
mq_info_set_import_status(exported, !Info).
|
|
process_module_defn(private_interface, !Info) :-
|
|
mq_info_set_import_status(local, !Info).
|
|
process_module_defn(implementation, !Info) :-
|
|
mq_info_set_import_status(local, !Info).
|
|
process_module_defn(imported(Locn), !Info) :-
|
|
mq_info_set_import_status(imported(Locn), !Info),
|
|
mq_info_set_need_qual_flag(may_be_unqualified, !Info).
|
|
process_module_defn(used(Locn), !Info) :-
|
|
mq_info_set_import_status(imported(Locn), !Info),
|
|
mq_info_set_need_qual_flag(must_be_qualified, !Info).
|
|
process_module_defn(opt_imported, !Info) :-
|
|
mq_info_set_import_status(imported(implementation), !Info),
|
|
mq_info_set_need_qual_flag(must_be_qualified, !Info).
|
|
process_module_defn(abstract_imported, !Info) :-
|
|
mq_info_set_import_status(abstract_imported, !Info),
|
|
mq_info_set_need_qual_flag(must_be_qualified, !Info).
|
|
process_module_defn(transitively_imported, !Info) :-
|
|
unexpected(this_file, "process_module_defn: transitively_imported item").
|
|
process_module_defn(external(_, _), !Info).
|
|
process_module_defn(end_module(_), !Info).
|
|
process_module_defn(export(_), !Info).
|
|
process_module_defn(import(Imports), !Info) :-
|
|
add_imports(Imports, !Info).
|
|
process_module_defn(use(Imports), !Info) :-
|
|
add_imports(Imports, !Info).
|
|
process_module_defn(version_numbers(_, _), !Info).
|
|
|
|
:- pred add_module_defn(module_name::in, mq_info::in, mq_info::out) is det.
|
|
|
|
add_module_defn(ModuleName, !Info) :-
|
|
mq_info_get_modules(!.Info, Modules0),
|
|
mq_info_get_need_qual_flag(!.Info, NeedQualifier),
|
|
Arity = 0,
|
|
id_set_insert(NeedQualifier, mq_id(ModuleName, Arity), Modules0, Modules),
|
|
mq_info_set_modules(Modules, !Info).
|
|
|
|
:- pred add_imports(sym_list::in, mq_info::in, mq_info::out) is det.
|
|
|
|
add_imports(Imports, !Info) :-
|
|
( Imports = module(ImportedModules) ->
|
|
add_imports_2(ImportedModules, !Info)
|
|
;
|
|
true
|
|
).
|
|
|
|
:- pred add_imports_2(list(sym_name)::in, mq_info::in, mq_info::out) is det.
|
|
|
|
add_imports_2(Imports, !Info) :-
|
|
mq_info_get_import_status(!.Info, Status),
|
|
|
|
%
|
|
% Modules imported from the the private interface of ancestors of
|
|
% the current module are treated as if they were directly imported
|
|
% by the current module.
|
|
%
|
|
(
|
|
( Status = local
|
|
; Status = exported
|
|
; Status = imported(ancestor_private_interface)
|
|
)
|
|
->
|
|
mq_info_get_imported_modules(!.Info, Modules0),
|
|
set.insert_list(Modules0, Imports, Modules),
|
|
mq_info_set_imported_modules(Modules, !Info)
|
|
;
|
|
true
|
|
),
|
|
|
|
%
|
|
% We check that all modules imported in the interface are
|
|
% used in the interface.
|
|
%
|
|
(
|
|
Status = exported
|
|
->
|
|
mq_info_get_unused_interface_modules(!.Info,
|
|
UnusedIntModules0),
|
|
set.insert_list(UnusedIntModules0, Imports, UnusedIntModules),
|
|
mq_info_set_unused_interface_modules(UnusedIntModules, !Info)
|
|
;
|
|
true
|
|
),
|
|
|
|
%
|
|
% Only modules imported in the interface or in the private
|
|
% interface of ancestor modules may be used in the interface.
|
|
%
|
|
(
|
|
( Status = exported
|
|
; Status = imported(ancestor_private_interface)
|
|
)
|
|
->
|
|
mq_info_get_interface_visible_modules(!.Info, IntModules0),
|
|
set.insert_list(IntModules0, Imports, IntModules),
|
|
mq_info_set_interface_visible_modules(IntModules, !Info)
|
|
;
|
|
true
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% process_assert(G, SNs, B)
|
|
%
|
|
% Scan the goal, G, building the list of qualified symbols, SNs.
|
|
% If there exists a single unqualified symbol in G, the bool, B,
|
|
% will be set to no.
|
|
%
|
|
:- pred process_assert(goal::in, list(sym_name)::out, bool::out) is det.
|
|
|
|
% AAA Some more stuff to do accumulator introduction on, it
|
|
% would be better to rewrite using maybes and then to declare
|
|
% the maybe_and predicate to be associative.
|
|
% NB. accumulator introduction doesn't work on this case yet.
|
|
%
|
|
process_assert(conj_expr(GA, GB) - _, Symbols, Success) :-
|
|
process_assert(GA, SymbolsA, SuccessA),
|
|
process_assert(GB, SymbolsB, SuccessB),
|
|
list.append(SymbolsA, SymbolsB, Symbols),
|
|
bool.and(SuccessA, SuccessB, Success).
|
|
process_assert(true_expr - _, [], yes).
|
|
process_assert(par_conj_expr(GA, GB) - _, Symbols, Success) :-
|
|
process_assert(GA, SymbolsA, SuccessA),
|
|
process_assert(GB, SymbolsB, SuccessB),
|
|
list.append(SymbolsA, SymbolsB, Symbols),
|
|
bool.and(SuccessA, SuccessB, Success).
|
|
process_assert(disj_expr(GA, GB) - _, Symbols, Success) :-
|
|
process_assert(GA, SymbolsA, SuccessA),
|
|
process_assert(GB, SymbolsB, SuccessB),
|
|
list.append(SymbolsA, SymbolsB, Symbols),
|
|
bool.and(SuccessA, SuccessB, Success).
|
|
process_assert(fail_expr - _, [], yes).
|
|
process_assert(some_expr(_, G) - _, Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(some_state_vars_expr(_, G) - _, Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(all_expr(_, G) - _, Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(all_state_vars_expr(_, G) - _, Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(promise_purity_expr(_I, _P, G) - _, Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(promise_equivalent_solutions_expr(_V, _D, _C, G) - _,
|
|
Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(promise_equivalent_solution_sets_expr(_V, _D, _C, G) - _,
|
|
Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(promise_equivalent_solution_arbitrary_expr(_V, _D, _C, G) - _,
|
|
Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(implies_expr(GA, GB) - _, Symbols, Success) :-
|
|
process_assert(GA, SymbolsA, SuccessA),
|
|
process_assert(GB, SymbolsB, SuccessB),
|
|
list.append(SymbolsA, SymbolsB, Symbols),
|
|
bool.and(SuccessA, SuccessB, Success).
|
|
process_assert(equivalent_expr(GA, GB) - _, Symbols, Success) :-
|
|
process_assert(GA, SymbolsA, SuccessA),
|
|
process_assert(GB, SymbolsB, SuccessB),
|
|
list.append(SymbolsA, SymbolsB, Symbols),
|
|
bool.and(SuccessA, SuccessB, Success).
|
|
process_assert(not_expr(G) - _, Symbols, Success) :-
|
|
process_assert(G, Symbols, Success).
|
|
process_assert(if_then_else_expr(_, _, GA, GB, GC) - _, Symbols, Success) :-
|
|
process_assert(GA, SymbolsA, SuccessA),
|
|
process_assert(GB, SymbolsB, SuccessB),
|
|
process_assert(GC, SymbolsC, SuccessC),
|
|
list.append(SymbolsA, SymbolsB, Symbols0),
|
|
list.append(Symbols0, SymbolsC, Symbols),
|
|
bool.and(SuccessA, SuccessB, Success0),
|
|
bool.and(Success0, SuccessC, Success).
|
|
process_assert(call_expr(SymName, Args0, _Purity) - _, Symbols, Success) :-
|
|
( SymName = qualified(_, _) ->
|
|
list.map(term.coerce, Args0, Args),
|
|
( term_qualified_symbols_list(Args, Symbols0) ->
|
|
Symbols = [SymName | Symbols0],
|
|
Success = yes
|
|
;
|
|
Symbols = [],
|
|
Success = no
|
|
)
|
|
;
|
|
Symbols = [],
|
|
Success = no
|
|
).
|
|
process_assert(unify_expr(LHS0, RHS0, _Purity) - _, Symbols, Success) :-
|
|
term.coerce(LHS0, LHS),
|
|
term.coerce(RHS0, RHS),
|
|
(
|
|
term_qualified_symbols(LHS, SymbolsL),
|
|
term_qualified_symbols(RHS, SymbolsR)
|
|
->
|
|
list.append(SymbolsL, SymbolsR, Symbols),
|
|
Success = yes
|
|
;
|
|
Symbols = [],
|
|
Success = no
|
|
).
|
|
|
|
% term_qualified_symbols(T, S)
|
|
%
|
|
% Given a term, T, return the list of all the sym_names, S, in the
|
|
% term. The predicate fails if any sub-term of T is unqualified.
|
|
%
|
|
:- pred term_qualified_symbols(term::in, list(sym_name)::out) is semidet.
|
|
|
|
term_qualified_symbols(Term, Symbols) :-
|
|
( sym_name_and_args(Term, SymName, Args) ->
|
|
SymName = qualified(_, _),
|
|
term_qualified_symbols_list(Args, Symbols0),
|
|
Symbols = [SymName | Symbols0]
|
|
;
|
|
Symbols = []
|
|
).
|
|
|
|
:- pred term_qualified_symbols_list(list(term)::in, list(sym_name)::out)
|
|
is semidet.
|
|
|
|
% Yeah one more place where accumulators will be introduced!
|
|
term_qualified_symbols_list([], []).
|
|
term_qualified_symbols_list([Term | Terms], Symbols) :-
|
|
term_qualified_symbols(Term, TermSymbols),
|
|
term_qualified_symbols_list(Terms, Symbols0),
|
|
list.append(Symbols0, TermSymbols, Symbols).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Iterate over the item list module qualifying all declarations.
|
|
% Stop when the :- imported or :- opt_imported pseudo-declaration
|
|
% is reached, since imported declarations should already be
|
|
% module qualified.
|
|
%
|
|
:- pred do_module_qualify_items(item_list::in, item_list::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
do_module_qualify_items([], [], !Info, !IO).
|
|
do_module_qualify_items([Item0 | Items0], [Item | Items], !Info, !IO) :-
|
|
module_qualify_item(Item0, Item, !Info, Continue, !IO),
|
|
(
|
|
Continue = yes,
|
|
do_module_qualify_items(Items0, Items, !Info, !IO)
|
|
;
|
|
Continue = no,
|
|
Items = Items0
|
|
).
|
|
|
|
% Call predicates to qualify a single item.
|
|
%
|
|
:- pred module_qualify_item(item_and_context::in, item_and_context::out,
|
|
mq_info::in, mq_info::out, bool::out, io::di, io::uo) is det.
|
|
|
|
module_qualify_item(Clause @ (clause(_,_,_,_,_,_) - _), Clause, !Info, yes,
|
|
!IO).
|
|
|
|
module_qualify_item(
|
|
type_defn(TVarSet, SymName, Params, TypeDefn0, C) - Context,
|
|
type_defn(TVarSet, SymName, Params, TypeDefn, C) - Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(Params, Arity),
|
|
mq_info_set_error_context(mqec_type(mq_id(SymName, Arity)) - Context,
|
|
!Info),
|
|
qualify_type_defn(TypeDefn0, TypeDefn, !Info, !IO).
|
|
|
|
module_qualify_item(inst_defn(A, SymName, Params, InstDefn0, C) - Context,
|
|
inst_defn(A, SymName, Params, InstDefn, C) - Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(Params, Arity),
|
|
mq_info_set_error_context(mqec_inst(mq_id(SymName, Arity)) - Context,
|
|
!Info),
|
|
qualify_inst_defn(InstDefn0, InstDefn, !Info, !IO).
|
|
|
|
module_qualify_item(mode_defn(A, SymName, Params, ModeDefn0, C) - Context,
|
|
mode_defn(A, SymName, Params, ModeDefn, C) - Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(Params, Arity),
|
|
mq_info_set_error_context(mqec_mode(mq_id(SymName, Arity)) - Context,
|
|
!Info),
|
|
qualify_mode_defn(ModeDefn0, ModeDefn, !Info, !IO).
|
|
|
|
module_qualify_item(module_defn(A, ModuleDefn) - Context,
|
|
module_defn(A, ModuleDefn) - Context, !Info, Continue, !IO) :-
|
|
update_import_status(ModuleDefn, !Info, Continue).
|
|
|
|
module_qualify_item(
|
|
pred_or_func(A, IVs, B, PredOrFunc, SymName, TypesAndModes0,
|
|
WithType0, WithInst0, C, D, E, Constraints0) - Context,
|
|
pred_or_func(A, IVs, B, PredOrFunc, SymName, TypesAndModes,
|
|
WithType, WithInst, C, D, E, Constraints) - Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(TypesAndModes0, Arity),
|
|
mq_info_set_error_context(
|
|
mqec_pred_or_func(PredOrFunc, mq_id(SymName, Arity)) - Context, !Info),
|
|
qualify_types_and_modes(TypesAndModes0, TypesAndModes, !Info, !IO),
|
|
qualify_prog_constraints(Constraints0, Constraints, !Info, !IO),
|
|
map_fold2_maybe(qualify_type, WithType0, WithType, !Info, !IO),
|
|
map_fold2_maybe(qualify_inst, WithInst0, WithInst, !Info, !IO).
|
|
|
|
module_qualify_item(
|
|
pred_or_func_mode(A, PredOrFunc, SymName, Modes0,
|
|
WithInst0, C, D) - Context,
|
|
pred_or_func_mode(A, PredOrFunc, SymName, Modes,
|
|
WithInst, C, D) - Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(Modes0, Arity),
|
|
mq_info_set_error_context(
|
|
mqec_pred_or_func_mode(PredOrFunc, mq_id(SymName, Arity)) - Context,
|
|
!Info),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO),
|
|
map_fold2_maybe(qualify_inst, WithInst0, WithInst, !Info, !IO).
|
|
module_qualify_item(Item0, Item, !Info, yes, !IO) :-
|
|
Item0 = pragma(Origin, Pragma0) - Context,
|
|
mq_info_set_error_context(mqec_pragma - Context, !Info),
|
|
qualify_pragma(Pragma0, Pragma, !Info, !IO),
|
|
Item = pragma(Origin, Pragma) - Context.
|
|
module_qualify_item(promise(T, G, V, U) - Context,
|
|
promise(T, G, V, U) - Context, !Info, yes, !IO).
|
|
module_qualify_item(nothing(A) - Context, nothing(A) - Context,
|
|
!Info, yes, !IO).
|
|
module_qualify_item(typeclass(Constraints0, FunDeps, Name, Vars, Interface0,
|
|
VarSet) - Context,
|
|
typeclass(Constraints, FunDeps, Name, Vars, Interface, VarSet)
|
|
- Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(Vars, Arity),
|
|
mq_info_set_error_context(mqec_class(mq_id(Name, Arity)) - Context, !Info),
|
|
qualify_prog_constraint_list(Constraints0, Constraints, !Info, !IO),
|
|
(
|
|
Interface0 = abstract,
|
|
Interface = abstract
|
|
;
|
|
Interface0 = concrete(Methods0),
|
|
qualify_class_interface(Methods0, Methods, !Info, !IO),
|
|
Interface = concrete(Methods)
|
|
).
|
|
|
|
module_qualify_item(
|
|
instance(Constraints0, Name0, Types0, Body0, VarSet,
|
|
ModName) - Context,
|
|
instance(Constraints, Name, Types, Body, VarSet,
|
|
ModName) - Context,
|
|
!Info, yes, !IO) :-
|
|
list.length(Types0, Arity),
|
|
Id = mq_id(Name0, Arity),
|
|
mq_info_set_error_context(mqec_instance(Id) - Context, !Info),
|
|
|
|
% We don't qualify the implementation yet, since that requires
|
|
% us to resolve overloading.
|
|
qualify_prog_constraint_list(Constraints0, Constraints, !Info, !IO),
|
|
qualify_class_name(Id, mq_id(Name, _), !Info, !IO),
|
|
qualify_type_list(Types0, Types, !Info, !IO),
|
|
qualify_instance_body(Name, Body0, Body).
|
|
|
|
module_qualify_item(
|
|
initialise(Origin, PredSymName, Arity) - Context,
|
|
initialise(Origin, PredSymName, Arity) - Context,
|
|
!Info, yes, !IO).
|
|
|
|
module_qualify_item(
|
|
finalise(Origin, PredSymName, Arity) - Context,
|
|
finalise(Origin, PredSymName, Arity) - Context,
|
|
!Info, yes, !IO).
|
|
|
|
module_qualify_item(
|
|
mutable(Name, Type0, InitTerm, Inst0, Attrs, Varset) - Context,
|
|
mutable(Name, Type, InitTerm, Inst, Attrs, Varset) - Context,
|
|
!Info, yes, !IO) :-
|
|
mq_info_set_error_context(mqec_mutable(Name) - Context, !Info),
|
|
qualify_type(Type0, Type, !Info, !IO),
|
|
qualify_inst(Inst0, Inst, !Info, !IO).
|
|
|
|
:- pred update_import_status(module_defn::in, mq_info::in, mq_info::out,
|
|
bool::out) is det.
|
|
|
|
update_import_status(opt_imported, !Info, no).
|
|
update_import_status(abstract_imported, !Info, yes) :-
|
|
mq_info_set_import_status(abstract_imported, !Info).
|
|
update_import_status(transitively_imported, !Info, no).
|
|
update_import_status(module(_), !Info, yes).
|
|
update_import_status(interface, !Info, yes) :-
|
|
mq_info_set_import_status(exported, !Info).
|
|
update_import_status(implementation, !Info, yes) :-
|
|
mq_info_set_import_status(local, !Info).
|
|
update_import_status(private_interface, !Info, yes) :-
|
|
mq_info_set_import_status(local, !Info).
|
|
update_import_status(imported(_), !Info, no).
|
|
update_import_status(used(_), !Info, no).
|
|
update_import_status(external(_, _), !Info, yes).
|
|
update_import_status(end_module(_), !Info, yes).
|
|
update_import_status(export(_), !Info, yes).
|
|
update_import_status(import(_), !Info, yes).
|
|
update_import_status(use(_), !Info, yes).
|
|
update_import_status(version_numbers(_, _), !Info, yes).
|
|
update_import_status(include_module(_), !Info, yes) :-
|
|
% The sub-module might make use of *any* of the imported modules.
|
|
% There's no way for us to tell which ones.
|
|
% So we conservatively assume that it uses all of them.
|
|
set.init(UnusedInterfaceModules),
|
|
mq_info_set_unused_interface_modules(UnusedInterfaceModules, !Info).
|
|
|
|
% Qualify the constructors or other types in a type definition.
|
|
%
|
|
:- pred qualify_type_defn(type_defn::in, type_defn::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_type_defn(du_type(Ctors0, MaybeUserEqComp0),
|
|
du_type(Ctors, MaybeUserEqComp),
|
|
!Info, !IO) :-
|
|
qualify_constructors(Ctors0, Ctors, !Info, !IO),
|
|
%
|
|
% 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.
|
|
qualify_type_defn(eqv_type(Type0), eqv_type(Type), !Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO).
|
|
qualify_type_defn(abstract_type(_) @ Defn, Defn, !Info, !IO).
|
|
qualify_type_defn(foreign_type(_, _, _) @ Defn, Defn, !Info, !IO).
|
|
qualify_type_defn(solver_type(SolverTypeDetails0, MaybeUserEqComp),
|
|
solver_type(SolverTypeDetails, MaybeUserEqComp),
|
|
!Info, !IO) :-
|
|
SolverTypeDetails0 = solver_type_details(RepnType0, InitPred,
|
|
GroundInst0, AnyInst0, MutableItems),
|
|
qualify_type(RepnType0, RepnType, !Info, !IO),
|
|
qualify_inst(GroundInst0, GroundInst, !Info, !IO),
|
|
qualify_inst(AnyInst0, AnyInst, !Info, !IO),
|
|
SolverTypeDetails = solver_type_details(RepnType, InitPred,
|
|
GroundInst, AnyInst, MutableItems).
|
|
|
|
:- pred qualify_constructors(list(constructor)::in, list(constructor)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_constructors([], [], !Info, !IO).
|
|
qualify_constructors([Ctor0 | Ctors0], [Ctor | Ctors], !Info, !IO) :-
|
|
Ctor0 = ctor(ExistQVars, Constraints0, SymName, Args0),
|
|
qualify_constructor_arg_list(Args0, Args, !Info, !IO),
|
|
qualify_constructors(Ctors0, Ctors, !Info, !IO),
|
|
qualify_prog_constraint_list(Constraints0, Constraints, !Info, !IO),
|
|
Ctor = ctor(ExistQVars, Constraints, SymName, Args).
|
|
|
|
% Qualify the inst parameters of an inst definition.
|
|
%
|
|
:- pred qualify_inst_defn(inst_defn::in, inst_defn::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_inst_defn(eqv_inst(Inst0), eqv_inst(Inst), !Info, !IO) :-
|
|
qualify_inst(Inst0, Inst, !Info, !IO).
|
|
qualify_inst_defn(abstract_inst, abstract_inst, !Info, !IO).
|
|
|
|
% Qualify the mode parameter of an equivalence mode definition.
|
|
%
|
|
:- pred qualify_mode_defn(mode_defn::in, mode_defn::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_mode_defn(eqv_mode(Mode0), eqv_mode(Mode), !Info, !IO) :-
|
|
qualify_mode(Mode0, Mode, !Info, !IO).
|
|
|
|
% Qualify a list of items of the form Type::Mode, as in a
|
|
% predicate declaration.
|
|
%
|
|
:- pred qualify_types_and_modes(list(type_and_mode)::in,
|
|
list(type_and_mode)::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_types_and_modes([], [], !Info, !IO).
|
|
qualify_types_and_modes([TypeAndMode0 | TypesAndModes0],
|
|
[TypeAndMode | TypesAndModes], !Info, !IO) :-
|
|
qualify_type_and_mode(TypeAndMode0, TypeAndMode, !Info, !IO),
|
|
qualify_types_and_modes(TypesAndModes0, TypesAndModes, !Info, !IO).
|
|
|
|
:- pred qualify_type_and_mode(type_and_mode::in, type_and_mode::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_type_and_mode(type_only(Type0), type_only(Type), !Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO).
|
|
|
|
qualify_type_and_mode(type_and_mode(Type0, Mode0), type_and_mode(Type, Mode),
|
|
!Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO),
|
|
qualify_mode(Mode0, Mode, !Info, !IO).
|
|
|
|
:- pred qualify_mode_list(list(mer_mode)::in, list(mer_mode)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_mode_list([], [], !Info, !IO).
|
|
qualify_mode_list([Mode0 | Modes0], [Mode | Modes], !Info, !IO) :-
|
|
qualify_mode(Mode0, Mode, !Info, !IO),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO).
|
|
|
|
:- pred qualify_mode(mer_mode::in, mer_mode::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_mode((InstA0 -> InstB0), (InstA -> InstB), !Info, !IO) :-
|
|
qualify_inst(InstA0, InstA, !Info, !IO),
|
|
qualify_inst(InstB0, InstB, !Info, !IO).
|
|
|
|
qualify_mode(user_defined_mode(SymName0, Insts0),
|
|
user_defined_mode(SymName, Insts), !Info, !IO) :-
|
|
qualify_inst_list(Insts0, Insts, !Info, !IO),
|
|
list.length(Insts, Arity),
|
|
mq_info_get_modes(!.Info, Modes),
|
|
find_unique_match(mq_id(SymName0, Arity), mq_id(SymName, _),
|
|
Modes, mode_id, !Info, !IO).
|
|
|
|
:- pred qualify_inst_list(list(mer_inst)::in, list(mer_inst)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_inst_list([], [], !Info, !IO).
|
|
qualify_inst_list([Inst0 | Insts0], [Inst | Insts], !Info, !IO) :-
|
|
qualify_inst(Inst0, Inst, !Info, !IO),
|
|
qualify_inst_list(Insts0, Insts, !Info, !IO).
|
|
|
|
% Qualify a single inst.
|
|
%
|
|
:- pred qualify_inst(mer_inst::in, mer_inst::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_inst(any(A), any(A), !Info, !IO).
|
|
qualify_inst(free, free, !Info, !IO).
|
|
qualify_inst(not_reached, not_reached, !Info, !IO).
|
|
qualify_inst(free(_), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst not expected").
|
|
qualify_inst(bound(Uniq, BoundInsts0), bound(Uniq, BoundInsts), !Info, !IO) :-
|
|
qualify_bound_inst_list(BoundInsts0, BoundInsts, !Info, !IO).
|
|
qualify_inst(ground(Uniq, GroundInstInfo0), ground(Uniq, GroundInstInfo),
|
|
!Info, !IO) :-
|
|
(
|
|
GroundInstInfo0 = higher_order(pred_inst_info(A, Modes0, Det)),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO),
|
|
GroundInstInfo = higher_order(pred_inst_info(A, Modes, Det))
|
|
;
|
|
GroundInstInfo0 = none,
|
|
GroundInstInfo = none
|
|
).
|
|
qualify_inst(inst_var(Var), inst_var(Var), !Info, !IO).
|
|
qualify_inst(constrained_inst_vars(Vars, Inst0),
|
|
constrained_inst_vars(Vars, Inst), !Info, !IO) :-
|
|
qualify_inst(Inst0, Inst, !Info, !IO).
|
|
qualify_inst(defined_inst(InstName0), defined_inst(InstName), !Info, !IO) :-
|
|
qualify_inst_name(InstName0, InstName, !Info, !IO).
|
|
qualify_inst(abstract_inst(Name, Args0), abstract_inst(Name, Args), !Info,
|
|
!IO) :-
|
|
qualify_inst_list(Args0, Args, !Info, !IO).
|
|
|
|
% Find the unique inst_id that matches this inst, and qualify
|
|
% the argument insts.
|
|
%
|
|
:- pred qualify_inst_name(inst_name::in, inst_name::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_inst_name(user_inst(SymName0, Insts0), user_inst(SymName, Insts),
|
|
!Info, !IO) :-
|
|
qualify_inst_list(Insts0, Insts, !Info, !IO),
|
|
(
|
|
% Check for a variable inst constructor.
|
|
SymName0 = unqualified("")
|
|
->
|
|
mq_info_get_error_context(!.Info, ErrorContext),
|
|
report_invalid_user_inst(SymName0, Insts, ErrorContext, !IO),
|
|
mq_info_set_error_flag(inst_id, !Info),
|
|
mq_info_incr_errors(!Info),
|
|
SymName = SymName0
|
|
;
|
|
list.length(Insts0, Arity),
|
|
mq_info_get_insts(!.Info, InstIds),
|
|
find_unique_match(mq_id(SymName0, Arity), mq_id(SymName, _),
|
|
InstIds, inst_id, !Info, !IO)
|
|
).
|
|
qualify_inst_name(merge_inst(_, _), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(unify_inst(_, _, _, _), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(ground_inst(_, _, _, _), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(any_inst(_, _, _, _), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(shared_inst(_), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(mostly_uniq_inst(_), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(typed_ground(_, _), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
qualify_inst_name(typed_inst(_, _), _, !Info, !IO) :-
|
|
unexpected(this_file, "compiler generated inst unexpected").
|
|
|
|
% Qualify an inst of the form bound(functor(...)).
|
|
%
|
|
:- pred qualify_bound_inst_list(list(bound_inst)::in, list(bound_inst)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_bound_inst_list([], [], !Info, !IO).
|
|
qualify_bound_inst_list([functor(ConsId, Insts0) | BoundInsts0],
|
|
[functor(ConsId, Insts) | BoundInsts], !Info, !IO) :-
|
|
( ConsId = cons(Name, Arity) ->
|
|
Id = item_name(Name, Arity),
|
|
update_recompilation_info(
|
|
recompilation.record_used_item(functor_item, Id, Id), !Info)
|
|
;
|
|
true
|
|
),
|
|
qualify_inst_list(Insts0, Insts, !Info, !IO),
|
|
qualify_bound_inst_list(BoundInsts0, BoundInsts, !Info, !IO).
|
|
|
|
:- pred qualify_constructor_arg_list(list(constructor_arg)::in,
|
|
list(constructor_arg)::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_constructor_arg_list([], [], !Info, !IO).
|
|
qualify_constructor_arg_list([Name - Type0 | Args0], [Name - Type | Args],
|
|
!Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO),
|
|
qualify_constructor_arg_list(Args0, Args, !Info, !IO).
|
|
|
|
:- pred qualify_type_list(list(mer_type)::in, list(mer_type)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_type_list([], [], !Info, !IO).
|
|
qualify_type_list([Type0 | Types0], [Type | Types], !Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO),
|
|
qualify_type_list(Types0, Types, !Info, !IO).
|
|
|
|
:- pred qualify_maybe_type(maybe(mer_type)::in, maybe(mer_type)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_maybe_type(no, no, !Info, !IO).
|
|
qualify_maybe_type(yes(Type0), yes(Type), !Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO).
|
|
|
|
% Qualify a type and its argument types.
|
|
%
|
|
:- pred qualify_type(mer_type::in, mer_type::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_type(variable(Var, Kind), variable(Var, Kind), !Info, !IO).
|
|
qualify_type(defined(SymName0, Args0, Kind), defined(SymName, Args, Kind),
|
|
!Info, !IO) :-
|
|
Arity = list.length(Args0),
|
|
TypeCtorId0 = mq_id(SymName0, Arity),
|
|
mq_info_get_types(!.Info, Types),
|
|
find_unique_match(TypeCtorId0, TypeCtorId, Types, type_id, !Info, !IO),
|
|
TypeCtorId = mq_id(SymName, _),
|
|
qualify_type_list(Args0, Args, !Info, !IO).
|
|
qualify_type(builtin(BuiltinType), builtin(BuiltinType), !Info, !IO) :-
|
|
%
|
|
% 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 = int,
|
|
mq_info_set_module_used(unqualified("int"), !Info)
|
|
;
|
|
BuiltinType = float,
|
|
mq_info_set_module_used(unqualified("float"), !Info)
|
|
;
|
|
BuiltinType = string,
|
|
mq_info_set_module_used(unqualified("string"), !Info)
|
|
;
|
|
BuiltinType = character
|
|
).
|
|
qualify_type(higher_order(Args0, MaybeRet0, Purity, EvalMethod),
|
|
higher_order(Args, MaybeRet, Purity, EvalMethod), !Info, !IO) :-
|
|
qualify_type_list(Args0, Args, !Info, !IO),
|
|
qualify_maybe_type(MaybeRet0, MaybeRet, !Info, !IO).
|
|
qualify_type(tuple(Args0, Kind), tuple(Args, Kind), !Info, !IO) :-
|
|
qualify_type_list(Args0, Args, !Info, !IO).
|
|
qualify_type(apply_n(Var, Args0, Kind), apply_n(Var, Args, Kind), !Info,
|
|
!IO) :-
|
|
qualify_type_list(Args0, Args, !Info, !IO).
|
|
qualify_type(kinded(Type0, Kind), kinded(Type, Kind), !Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO).
|
|
|
|
% Qualify the modes in a pragma c_code(...) decl.
|
|
%
|
|
:- pred qualify_pragma((pragma_type)::in, (pragma_type)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_pragma(X@source_file(_), X, !Info, !IO).
|
|
qualify_pragma(X@foreign_decl(_, _, _), X, !Info, !IO).
|
|
qualify_pragma(X@foreign_code(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@foreign_import_module(_, _), X, !Info, !IO).
|
|
qualify_pragma(X, Y, !Info, !IO) :-
|
|
PragmaVars0 = X ^ proc_vars,
|
|
qualify_pragma_vars(PragmaVars0, PragmaVars, !Info, !IO),
|
|
Y = X ^ proc_vars := PragmaVars.
|
|
qualify_pragma(tabled(A, B, C, D, MModes0), tabled(A, B, C, D, MModes),
|
|
!Info, !IO) :-
|
|
(
|
|
MModes0 = yes(Modes0),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO),
|
|
MModes = yes(Modes)
|
|
;
|
|
MModes0 = no,
|
|
MModes = no
|
|
).
|
|
qualify_pragma(X@inline(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@no_inline(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@obsolete(_, _), X, !Info, !IO).
|
|
qualify_pragma(import(Name, PredOrFunc, Modes0, Attributes, CFunc),
|
|
import(Name, PredOrFunc, Modes, Attributes, CFunc),
|
|
!Info, !IO) :-
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO).
|
|
qualify_pragma(export(Name, PredOrFunc, Modes0, CFunc),
|
|
export(Name, PredOrFunc, Modes, CFunc), !Info, !IO) :-
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO).
|
|
qualify_pragma(X@unused_args(_, _, _, _, _), X, !Info, !IO).
|
|
qualify_pragma(X@exceptions(_, _, _, _, _), X, !Info, !IO).
|
|
qualify_pragma(X@trailing_info(_, _, _, _, _), X, !Info, !IO).
|
|
qualify_pragma(type_spec(A, B, C, D, MaybeModes0, Subst0, G, H),
|
|
type_spec(A, B, C, D, MaybeModes, Subst, G, H),
|
|
!Info, !IO) :-
|
|
(
|
|
MaybeModes0 = yes(Modes0),
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO),
|
|
MaybeModes = yes(Modes)
|
|
;
|
|
MaybeModes0 = no,
|
|
MaybeModes = no
|
|
),
|
|
qualify_type_spec_subst(Subst0, Subst, !Info, !IO).
|
|
qualify_pragma(X@fact_table(_, _, _), X, !Info, !IO).
|
|
qualify_pragma(X@reserve_tag(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@promise_pure(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@promise_semipure(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@promise_equivalent_clauses(_, _), X, !Info, !IO).
|
|
qualify_pragma(termination_info(PredOrFunc, SymName, ModeList0, Args, Term),
|
|
termination_info(PredOrFunc, SymName, ModeList, Args, Term),
|
|
!Info, !IO) :-
|
|
qualify_mode_list(ModeList0, ModeList, !Info, !IO).
|
|
qualify_pragma(structure_sharing(PredOrFunc, SymName, ModeList0, Vars, Types,
|
|
Sharing),
|
|
structure_sharing(PredOrFunc, SymName, ModeList, Vars, Types, Sharing),
|
|
!Info, !IO) :-
|
|
qualify_mode_list(ModeList0, ModeList, !Info, !IO).
|
|
qualify_pragma(structure_reuse(PredOrFunc, SymName, ModeList0, Vars, Types,
|
|
ReuseTuples, ReuseName),
|
|
structure_reuse(PredOrFunc, SymName, ModeList, Vars, Types,
|
|
ReuseTuples, ReuseName),
|
|
!Info, !IO) :-
|
|
qualify_mode_list(ModeList0, ModeList, !Info, !IO).
|
|
qualify_pragma(termination2_info(PredOrFunc, SymName, ModeList0,
|
|
SuccessArgs, FailureArgs, Term),
|
|
termination2_info(PredOrFunc, SymName, ModeList,
|
|
SuccessArgs, FailureArgs, Term),
|
|
!Info, !IO) :-
|
|
qualify_mode_list(ModeList0, ModeList, !Info, !IO).
|
|
qualify_pragma(X@terminates(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@does_not_terminate(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@check_termination(_, _), X, !Info, !IO).
|
|
qualify_pragma(X@mode_check_clauses(_, _), X, !Info, !IO).
|
|
|
|
:- pred qualify_pragma_vars(list(pragma_var)::in, list(pragma_var)::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_pragma_vars([], [], !Info, !IO).
|
|
qualify_pragma_vars([pragma_var(Var, Name, Mode0, Box) | PragmaVars0],
|
|
[pragma_var(Var, Name, Mode, Box) | PragmaVars], !Info, !IO) :-
|
|
qualify_mode(Mode0, Mode, !Info, !IO),
|
|
qualify_pragma_vars(PragmaVars0, PragmaVars, !Info, !IO).
|
|
|
|
:- pred qualify_type_spec_subst(assoc_list(tvar, mer_type)::in,
|
|
assoc_list(tvar, mer_type)::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_type_spec_subst([], [], !Info, !IO).
|
|
qualify_type_spec_subst([Var - Type0 | Subst0], [Var - Type | Subst],
|
|
!Info, !IO) :-
|
|
qualify_type(Type0, Type, !Info, !IO),
|
|
qualify_type_spec_subst(Subst0, Subst, !Info, !IO).
|
|
|
|
:- pred qualify_prog_constraints(prog_constraints::in,
|
|
prog_constraints::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_prog_constraints(constraints(UnivCs0, ExistCs0),
|
|
constraints(UnivCs, ExistCs), !Info, !IO) :-
|
|
qualify_prog_constraint_list(UnivCs0, UnivCs, !Info, !IO),
|
|
qualify_prog_constraint_list(ExistCs0, ExistCs, !Info, !IO).
|
|
|
|
:- pred qualify_prog_constraint_list(list(prog_constraint)::in,
|
|
list(prog_constraint)::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_prog_constraint_list([], [], !Info, !IO).
|
|
qualify_prog_constraint_list([C0 | C0s], [C | Cs], !Info, !IO) :-
|
|
qualify_prog_constraint(C0, C, !Info, !IO),
|
|
qualify_prog_constraint_list(C0s, Cs, !Info, !IO).
|
|
|
|
:- pred qualify_prog_constraint(prog_constraint::in, prog_constraint::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_prog_constraint(constraint(ClassName0, Types0),
|
|
constraint(ClassName, Types), !Info, !IO) :-
|
|
list.length(Types0, Arity),
|
|
qualify_class_name(mq_id(ClassName0, Arity), mq_id(ClassName, _),
|
|
!Info, !IO),
|
|
qualify_type_list(Types0, Types, !Info, !IO).
|
|
|
|
:- pred qualify_class_name(mq_id::in, mq_id::out, mq_info::in, mq_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
qualify_class_name(Class0, Class, !Info, !IO) :-
|
|
mq_info_get_classes(!.Info, ClassIdSet),
|
|
find_unique_match(Class0, Class, ClassIdSet, class_id, !Info, !IO).
|
|
|
|
:- pred qualify_class_interface(class_methods::in, class_methods::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
qualify_class_interface([], [], !Info, !IO).
|
|
qualify_class_interface([M0 | M0s], [M | Ms], !Info, !IO) :-
|
|
qualify_class_method(M0, M, !Info, !IO),
|
|
qualify_class_interface(M0s, Ms, !Info, !IO).
|
|
|
|
:- pred qualify_class_method(class_method::in, class_method::out,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
% There is no need to qualify the method name, since that is
|
|
% done when the item is parsed.
|
|
qualify_class_method(
|
|
pred_or_func(TypeVarset, InstVarset, ExistQVars, PredOrFunc,
|
|
Name, TypesAndModes0, WithType0, WithInst0, MaybeDet,
|
|
Cond, Purity, ClassContext0, Context),
|
|
pred_or_func(TypeVarset, InstVarset, ExistQVars, PredOrFunc,
|
|
Name, TypesAndModes, WithType, WithInst, MaybeDet,
|
|
Cond, Purity, ClassContext, Context),
|
|
!Info, !IO) :-
|
|
qualify_types_and_modes(TypesAndModes0, TypesAndModes, !Info, !IO),
|
|
qualify_prog_constraints(ClassContext0, ClassContext, !Info, !IO),
|
|
map_fold2_maybe(qualify_type, WithType0, WithType, !Info, !IO),
|
|
map_fold2_maybe(qualify_inst, WithInst0, WithInst, !Info, !IO).
|
|
qualify_class_method(
|
|
pred_or_func_mode(Varset, PredOrFunc, Name, Modes0,
|
|
WithInst0, MaybeDet, Cond, Context),
|
|
pred_or_func_mode(Varset, PredOrFunc, Name, Modes,
|
|
WithInst, MaybeDet, Cond, Context),
|
|
!Info, !IO) :-
|
|
qualify_mode_list(Modes0, Modes, !Info, !IO),
|
|
map_fold2_maybe(qualify_inst, WithInst0, WithInst, !Info, !IO).
|
|
|
|
:- pred qualify_instance_body(sym_name::in, instance_body::in,
|
|
instance_body::out) is det.
|
|
|
|
qualify_instance_body(_ClassName, abstract, abstract).
|
|
qualify_instance_body(ClassName, concrete(M0s), concrete(Ms)) :-
|
|
( ClassName = unqualified(_) ->
|
|
Ms = M0s
|
|
;
|
|
sym_name_get_module_name(ClassName, unqualified(""), Module),
|
|
Qualify = (pred(M0::in, M::out) is det :-
|
|
M0 = instance_method(A, Method0, C, D, E),
|
|
add_module_qualifier(Module, Method0, Method),
|
|
M = instance_method(A, Method, C, D, E)
|
|
),
|
|
list.map(Qualify, M0s, Ms)
|
|
).
|
|
|
|
:- pred add_module_qualifier(sym_name::in, sym_name::in, sym_name::out) is det.
|
|
|
|
add_module_qualifier(Module, unqualified(SymName), qualified(Module, SymName)).
|
|
add_module_qualifier(DefaultModule, qualified(SymModule, SymName),
|
|
qualified(Module, SymName)) :-
|
|
( match_sym_name(SymModule, DefaultModule) ->
|
|
Module = DefaultModule
|
|
;
|
|
% 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.
|
|
|
|
Module = SymModule
|
|
).
|
|
|
|
% Find the unique match in the current name space for a given mq_id
|
|
% from a list of ids. If none exists, either because no match
|
|
% was found or multiple matches were found, report an error.
|
|
% This predicate assumes that type_ids, inst_ids, mode_ids and
|
|
% class_ids have the same representation.
|
|
%
|
|
:- pred find_unique_match(mq_id::in, mq_id::out, id_set::in, id_type::in,
|
|
mq_info::in, mq_info::out, io::di, io::uo) is det.
|
|
|
|
find_unique_match(Id0, Id, Ids, TypeOfId, !Info, !IO) :-
|
|
|
|
% Find all IDs which match the current id.
|
|
Id0 = mq_id(SymName0, Arity),
|
|
mq_info_get_modules(!.Info, Modules),
|
|
id_set_search_sym_arity(Ids, SymName0, Arity, Modules, MatchingModules0),
|
|
|
|
( mq_info_get_import_status(!.Info, exported) ->
|
|
% Items in the interface may only refer to modules
|
|
% imported in the interface.
|
|
mq_info_get_interface_visible_modules(!.Info, InterfaceImports),
|
|
list.filter(set.contains(InterfaceImports),
|
|
MatchingModules0, MatchingModules)
|
|
;
|
|
MatchingModules = MatchingModules0
|
|
),
|
|
|
|
(
|
|
MatchingModules = [],
|
|
% No matches for this id.
|
|
Id = Id0,
|
|
( mq_info_get_report_error_flag(!.Info, yes) ->
|
|
report_undefined(MatchingModules0, !.Info, Id0,
|
|
TypeOfId, !IO),
|
|
mq_info_set_error_flag(TypeOfId, !Info),
|
|
mq_info_incr_errors(!Info)
|
|
;
|
|
true
|
|
)
|
|
;
|
|
MatchingModules = [Module],
|
|
% A unique match for this ID.
|
|
unqualify_name(SymName0, IdName),
|
|
Id = mq_id(qualified(Module, IdName), Arity),
|
|
mq_info_set_module_used(Module, !Info),
|
|
ItemType = convert_simple_item_type(TypeOfId),
|
|
ItemName0 = item_name(SymName0, Arity),
|
|
ItemName = item_name(qualified(Module, IdName), Arity),
|
|
update_recompilation_info(
|
|
recompilation.record_used_item(ItemType, ItemName0, ItemName),
|
|
!Info)
|
|
;
|
|
MatchingModules = [_, _ | _],
|
|
% There are multiple matches.
|
|
Id = Id0,
|
|
( mq_info_get_report_error_flag(!.Info, yes) ->
|
|
mq_info_get_error_context(!.Info, ErrorContext),
|
|
report_ambiguous_match(ErrorContext, Id0, TypeOfId,
|
|
MatchingModules, !IO),
|
|
mq_info_set_error_flag(TypeOfId, !Info),
|
|
mq_info_incr_errors(!Info)
|
|
;
|
|
true
|
|
)
|
|
).
|
|
|
|
:- pred update_recompilation_info(
|
|
pred(recompilation_info, recompilation_info)::in(pred(in, out) is det),
|
|
mq_info::in, mq_info::out) is det.
|
|
|
|
update_recompilation_info(Pred, !Info) :-
|
|
mq_info_get_recompilation_info(!.Info, MaybeRecompInfo0),
|
|
(
|
|
MaybeRecompInfo0 = yes(RecompInfo0),
|
|
Pred(RecompInfo0, RecompInfo),
|
|
mq_info_set_recompilation_info(yes(RecompInfo), !Info)
|
|
;
|
|
MaybeRecompInfo0 = no
|
|
).
|
|
|
|
:- func convert_simple_item_type(id_type) = item_type.
|
|
|
|
convert_simple_item_type(type_id) = type_item.
|
|
convert_simple_item_type(mode_id) = mode_item.
|
|
convert_simple_item_type(inst_id) = inst_item.
|
|
convert_simple_item_type(class_id) = typeclass_item.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type id_type
|
|
---> type_id
|
|
; mode_id
|
|
; inst_id
|
|
; class_id.
|
|
|
|
:- type error_context == pair(mq_error_context, prog_context).
|
|
|
|
:- type mq_id
|
|
---> mq_id(sym_name, int).
|
|
|
|
:- type mq_error_context
|
|
---> mqec_type(mq_id)
|
|
; mqec_inst(mq_id)
|
|
; mqec_mode(mq_id)
|
|
; mqec_pred_or_func(pred_or_func, mq_id)
|
|
; mqec_pred_or_func_mode(maybe(pred_or_func), mq_id)
|
|
; mqec_pragma
|
|
; mqec_lambda_expr
|
|
; mqec_clause_mode_annotation
|
|
; mqec_type_qual
|
|
; mqec_class(mq_id)
|
|
; mqec_instance(mq_id)
|
|
; mqec_mutable(string).
|
|
|
|
:- func id_to_sym_name_and_arity(mq_id) = sym_name_and_arity.
|
|
|
|
id_to_sym_name_and_arity(mq_id(SymName, Arity)) = SymName / Arity.
|
|
|
|
% Report an undefined type, inst or mode.
|
|
%
|
|
:- pred report_undefined(list(module_name)::in, mq_info::in,
|
|
mq_id::in, id_type::in, io::di, io::uo) is det.
|
|
|
|
report_undefined(MatchingModules, Info, Id, IdType, !IO) :-
|
|
mq_info_get_error_context(Info, ErrorContext - Context),
|
|
id_type_to_string(IdType, IdStr),
|
|
io.set_exit_status(1, !IO),
|
|
|
|
Pieces1 = [words("In")] ++ mq_error_context_to_pieces(ErrorContext) ++
|
|
[suffix(":"), nl, words("error: undefined"), fixed(IdStr),
|
|
sym_name_and_arity(id_to_sym_name_and_arity(Id)),
|
|
suffix("."), nl],
|
|
(
|
|
%
|
|
% If it is a qualified symbol, then check whether the module
|
|
% specified has been imported.
|
|
%
|
|
Id = mq_id(qualified(ModuleName, _), _Arity),
|
|
mq_info_get_imported_modules(Info, ImportedModules),
|
|
\+ set.member(ModuleName, ImportedModules),
|
|
\+ ModuleName = Info ^ this_module
|
|
->
|
|
Pieces2 = [words("(The module"), sym_name(ModuleName),
|
|
words("has not been imported.)"), nl]
|
|
;
|
|
MatchingModules = [_ | MatchingModules1]
|
|
->
|
|
(
|
|
MatchingModules1 = [],
|
|
ModuleWord = "module",
|
|
HasWord = "has"
|
|
;
|
|
MatchingModules1 = [_ | _],
|
|
ModuleWord = "modules",
|
|
HasWord = "have"
|
|
),
|
|
MatchingSymNames = list.map(wrap_module_name, MatchingModules),
|
|
Pieces2 = [words("(The"), fixed(ModuleWord)] ++
|
|
component_list_to_pieces(MatchingSymNames) ++
|
|
[fixed(HasWord), words("not been imported in the interface.)")]
|
|
;
|
|
Pieces2 = []
|
|
),
|
|
write_error_pieces(Context, 0, Pieces1 ++ Pieces2, !IO).
|
|
|
|
% Report an error where a type, inst, mode or typeclass had
|
|
% multiple possible matches.
|
|
%
|
|
:- pred report_ambiguous_match(error_context::in, mq_id::in, id_type::in,
|
|
list(module_name)::in, io::di, io::uo) is det.
|
|
|
|
report_ambiguous_match(ErrorContext - Context, Id, IdType, Modules, !IO) :-
|
|
id_type_to_string(IdType, IdStr),
|
|
ModuleNames = list.map(wrap_module_name, Modules),
|
|
Pieces1 = [words("In")] ++ mq_error_context_to_pieces(ErrorContext) ++
|
|
[words("ambiguity error: multiple possible matches for"),
|
|
fixed(IdStr), wrap_id(Id), suffix("."), nl,
|
|
words("The possible matches are in modules")] ++ ModuleNames ++
|
|
[suffix("."), nl],
|
|
globals.io_lookup_bool_option(verbose_errors, Verbose, !IO),
|
|
(
|
|
Verbose = yes,
|
|
Pieces2 = [words("An explicit module qualifier"),
|
|
words("may be necessary."), nl]
|
|
;
|
|
Verbose = no,
|
|
globals.io_set_extra_error_info(yes, !IO),
|
|
Pieces2 = []
|
|
),
|
|
write_error_pieces(Context, 0, Pieces1 ++ Pieces2, !IO),
|
|
io.set_exit_status(1, !IO).
|
|
|
|
% Give a context for the current error message.
|
|
%
|
|
:- func mq_error_context_to_pieces(mq_error_context) = list(format_component).
|
|
|
|
mq_error_context_to_pieces(mqec_type(Id)) =
|
|
[words("definition of type"), wrap_id(Id)].
|
|
mq_error_context_to_pieces(mqec_mode(Id)) =
|
|
[words("definition of mode"), wrap_id(Id)].
|
|
mq_error_context_to_pieces(mqec_inst(Id)) =
|
|
[words("definition of inst"), wrap_id(Id)].
|
|
mq_error_context_to_pieces(mqec_pred_or_func(PredOrFunc, Id)) = Pieces :-
|
|
Id = mq_id(SymName, OrigArity),
|
|
adjust_func_arity(PredOrFunc, OrigArity, Arity),
|
|
Pieces = [words("definition of "),
|
|
fixed(pred_or_func_to_full_str(PredOrFunc)),
|
|
sym_name_and_arity(SymName / Arity)].
|
|
mq_error_context_to_pieces(mqec_pred_or_func_mode(MaybePredOrFunc, Id))
|
|
= Pieces :-
|
|
Id = mq_id(SymName, OrigArity),
|
|
(
|
|
MaybePredOrFunc = yes(PredOrFunc),
|
|
adjust_func_arity(PredOrFunc, OrigArity, Arity),
|
|
Pieces = [words("mode declaration for"),
|
|
fixed(pred_or_func_to_full_str(PredOrFunc)),
|
|
sym_name_and_arity(SymName / Arity)]
|
|
;
|
|
MaybePredOrFunc = no,
|
|
Pieces = [words("mode declaration for"),
|
|
sym_name_and_arity(SymName / OrigArity)]
|
|
).
|
|
mq_error_context_to_pieces(mqec_lambda_expr) =
|
|
[words("mode declaration for lambda expression")].
|
|
mq_error_context_to_pieces(mqec_clause_mode_annotation) =
|
|
[words("clause mode annotation")].
|
|
mq_error_context_to_pieces(mqec_pragma) =
|
|
[words("pragma")].
|
|
mq_error_context_to_pieces(mqec_type_qual) =
|
|
[words("explicit type qualification")].
|
|
mq_error_context_to_pieces(mqec_class(Id)) =
|
|
[words("declaration of typeclass"), wrap_id(Id)].
|
|
mq_error_context_to_pieces(mqec_instance(Id)) =
|
|
[words("declaration of instance of typeclass"), wrap_id(Id)].
|
|
mq_error_context_to_pieces(mqec_mutable(Name)) =
|
|
[
|
|
words("declaration for mutable "),
|
|
prefix("`"),
|
|
words(Name),
|
|
suffix("'")
|
|
].
|
|
|
|
:- pred id_type_to_string(id_type::in, string::out) is det.
|
|
|
|
id_type_to_string(type_id, "type").
|
|
id_type_to_string(mode_id, "mode").
|
|
id_type_to_string(inst_id, "inst").
|
|
id_type_to_string(class_id, "typeclass").
|
|
|
|
% Warn about modules imported in the interface when they do not
|
|
% need to be.
|
|
:- pred maybe_warn_unused_interface_imports(module_name::in,
|
|
list(module_name)::in, io::di, io::uo) is det.
|
|
|
|
maybe_warn_unused_interface_imports(ModuleName, UnusedImports, !IO) :-
|
|
globals.io_lookup_bool_option(warn_interface_imports, Warn, !IO),
|
|
(
|
|
( UnusedImports = []
|
|
; Warn = no
|
|
)
|
|
->
|
|
true
|
|
;
|
|
module_name_to_file_name(ModuleName, ".m", no, FileName, !IO),
|
|
term.context_init(FileName, 1, Context),
|
|
( UnusedImports = [_] ->
|
|
ModuleWord = "module"
|
|
;
|
|
ModuleWord = "modules"
|
|
),
|
|
UnusedSymNames = list.map(wrap_module_name, UnusedImports),
|
|
is_or_are(UnusedImports, IsOrAre),
|
|
Pieces = [words("In module"), sym_name(ModuleName),
|
|
suffix(":"), nl,
|
|
words("warning:"), words(ModuleWord)] ++
|
|
component_list_to_pieces(UnusedSymNames) ++
|
|
[fixed(IsOrAre), words("imported in the interface,"),
|
|
words("but"), fixed(IsOrAre),
|
|
words("not used in the interface.")],
|
|
write_error_pieces(Context, 0, Pieces, !IO),
|
|
record_warning(!IO)
|
|
).
|
|
|
|
:- func wrap_module_name(module_name) = format_component.
|
|
|
|
wrap_module_name(SymName) = sym_name(SymName).
|
|
|
|
:- func wrap_id(mq_id) = format_component.
|
|
|
|
wrap_id(mq_id(Name, Arity)) = sym_name_and_arity(Name / Arity).
|
|
|
|
:- pred is_or_are(list(T)::in, string::out) is det.
|
|
|
|
is_or_are([], "") :- unexpected(this_file, "module_qual:is_or_are").
|
|
is_or_are([_], "is").
|
|
is_or_are([_, _ | _], "are").
|
|
|
|
% Output an error message about an ill-formed user_inst.
|
|
%
|
|
:- pred report_invalid_user_inst(sym_name::in, list(mer_inst)::in,
|
|
error_context::in, io::di, io::uo) is det.
|
|
|
|
report_invalid_user_inst(_SymName, _Insts, ErrorContext - Context, !IO) :-
|
|
ContextPieces = mq_error_context_to_pieces(ErrorContext),
|
|
Pieces = [words("In")] ++ ContextPieces ++ [suffix(":"), nl,
|
|
words("error: variable used as inst constructor.")],
|
|
write_error_pieces(Context, 0, Pieces, !IO),
|
|
io.set_exit_status(1, !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% is_builtin_atomic_type(TypeCtor)
|
|
% is true 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(type_ctor(unqualified("int"), 0)).
|
|
is_builtin_atomic_type(type_ctor(unqualified("float"), 0)).
|
|
is_builtin_atomic_type(type_ctor(unqualified("string"), 0)).
|
|
is_builtin_atomic_type(type_ctor(unqualified("character"), 0)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Access and initialisation predicates.
|
|
%
|
|
|
|
:- pred init_mq_info(item_list::in, globals::in, bool::in, module_name::in,
|
|
mq_info::out) is det.
|
|
|
|
init_mq_info(Items, Globals, ReportErrors, ModuleName, Info) :-
|
|
term.context_init(Context),
|
|
ErrorContext = mqec_type(mq_id(unqualified(""), 0)) - Context,
|
|
set.init(InterfaceModules0),
|
|
get_implicit_dependencies(Items, Globals, ImportDeps, UseDeps),
|
|
set.list_to_set(ImportDeps `list.append` UseDeps, ImportedModules),
|
|
|
|
% Ancestor modules are visible without being explicitly imported.
|
|
set.insert_list(ImportedModules,
|
|
[ModuleName | get_ancestors(ModuleName)], InterfaceVisibleModules),
|
|
|
|
id_set_init(Empty),
|
|
globals.lookup_bool_option(Globals, smart_recompilation,
|
|
SmartRecompilation),
|
|
(
|
|
SmartRecompilation = no,
|
|
MaybeRecompInfo = no
|
|
;
|
|
SmartRecompilation = yes,
|
|
MaybeRecompInfo = yes(init_recompilation_info(ModuleName))
|
|
),
|
|
Info = mq_info(ImportedModules, InterfaceVisibleModules,
|
|
Empty, Empty, Empty, Empty, Empty, Empty,
|
|
InterfaceModules0, local, 0,
|
|
no, no, ReportErrors, ErrorContext, ModuleName,
|
|
may_be_unqualified, MaybeRecompInfo).
|
|
|
|
:- pred mq_info_get_imported_modules(mq_info::in, set(module_name)::out)
|
|
is det.
|
|
:- pred mq_info_get_interface_visible_modules(mq_info::in,
|
|
set(module_name)::out) is det.
|
|
:- pred mq_info_get_modules(mq_info::in, module_id_set::out) is det.
|
|
:- pred mq_info_get_types(mq_info::in, type_id_set::out) is det.
|
|
:- pred mq_info_get_impl_types(mq_info::in, type_id_set::out) is det.
|
|
:- pred mq_info_get_insts(mq_info::in, inst_id_set::out) is det.
|
|
:- pred mq_info_get_modes(mq_info::in, mode_id_set::out) is det.
|
|
:- pred mq_info_get_classes(mq_info::in, class_id_set::out) is det.
|
|
:- pred mq_info_get_unused_interface_modules(mq_info::in,
|
|
set(module_name)::out) is det.
|
|
:- pred mq_info_get_import_status(mq_info::in, import_status::out) is det.
|
|
% :- pred mq_info_get_num_errors(mq_info::in, int::out) is det.
|
|
% :- pred mq_info_get_type_error_flag(mq_info::in, bool::out) is det.
|
|
% :- pred mq_info_get_mode_error_flag(mq_info::in, bool::out) is det.
|
|
:- pred mq_info_get_report_error_flag(mq_info::in, bool::out) is det.
|
|
:- pred mq_info_get_error_context(mq_info::in, error_context::out) is det.
|
|
|
|
mq_info_get_imported_modules(Info, Info ^ imported_modules).
|
|
mq_info_get_interface_visible_modules(Info, Info ^ interface_visible_modules).
|
|
mq_info_get_modules(Info, Info ^ modules).
|
|
mq_info_get_types(Info, Info ^ types).
|
|
mq_info_get_impl_types(Info, Info ^ impl_types).
|
|
mq_info_get_insts(Info, Info ^ insts).
|
|
mq_info_get_modes(Info, Info ^ modes).
|
|
mq_info_get_classes(Info, Info ^ classes).
|
|
mq_info_get_unused_interface_modules(Info, Info ^ unused_interface_modules).
|
|
mq_info_get_import_status(Info, Info ^ import_status).
|
|
mq_info_get_num_errors(Info, Info ^ num_errors).
|
|
mq_info_get_type_error_flag(Info, Info ^ type_error_flag).
|
|
mq_info_get_mode_error_flag(Info, Info ^ mode_error_flag).
|
|
mq_info_get_report_error_flag(Info, Info ^ report_error_flag).
|
|
mq_info_get_error_context(Info, Info ^ error_context).
|
|
mq_info_get_need_qual_flag(Info, Info ^ need_qual_flag).
|
|
mq_info_get_recompilation_info(Info, Info ^ maybe_recompilation_info).
|
|
|
|
:- pred mq_info_set_imported_modules(set(module_name)::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_interface_visible_modules(set(module_name)::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_modules(module_id_set::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_types(type_id_set::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_impl_types(type_id_set::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_insts(inst_id_set::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_modes(mode_id_set::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_classes(class_id_set::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_unused_interface_modules(set(module_name)::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_import_status(import_status::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_type_error_flag(mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_mode_error_flag(mq_info::in, mq_info::out) is det.
|
|
:- pred mq_info_set_error_context(error_context::in,
|
|
mq_info::in, mq_info::out) is det.
|
|
|
|
mq_info_set_imported_modules(ImportedModules, Info,
|
|
Info ^ imported_modules := ImportedModules).
|
|
mq_info_set_interface_visible_modules(ImportedModules, Info,
|
|
Info ^ interface_visible_modules := ImportedModules).
|
|
mq_info_set_modules(Modules, Info, Info ^ modules := Modules).
|
|
mq_info_set_types(Types, Info, Info ^ types := Types).
|
|
mq_info_set_impl_types(Types, Info, Info ^ impl_types := Types).
|
|
mq_info_set_insts(Insts, Info, Info ^ insts := Insts).
|
|
mq_info_set_modes(Modes, Info, Info ^ modes := Modes).
|
|
mq_info_set_classes(Classes, Info, Info ^ classes := Classes).
|
|
mq_info_set_unused_interface_modules(Modules, Info,
|
|
Info ^ unused_interface_modules := Modules).
|
|
mq_info_set_import_status(Status, Info, Info ^ import_status := Status).
|
|
mq_info_set_type_error_flag(Info, Info ^ type_error_flag := yes).
|
|
mq_info_set_mode_error_flag(Info, Info ^ mode_error_flag := yes).
|
|
mq_info_set_error_context(Context, Info, Info ^ error_context := Context).
|
|
mq_info_set_need_qual_flag(Flag, Info, Info ^ need_qual_flag := Flag).
|
|
mq_info_set_recompilation_info(RecompInfo, Info,
|
|
Info ^ maybe_recompilation_info := RecompInfo).
|
|
|
|
:- pred mq_info_incr_errors(mq_info::in, mq_info::out) is det.
|
|
|
|
mq_info_incr_errors(Info, Info ^ num_errors := (Info ^ num_errors +1)).
|
|
|
|
:- pred mq_info_set_error_flag(id_type::in, mq_info::in, mq_info::out) is det.
|
|
|
|
mq_info_set_error_flag(IdType, !Info) :-
|
|
mq_info_set_error_flag_2(IdType, !Info).
|
|
|
|
:- pred mq_info_set_error_flag_2(id_type::in, mq_info::in, mq_info::out)
|
|
is det.
|
|
|
|
mq_info_set_error_flag_2(type_id, !Info) :-
|
|
mq_info_set_type_error_flag(!Info).
|
|
mq_info_set_error_flag_2(mode_id, !Info) :-
|
|
mq_info_set_mode_error_flag(!Info).
|
|
mq_info_set_error_flag_2(inst_id, !Info) :-
|
|
mq_info_set_mode_error_flag(!Info).
|
|
mq_info_set_error_flag_2(class_id, !Info) :-
|
|
mq_info_set_type_error_flag(!Info).
|
|
|
|
% If the current item is in the interface, remove its module name
|
|
% from the list of modules not used in the interface (and if the
|
|
% module name is itself module-qualified, recursively mark its
|
|
% parent module as used).
|
|
%
|
|
:- pred mq_info_set_module_used(module_name::in, mq_info::in, mq_info::out)
|
|
is det.
|
|
|
|
mq_info_set_module_used(Module, !Info) :-
|
|
( mq_info_get_import_status(!.Info, exported) ->
|
|
mq_info_get_unused_interface_modules(!.Info, Modules0),
|
|
set.delete(Modules0, Module, Modules),
|
|
mq_info_set_unused_interface_modules(Modules, !Info),
|
|
(
|
|
Module = qualified(ParentModule, _),
|
|
mq_info_set_module_used(ParentModule, !Info)
|
|
;
|
|
Module = unqualified(_)
|
|
)
|
|
;
|
|
true
|
|
).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
% Define a type for representing sets of ids during module qualification
|
|
% to allow efficient retrieval of all the modules which define an id
|
|
% with a certain name and arity.
|
|
|
|
% The first set of module_names can be used without module qualifiers,
|
|
% items from the second set can only be used with module qualifiers.
|
|
% Items from modules imported with a :- use_module declaration and from `.opt'
|
|
% files should go into the second set.
|
|
:- type id_set == map(pair(string, arity), pair(set(module_name))).
|
|
|
|
:- type type_id_set == id_set.
|
|
:- type mode_id_set == id_set.
|
|
:- type inst_id_set == id_set.
|
|
:- type class_id_set == id_set.
|
|
% Modules don't have an arity, but for simplicity we use the same
|
|
% data structure here, assigning arity zero to all module names.
|
|
:- type module_id_set == id_set.
|
|
|
|
:- pred id_set_init(id_set::out) is det.
|
|
|
|
id_set_init(IdSet) :-
|
|
map.init(IdSet).
|
|
|
|
% Insert an mq_id into an id_set, aborting with an error if the
|
|
% mq_id is not module qualified.
|
|
%
|
|
:- pred id_set_insert(need_qualifier::in, mq_id::in, id_set::in, id_set::out)
|
|
is det.
|
|
|
|
id_set_insert(_, mq_id(unqualified(_), _), _, _) :-
|
|
unexpected(this_file, "module_qual.id_set_insert - unqualified id").
|
|
id_set_insert(NeedQualifier, mq_id(qualified(Module, Name), Arity), !IdSet) :-
|
|
( map.search(!.IdSet, Name - Arity, ImportModules0 - UseModules0) ->
|
|
ImportModules1 = ImportModules0,
|
|
UseModules1 = UseModules0
|
|
;
|
|
set.init(ImportModules1),
|
|
set.init(UseModules1)
|
|
),
|
|
(
|
|
NeedQualifier = must_be_qualified,
|
|
set.insert(UseModules1, Module, UseModules),
|
|
ImportModules = ImportModules1
|
|
;
|
|
NeedQualifier = may_be_unqualified,
|
|
set.insert(ImportModules1, Module, ImportModules),
|
|
UseModules = UseModules1
|
|
),
|
|
svmap.set(Name - Arity, ImportModules - UseModules, !IdSet).
|
|
|
|
:- pred id_set_search_sym_arity(id_set::in, sym_name::in, int::in,
|
|
module_id_set::in, list(module_name)::out) is det.
|
|
|
|
id_set_search_sym_arity(IdSet, Sym, Arity, Modules, MatchingModules) :-
|
|
unqualify_name(Sym, UnqualName),
|
|
(
|
|
map.search(IdSet, UnqualName - Arity, ImportModules - UseModules)
|
|
->
|
|
(
|
|
Sym = unqualified(_),
|
|
set.to_sorted_list(ImportModules, MatchingModules)
|
|
;
|
|
Sym = qualified(Module, _),
|
|
%
|
|
% First, compute the set of modules that this
|
|
% module specifier could possibly refer to.
|
|
%
|
|
% Do a recursive search to find nested modules
|
|
% that match the specified module name.
|
|
%
|
|
ModuleArity = 0,
|
|
id_set_search_sym_arity(Modules, Module, ModuleArity,
|
|
Modules, MatchingParentModules),
|
|
unqualify_name(Module, UnqualModule),
|
|
AppendModuleName = (pred(X::in, Y::out) is det :-
|
|
Y = qualified(X, UnqualModule)
|
|
),
|
|
list.map(AppendModuleName,
|
|
MatchingParentModules,
|
|
MatchingNestedModules),
|
|
%
|
|
% Add the specified module name itself, in case
|
|
% it refers to a top-level (unnested) module name,
|
|
% since top-level modules don't get inserted into
|
|
% the module_id_set.
|
|
%
|
|
AllMatchingModules = [Module | MatchingNestedModules],
|
|
%
|
|
% Second, compute the set of modules that define this symbol.
|
|
%
|
|
set.union(ImportModules, UseModules, DefiningModules),
|
|
%
|
|
% Third, take the intersection of the sets computed in
|
|
% the first two steps
|
|
%
|
|
FindMatch = (pred(MatchModule::out) is nondet :-
|
|
list.member(MatchModule, AllMatchingModules),
|
|
set.member(MatchModule, DefiningModules)
|
|
),
|
|
solutions.solutions(FindMatch, MatchingModules)
|
|
)
|
|
;
|
|
MatchingModules = []
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
get_partial_qualifiers(ModuleName, PartialQualInfo, PartialQualifiers) :-
|
|
PartialQualInfo = partial_qualifier_info(ModuleIdSet),
|
|
(
|
|
ModuleName = unqualified(_),
|
|
PartialQualifiers = []
|
|
;
|
|
ModuleName = qualified(Parent, Child),
|
|
get_partial_qualifiers_2(Parent, unqualified(Child),
|
|
ModuleIdSet, [], PartialQualifiers)
|
|
).
|
|
|
|
:- pred get_partial_qualifiers_2(module_name::in, module_name::in,
|
|
module_id_set::in, list(module_name)::in, list(module_name)::out)
|
|
is det.
|
|
|
|
get_partial_qualifiers_2(ImplicitPart, ExplicitPart, ModuleIdSet,
|
|
!Qualifiers) :-
|
|
%
|
|
% If the ImplicitPart module was imported, rather than just being
|
|
% used, then insert the ExplicitPart module into the list of
|
|
% valid partial qualifiers.
|
|
%
|
|
( parent_module_is_imported(ImplicitPart, ExplicitPart, ModuleIdSet) ->
|
|
!:Qualifiers = [ExplicitPart | !.Qualifiers]
|
|
;
|
|
true
|
|
),
|
|
%
|
|
% Recursively try to add the other possible partial qualifiers.
|
|
%
|
|
( ImplicitPart = qualified(Parent, Child) ->
|
|
NextImplicitPart = Parent,
|
|
insert_module_qualifier(Child, ExplicitPart, NextExplicitPart),
|
|
get_partial_qualifiers_2(NextImplicitPart, NextExplicitPart,
|
|
ModuleIdSet, !Qualifiers)
|
|
;
|
|
true
|
|
).
|
|
|
|
% Check whether the parent module was imported, given the name of a
|
|
% child (or grandchild, etc.) module occurring in that parent module.
|
|
%
|
|
:- pred parent_module_is_imported(module_name::in, module_name::in,
|
|
module_id_set::in) is semidet.
|
|
|
|
parent_module_is_imported(ParentModule, ChildModule, ModuleIdSet) :-
|
|
% Find the module name at the start of the ChildModule;
|
|
% this sub-module will be a direct sub-module of ParentModule
|
|
DirectSubModuleName = get_first_module_name(ChildModule),
|
|
|
|
% Check that the ParentModule was imported.
|
|
% We do this by looking up the definitions for the direct sub-module
|
|
% and checking that the one in ParentModule came from an
|
|
% imported module.
|
|
Arity = 0,
|
|
map.search(ModuleIdSet, DirectSubModuleName - Arity,
|
|
ImportModules - _UseModules),
|
|
set.member(ParentModule, ImportModules).
|
|
|
|
% Given a module name, possibly module-qualified,
|
|
% return the name of the first module in the qualifier list.
|
|
% e.g. given `foo.bar.baz', this returns `foo',
|
|
% and given just `baz', it returns `baz'.
|
|
%
|
|
:- func get_first_module_name(module_name) = string.
|
|
|
|
get_first_module_name(unqualified(ModuleName)) = ModuleName.
|
|
get_first_module_name(qualified(Parent, _)) = get_first_module_name(Parent).
|
|
|
|
%----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "module_qual.m".
|
|
|
|
%----------------------------------------------------------------------------%
|
|
:- end_module module_qual.
|
|
%----------------------------------------------------------------------------%
|