mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
library/cord.m:
Add those two new predicates.
NEWS.md:
Announce the additions.
compiler/*.m:
Use snoc_list in many places.
tests/hard_coded/test_cord_2.{m,exp}:
Extend this test case to test cons_list.
506 lines
22 KiB
Mathematica
506 lines
22 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2015-2025 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This module creates both the public predicates users use to access mutables,
|
|
% and the private auxiliary predicates needed to make that possible.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Mutables are implemented as a source-to-source transformation on the
|
|
% parse tree. The transformation, whose details depend on the compilation
|
|
% target, is documented in notes/mutables.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module hlds.make_hlds.add_mutable_aux_preds.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.make_hlds.make_hlds_types.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_foreign.
|
|
:- import_module parse_tree.prog_item.
|
|
|
|
:- import_module cord.
|
|
:- import_module list.
|
|
:- import_module set_tree234.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Check the mutables that are local to this module for errors,
|
|
% and implement them by transforming them into other kinds of items
|
|
% and pred_target_names to be added to the HLDS by our caller.
|
|
%
|
|
:- pred implement_mutables_if_local(module_info::in,
|
|
set_tree234(inst_ctor)::in, sec_list(item_mutable_info)::in,
|
|
sec_list(item_pred_decl_info)::out,
|
|
ims_list(item_clause_info)::out, ims_list(item_foreign_proc_info)::out,
|
|
list(foreign_decl_code)::out, list(foreign_body_code)::out,
|
|
cord(impl_pragma_fproc_export_info)::out,
|
|
pred_target_names::in, pred_target_names::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.foreign.
|
|
:- import_module hlds.error_msg_inst.
|
|
:- import_module hlds.hlds_inst_mode.
|
|
:- import_module hlds.status.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.builtin_modules.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.prog_mutable.
|
|
|
|
:- import_module bool.
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
implement_mutables_if_local(ModuleInfo, UndefInstCtors, SecList, PredDecls,
|
|
ClauseInfos, ForeignProcs, ForeignDeclCodes, ForeignBodyCodes,
|
|
FPEInfoCord, !PredTargetNames, !Specs) :-
|
|
implement_mutables_sec_loop(ModuleInfo, UndefInstCtors,
|
|
SecList, map.init,
|
|
cord.init, PredDeclCord,
|
|
cord.init, ClauseInfoCord, cord.init, ForeignProcCord,
|
|
cord.init, ForeignDeclCodeCord, cord.init, ForeignBodyCodeCord,
|
|
cord.init, FPEInfoCord, !PredTargetNames, !Specs),
|
|
PredDecls = cord.list(PredDeclCord),
|
|
ClauseInfos = cord.list(ClauseInfoCord),
|
|
ForeignProcs = cord.list(ForeignProcCord),
|
|
ForeignDeclCodes = cord.list(ForeignDeclCodeCord),
|
|
ForeignBodyCodes = cord.list(ForeignBodyCodeCord).
|
|
|
|
:- pred implement_mutables_sec_loop(module_info::in,
|
|
set_tree234(inst_ctor)::in, sec_list(item_mutable_info)::in,
|
|
map(string, prog_context)::in,
|
|
sec_cord(item_pred_decl_info)::in, sec_cord(item_pred_decl_info)::out,
|
|
ims_cord(item_clause_info)::in, ims_cord(item_clause_info)::out,
|
|
ims_cord(item_foreign_proc_info)::in,
|
|
ims_cord(item_foreign_proc_info)::out,
|
|
cord(foreign_decl_code)::in, cord(foreign_decl_code)::out,
|
|
cord(foreign_body_code)::in, cord(foreign_body_code)::out,
|
|
cord(impl_pragma_fproc_export_info)::in,
|
|
cord(impl_pragma_fproc_export_info)::out,
|
|
pred_target_names::in, pred_target_names::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
implement_mutables_sec_loop(_ModuleInfo, _UndefInstCtors, [], _DefinedMutables,
|
|
!PredDeclCord, !ClauseInfoCord, !ForeignProcCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs).
|
|
implement_mutables_sec_loop(ModuleInfo, UndefInstCtors,
|
|
[SecSubList | SecSubLists], !.DefinedMutables,
|
|
!PredDeclCord, !ClauseInfoCord, !ForeignProcCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs) :-
|
|
SecSubList = sec_sub_list(SectionInfo, ItemMutables),
|
|
SectionInfo = sec_info(ItemMercuryStatus, _NeedQual),
|
|
(
|
|
ItemMercuryStatus = item_defined_in_this_module(_),
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
module_info_get_name(ModuleInfo, ModuleName),
|
|
TypeNameFunc = exported_type_to_string(ModuleInfo),
|
|
ModuleParams = module_params(Globals, ModuleName, UndefInstCtors,
|
|
TypeNameFunc),
|
|
implement_mutables_loop(ModuleInfo, SectionInfo, ModuleParams,
|
|
ItemMutables, !DefinedMutables, cord.init, PredDeclSubCord,
|
|
cord.init, ClauseInfoSubCord, cord.init, ForeignProcSubCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs),
|
|
PredDeclSubList =
|
|
sec_sub_list(SectionInfo, cord.list(PredDeclSubCord)),
|
|
cord.snoc(PredDeclSubList, !PredDeclCord),
|
|
( if cord.is_empty(ClauseInfoSubCord) then
|
|
true
|
|
else
|
|
ClauseInfoSubList =
|
|
ims_sub_list(ItemMercuryStatus, cord.list(ClauseInfoSubCord)),
|
|
cord.snoc(ClauseInfoSubList, !ClauseInfoCord)
|
|
),
|
|
( if cord.is_empty(ForeignProcSubCord) then
|
|
true
|
|
else
|
|
ForeignProcSubList =
|
|
ims_sub_list(ItemMercuryStatus, cord.list(ForeignProcSubCord)),
|
|
cord.snoc(ForeignProcSubList, !ForeignProcCord)
|
|
)
|
|
;
|
|
ItemMercuryStatus = item_defined_in_other_module(_)
|
|
% We don't implement the `mutable' declaration unless it is defined
|
|
% in this module. If we did not have this check, we would duplicate
|
|
% the definition of the global variable storing the mutable
|
|
% in any submodules of the module that actually defined the mutable.
|
|
),
|
|
implement_mutables_sec_loop(ModuleInfo, UndefInstCtors,
|
|
SecSubLists, !.DefinedMutables,
|
|
!PredDeclCord, !ClauseInfoCord, !ForeignProcCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs).
|
|
|
|
:- pred implement_mutables_loop(module_info::in, sec_info::in,
|
|
module_params::in, list(item_mutable_info)::in,
|
|
map(string, prog_context)::in, map(string, prog_context)::out,
|
|
cord(item_pred_decl_info)::in, cord(item_pred_decl_info)::out,
|
|
cord(item_clause_info)::in, cord(item_clause_info)::out,
|
|
cord(item_foreign_proc_info)::in, cord(item_foreign_proc_info)::out,
|
|
cord(foreign_decl_code)::in, cord(foreign_decl_code)::out,
|
|
cord(foreign_body_code)::in, cord(foreign_body_code)::out,
|
|
cord(impl_pragma_fproc_export_info)::in,
|
|
cord(impl_pragma_fproc_export_info)::out,
|
|
pred_target_names::in, pred_target_names::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
implement_mutables_loop(_ModuleInfo, _SectionInfo, _ModuleParams,
|
|
[], !DefinedMutables, !PredDeclCord, !ClauseInfoCord, !ForeignProcCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs).
|
|
implement_mutables_loop(ModuleInfo, SectionInfo, ModuleParams,
|
|
[ItemMutable | ItemMutables], !DefinedMutables, !PredDeclCord,
|
|
!ClauseInfoCord, !ForeignProcCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs) :-
|
|
MutableName = ItemMutable ^ mut_name,
|
|
Context = ItemMutable ^ mut_context,
|
|
( if map.search(!.DefinedMutables, MutableName, OldContext) then
|
|
Pieces = [words("Error: this definition of the mutable")] ++
|
|
color_as_subject([fixed(MutableName)]) ++
|
|
[words("is a")] ++
|
|
color_as_incorrect([words("duplicate.")]) ++
|
|
[nl],
|
|
OldPieces = [words("The first definition is here."), nl],
|
|
Spec = error_spec($pred, severity_error, phase_pt2h,
|
|
[msg(Context, Pieces),
|
|
msg(OldContext, OldPieces)]),
|
|
!:Specs = [Spec | !.Specs]
|
|
else
|
|
map.det_insert(MutableName, Context, !DefinedMutables),
|
|
check_mutable(ModuleInfo, ModuleParams, ItemMutable, !Specs),
|
|
implement_mutable(ModuleParams, ItemMutable,
|
|
PredDecls, ClauseInfos, ForeignProcs, FPEInfo,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord, !PredTargetNames),
|
|
cord.snoc_list(PredDecls, !PredDeclCord),
|
|
cord.snoc_list(ClauseInfos, !ClauseInfoCord),
|
|
cord.snoc_list(ForeignProcs, !ForeignProcCord),
|
|
cord.snoc(FPEInfo, !FPEInfoCord)
|
|
),
|
|
implement_mutables_loop(ModuleInfo, SectionInfo, ModuleParams,
|
|
ItemMutables, !DefinedMutables, !PredDeclCord,
|
|
!ClauseInfoCord, !ForeignProcCord,
|
|
!ForeignDeclCodeCord, !ForeignBodyCodeCord,
|
|
!FPEInfoCord, !PredTargetNames, !Specs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred check_mutable(module_info::in, module_params::in,
|
|
item_mutable_info::in, list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
check_mutable(ModuleInfo, ModuleParams, ItemMutable, !Specs) :-
|
|
ItemMutable = item_mutable_info(_MutableName,
|
|
_OrigType, _Type, OrigInst, Inst,
|
|
_InitTerm, _VarSetMutable, MutAttrs, Context, _SeqNum),
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
|
|
% If the mutable is to be trailed, then we need to be in a trailing grade.
|
|
MutAttrs = mutable_var_attributes(_LangMap, Const),
|
|
globals.lookup_bool_option(Globals, use_trail, UseTrail),
|
|
( if
|
|
Const = mutable_is_not_constant(_, Local),
|
|
mutable_thread_local_trailed(Local) = mutable_trailed,
|
|
UseTrail = no
|
|
then
|
|
TrailPieces = [words("Error:")] ++
|
|
color_as_subject([words("trailed"), decl("mutable"),
|
|
words("declaration")]) ++
|
|
color_as_incorrect([words("in non-trailing grade.")]) ++ [nl],
|
|
TrailSpec = spec($pred, severity_error, phase_pt2h,
|
|
Context, TrailPieces),
|
|
!:Specs = [TrailSpec | !.Specs]
|
|
else
|
|
true
|
|
),
|
|
|
|
% Check that the inst in the mutable declaration is a valid inst
|
|
% for a mutable declaration.
|
|
% It is okay to pass a dummy varset in here since any attempt
|
|
% to use inst variables in a mutable declaration should already
|
|
% been dealt with when the mutable declaration was parsed.
|
|
DummyInstVarSet = varset.init,
|
|
check_mutable_inst(ModuleInfo, ModuleParams, Context, DummyInstVarSet,
|
|
[], Inst, [], ExpandedInstSpecs),
|
|
(
|
|
ExpandedInstSpecs = []
|
|
;
|
|
ExpandedInstSpecs = [_ | _],
|
|
% We found some insts in Inst that are not allowed in mutables.
|
|
%
|
|
% Inst has been processed by equiv_type.m, which replaces named insts
|
|
% with the definition of the named inst. When we check it, the error
|
|
% messages we generate for any errors in it will lack information
|
|
% about what nested sequence of named inst definitions the errors is
|
|
% inside. We therefore compute the error messages on the original
|
|
% inst as well.
|
|
%
|
|
% If ExpandedInstSpecs is nonempty, then UnexpandedInstSpecs should
|
|
% be nonempty as well, but we prepare for it to be empty just in case.
|
|
check_mutable_inst(ModuleInfo, ModuleParams, Context, DummyInstVarSet,
|
|
[], OrigInst, [], UnexpandedInstSpecs),
|
|
(
|
|
UnexpandedInstSpecs = [],
|
|
% Printing error messages without the proper context is better than
|
|
% not printing error messages at all, once we have discovered
|
|
% an error.
|
|
!:Specs = ExpandedInstSpecs ++ !.Specs
|
|
;
|
|
UnexpandedInstSpecs = [_ | _],
|
|
!:Specs = UnexpandedInstSpecs ++ !.Specs
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Add an error to !Specs for each part of the inst that isn't allowed
|
|
% inside a mutable declaration.
|
|
%
|
|
:- pred check_mutable_inst(module_info::in, module_params::in,
|
|
prog_context::in, inst_varset::in, list(inst_ctor)::in, mer_inst::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
check_mutable_inst(ModuleInfo, ModuleParams, Context, InstVarSet,
|
|
ParentInsts, Inst, !Specs) :-
|
|
(
|
|
( Inst = any(Uniq, _)
|
|
; Inst = ground(Uniq, _)
|
|
),
|
|
check_mutable_inst_uniqueness(ModuleInfo, Context, InstVarSet,
|
|
ParentInsts, Inst, Uniq, !Specs)
|
|
;
|
|
Inst = bound(Uniq, _, BoundFunctors),
|
|
check_mutable_inst_uniqueness(ModuleInfo, Context, InstVarSet,
|
|
ParentInsts, Inst, Uniq, !Specs),
|
|
check_mutable_bound_functors(ModuleInfo, ModuleParams, Context,
|
|
InstVarSet, ParentInsts, BoundFunctors, !Specs)
|
|
;
|
|
Inst = defined_inst(InstName),
|
|
(
|
|
InstName = user_inst(UserInstSymName, UserInstArgs),
|
|
list.length(UserInstArgs, UserInstArity),
|
|
UserInstCtor = inst_ctor(UserInstSymName, UserInstArity),
|
|
( if
|
|
list.member(UserInstCtor, ParentInsts)
|
|
then
|
|
true
|
|
else if
|
|
UserInstSymName =
|
|
qualified(UserInstModuleName, UserInstBaseName),
|
|
UserInstModuleName = mercury_public_builtin_module,
|
|
UserInstArity = 0,
|
|
( UserInstBaseName = "dead"
|
|
; UserInstBaseName = "mostly_dead"
|
|
)
|
|
then
|
|
FreePieces =
|
|
color_as_incorrect([words("may not appear in")]) ++
|
|
[decl("mutable"), words("declarations.")],
|
|
UnqualInstName =
|
|
user_inst(unqualified(UserInstBaseName), UserInstArgs),
|
|
% There is special code in error_msg_inst.m to handle
|
|
% inst names from which the qualification by
|
|
% mercury_public_builtin_module has been stripped.
|
|
UnqualInst = defined_inst(UnqualInstName),
|
|
invalid_inst_in_mutable(ModuleInfo, Context, InstVarSet,
|
|
ParentInsts, UnqualInst, FreePieces, !Specs)
|
|
else
|
|
check_mutable_insts(ModuleInfo, ModuleParams, Context,
|
|
InstVarSet, ParentInsts, UserInstArgs, !Specs),
|
|
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_user_insts(InstTable, UserInstTable),
|
|
( if map.search(UserInstTable, UserInstCtor, InstDefn) then
|
|
InstDefn = hlds_inst_defn(DefnInstVarSet, _Params,
|
|
InstBody, _MMTC, _Context, _Status),
|
|
InstBody = eqv_inst(EqvInst),
|
|
DefnParentInsts = [UserInstCtor | ParentInsts],
|
|
check_mutable_inst(ModuleInfo, ModuleParams, Context,
|
|
DefnInstVarSet, DefnParentInsts, EqvInst, !Specs)
|
|
else
|
|
UndefInstCtors = ModuleParams ^ mp_undef_inst_ctors,
|
|
( if
|
|
set_tree234.contains(UndefInstCtors, UserInstCtor)
|
|
then
|
|
% An error message about UserInstCtor being undefined
|
|
% has already been generated. Any message we could
|
|
% generate here would only repeat the same information
|
|
% in a (possibly confusingly) different form.
|
|
true
|
|
else
|
|
% This should not happen, but just in case it does ...
|
|
UndefinedPieces =
|
|
color_as_incorrect([words("is not defined.")]),
|
|
invalid_inst_in_mutable(ModuleInfo, Context,
|
|
InstVarSet, ParentInsts, Inst, UndefinedPieces,
|
|
!Specs)
|
|
)
|
|
)
|
|
)
|
|
;
|
|
( InstName = unify_inst(_, _, _, _)
|
|
; InstName = merge_inst(_, _)
|
|
; InstName = ground_inst(_, _, _, _)
|
|
; InstName = any_inst(_, _, _, _)
|
|
; InstName = shared_inst(_)
|
|
; InstName = mostly_uniq_inst(_)
|
|
; InstName = typed_inst(_, _)
|
|
; InstName = typed_ground(_, _)
|
|
),
|
|
unexpected($pred, "non-user inst")
|
|
)
|
|
;
|
|
Inst = free,
|
|
FreePieces = color_as_incorrect([words("may not appear in")]) ++
|
|
[decl("mutable"), words("declarations.")],
|
|
invalid_inst_in_mutable(ModuleInfo, Context, InstVarSet, ParentInsts,
|
|
Inst, FreePieces, !Specs)
|
|
;
|
|
Inst = constrained_inst_vars(_, _),
|
|
ConstrainedPieces = [words("is constrained, and thus")] ++
|
|
color_as_incorrect([words("may not appear")]) ++
|
|
[words("in"), decl("mutable"), words("declarations.")],
|
|
invalid_inst_in_mutable(ModuleInfo, Context, InstVarSet, ParentInsts,
|
|
Inst, ConstrainedPieces, !Specs)
|
|
;
|
|
Inst = inst_var(_)
|
|
% The parser ensures that the inst in the mutable declaration does
|
|
% not have any variables. Any variables we encounter here must be
|
|
% a parameter from a named inst that the top level inst refers to
|
|
% either directly or indirectly.
|
|
;
|
|
Inst = not_reached,
|
|
unexpected($pred, "not_reached")
|
|
).
|
|
|
|
:- pred check_mutable_bound_functors(module_info::in, module_params::in,
|
|
prog_context::in, inst_varset::in,
|
|
list(inst_ctor)::in, list(bound_functor)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
check_mutable_bound_functors(_ModuleInfo, _ModuleParams, _Context,
|
|
_InstVarSet, _ParentInsts, [], !Specs).
|
|
check_mutable_bound_functors(ModuleInfo, ModuleParams, Context,
|
|
InstVarSet, ParentInsts, [BoundFunctor | BoundFunctors], !Specs) :-
|
|
BoundFunctor = bound_functor(_ConsId, ArgInsts),
|
|
check_mutable_insts(ModuleInfo, ModuleParams, Context, InstVarSet,
|
|
ParentInsts, ArgInsts, !Specs),
|
|
check_mutable_bound_functors(ModuleInfo, ModuleParams, Context, InstVarSet,
|
|
ParentInsts, BoundFunctors, !Specs).
|
|
|
|
:- pred check_mutable_insts(module_info::in, module_params::in,
|
|
prog_context::in, inst_varset::in, list(inst_ctor)::in, list(mer_inst)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
check_mutable_insts(_ModuleInfo, _ModuleParams, _Context, _InstVarSet,
|
|
_ParentInsts, [], !Specs).
|
|
check_mutable_insts(ModuleInfo, ModuleParams, Context, InstVarSet,
|
|
ParentInsts, [Inst | Insts], !Specs) :-
|
|
check_mutable_inst(ModuleInfo, ModuleParams, Context, InstVarSet,
|
|
ParentInsts, Inst, !Specs),
|
|
check_mutable_insts(ModuleInfo, ModuleParams, Context, InstVarSet,
|
|
ParentInsts, Insts, !Specs).
|
|
|
|
%---------------------%
|
|
|
|
:- pred check_mutable_inst_uniqueness(module_info::in, prog_context::in,
|
|
inst_varset::in, list(inst_ctor)::in, mer_inst::in, uniqueness::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
check_mutable_inst_uniqueness(ModuleInfo, Context, InstVarSet, ParentInsts,
|
|
Inst, Uniq, !Specs) :-
|
|
(
|
|
Uniq = shared
|
|
;
|
|
(
|
|
Uniq = unique,
|
|
UniqStr = "unique"
|
|
;
|
|
Uniq = mostly_unique,
|
|
UniqStr = "mostly_unique"
|
|
;
|
|
Uniq = clobbered,
|
|
UniqStr = "clobbered"
|
|
;
|
|
Uniq = mostly_clobbered,
|
|
UniqStr = "mostly_clobbered"
|
|
),
|
|
( if Inst = ground(Uniq, _) then
|
|
UniqPieces = color_as_incorrect([words("may not appear")]) ++
|
|
[words("in"), decl("mutable"), words("declarations.")]
|
|
else
|
|
UniqPieces =
|
|
[words("has uniqueness"), quote(UniqStr), suffix(","),
|
|
words("which")] ++
|
|
color_as_incorrect([words("may not appear")]) ++
|
|
[words("in"), decl("mutable"), words("declarations.")]
|
|
),
|
|
invalid_inst_in_mutable(ModuleInfo, Context, InstVarSet, ParentInsts,
|
|
Inst, UniqPieces, !Specs)
|
|
).
|
|
|
|
% Note: the caller is responsible for coloring the relevant parts of
|
|
% ProblemPieces.
|
|
%
|
|
:- pred invalid_inst_in_mutable(module_info::in, prog_context::in,
|
|
inst_varset::in, list(inst_ctor)::in, mer_inst::in, list(format_piece)::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
invalid_inst_in_mutable(ModuleInfo, Context, InstVarSet, ParentInsts, Inst,
|
|
ProblemPieces, !Specs) :-
|
|
named_parents_to_pieces(ParentInsts, ParentPieces),
|
|
InstPieces = error_msg_inst(ModuleInfo, InstVarSet,
|
|
do_not_expand_named_insts, uod_user, quote_short_inst, [], [],
|
|
[nl_indent_delta(1)], [nl_indent_delta(-1)], Inst),
|
|
Pieces = [words("Error:") | ParentPieces] ++
|
|
[words("the inst")] ++ color_as_subject(InstPieces) ++
|
|
ProblemPieces ++ [nl],
|
|
Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
:- pred named_parents_to_pieces(list(inst_ctor)::in,
|
|
list(format_piece)::out) is det.
|
|
|
|
named_parents_to_pieces([], []).
|
|
named_parents_to_pieces([InstCtor | InstCtors], Pieces) :-
|
|
named_parent_to_pieces(InstCtor, HeadPieces),
|
|
named_parents_to_pieces(InstCtors, TailPieces),
|
|
Pieces = HeadPieces ++ TailPieces.
|
|
|
|
:- pred named_parent_to_pieces(inst_ctor::in,
|
|
list(format_piece)::out) is det.
|
|
|
|
named_parent_to_pieces(InstCtor, Pieces) :-
|
|
InstCtor = inst_ctor(InstName, InstArity),
|
|
Pieces = [words("in the expansion of the named inst"),
|
|
qual_sym_name_arity(sym_name_arity(InstName, InstArity)),
|
|
suffix(":"), nl].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module hlds.make_hlds.add_mutable_aux_preds.
|
|
%---------------------------------------------------------------------------%
|