Files
mercury/compiler/pred_name.m
Zoltan Somogyi a16cd8c725 Replace three pred_or_func_to_* functions with two.
mdbcomp/prim_data.m:
    Delete the pred_or_func_to_string function that used to be defined here,
    and replace it with pred_or_func_to_str and pred_or_func_to_full_str
    that used to be in parse_tree_out_misc.m. These two names make it
    clear which one returns "pred" or "func", and which returns "predicate"
    or "function".

compiler/parse_tree_out_misc.m:
    Delete the functions moved to prim_data.m.

compiler/add_clause.m:
compiler/add_pred.m:
compiler/hlds_desc.m:
compiler/hlds_out_typeclass_table.m:
compiler/hlds_out_util.m:
compiler/make_hlds_error.m:
compiler/mlds_to_target_util.m:
compiler/mode_errors.m:
compiler/module_qual.qual_errors.m:
compiler/optimize.m:
compiler/parse_tree_out_sym_name.m:
compiler/polymorphism_lambda.m:
compiler/pred_name.m:
compiler/pred_table.m:
compiler/prog_type_test.m:
compiler/recompilation.check.m:
compiler/recompilation.used_file.m:
compiler/style_checks.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/write_error_spec.m:
    Conform to the changes above, mostly by not importing
    parse_tree_out_misc.m.
2024-05-12 15:41:09 +10:00

1992 lines
86 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1994-2001, 2003-2012 The University of Melbourne.
% Copyright (C) 2014-2017, 2022-2024 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% File: pred_name.m.
%
% This module contains two related but distinct parts.
%
% The first part contains types and predicates for constructing predicate
% names as strings. This is the approach mmc has traditionally used.
%
% The second part contains the pred_origin type, which records the
% "origin story" of each predicate. It is here because it is now quite close
% to being a *structured* representation of predicate names, and we intend
% to use it to eventually replace the plain string representation.
% So the first part is intended to eventually be deleted.
%
%---------------------------------------------------------------------------%
:- module hlds.pred_name.
:- interface.
:- import_module hlds.hlds_pred.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_data_pragma.
:- import_module list.
:- import_module maybe.
:- import_module one_or_more.
:- import_module pair.
%---------------------------------------------------------------------------%
%
% First part:
%
% When we create new predicates (or functions), we need names for them.
% This module creates those names.
%
% - If the new predicate is a transformed version of an old predicate,
% we create the name out of the name of the original predicate, and
% the identity and parameters of the transformation.
%
% - If the new predicate is not a transformed version of an old predicate,
% but is a predicate that implements a method for an instance, or
% a unify, compare or index (uci) predicate for a type, then we create
% its name out of the parameters of the instance and the method,
% or the name of the type.
%
%---------------------------------------------------------------------------%
% For use in cases where we create more than one predicate for the
% same line, we also include a counter in the name of the transformed
% predicate.
:- type line_number_and_counter
---> lnc(int, int).
:- type aux_tabling_pred_kind
---> atpk_statistics
; atpk_reset.
:- type aux_tabling_maybe_single_proc
---> is_not_single_proc
; is_single_proc.
% With three exceptions, all the transform_names specify whether
% the original predicate is a predicate or a function, because
% our naming scheme includes this information in the transformed name.
% (This is needed to avoid accidental collisions between the transformed
% name of a predicate, and the transformed name of a function.)
%
% Two of the exceptions are transformations done by higher_order.m.
% Although their transform_names include a pred_or_func argument,
% the name we generate for them ignores this argument. I (zs) can see
% no reason for this omission, but (a) it cannot be fixed without also
% fixing name demangling code, and (b) there is not much point in doing
% such fixes piecemeal.
%
% The third exception is tn_pragma_type_spec, which gets its information
% not from a pred_info (which will *always* tell you whether it contains
% a predicate or a function), but from a type_spec pragma (which *may*
% specify predicate vs function, but, for now, it is allowed to stay silent
% on that matter.
:- type transform_name
---> tn_higher_order(pred_or_func, int)
% The higher order specialization specifies only a counter.
; tn_user_type_spec(pred_or_func, pred_id, proc_id, int)
% The predicate calling make_transformed_pred_sym_name with this
% transform should pass us *not* the name of the predicate
% being transformed, but the name of the predicate *calling it*
% at the call site being optimized. The second and third arguments
% give the pred_id and proc_id of this caller. The last argument
% is the version number of the higher order transformation
% algorithm.
%
% XXX It would be nice to know what the relationship is
% between tn_pragma_type_spec and tn_higher_order_type_spec.
; tn_aux_tabling(pred_or_func, user_arity, aux_tabling_pred_kind,
aux_tabling_maybe_single_proc, int)
% The new predicate name will include the arity of the original
% predicate, an indication of what kind of aux predicate this is,
% and, if the procedure being transformed is not the only procedure
% in its predicate (as indicated by the fourth argument), it will
% also include the proc_id of the original procedure
% (in its int form, as given by the fifth argument).
; tn_accumulator(pred_or_func, line_number_and_counter)
; tn_deforestation(pred_or_func, line_number_and_counter)
; tn_lambda(pred_or_func, line_number_and_counter)
% With the above transforms, the new predicate name includes
% the line number and a unique counter value.
; tn_loop_inv(pred_or_func, int, line_number_and_counter)
; tn_tupling(pred_or_func, int, line_number_and_counter)
; tn_untupling(pred_or_func, int, line_number_and_counter)
% With the above transforms, the new predicate name,
% besides the above, also includes (the integer form of)
% the proc_id of the transformed procedure. This is because
% (if relevant) we create a new pred_info for each procedure
% we transform, even if they come from the same pred_info.
%
% XXX We cannot take the proc_ids as proc_ids, rather than ints,
% as long as we call make_transformed_pred_sym_name from
% parse_pragma.m, which is in the parse_tree package.
%
% XXX Arguably, that call in to make_transformed_pred_sym_name
% in parse_pragma.m should be moved to add_pragma_type_spec.m,
% which is inside the hlds package, and thus has access
% to the proc_id type.
; tn_last_call_modulo_cons(pred_or_func, int)
% The new predicate names includes a sequentially allocated
% variant number.
% XXX A proc_id and a list of the argument numbers of the
% arguments being passed by address would also work.
; tn_ssdb_stdlib_proxy(pred_or_func)
% The new predicate name includes only the pred_or_func indication.
; tn_dep_par_conj(pred_or_func, int, list(int))
% The new predicate name includes the proc_id of the original
% predicate (given by the second argument), as well as the list
% of the argument positions that we transform into futures.
; tn_par_distance_granularity(pred_or_func, int)
% The new predicate name includes the distance parameter,
% the main (actually only) parameter of the transformation.
; tn_par_loop_control(pred_or_func, int)
% The new predicate name includes the proc_id of the original
% predicate (given by the second argument).
; tn_structure_reuse(pred_or_func, int, list(int))
% The new predicate name includes the proc_id of the original
% predicate (given by the second argument), as well a list
% of argument numbers. XXX It would be nice to know just
% how those arguments were selected.
; tn_pragma_type_spec(maybe(pred_or_func), tvarset, type_subst)
% The new predicate name includes the type substitution
% specified by the type_spec pragma, in the form of an assoc_list,
% each element of which maps a type var to a type. The tvarset
% argument is there to provide the names of the type vars
% on both sides of those arrows.
; tn_io_tabling(pred_or_func)
% The new predicate name includes only the pred_or_func indication.
; tn_minimal_model_generator(pred_or_func, int)
% The new predicate name includes the proc_id of the original
% predicate (given by the second argument).
; tn_stm_expanded(pred_or_func, stm_clone_kind, int, int, int)
% The new predicate name includes the clone kind, the arity
% of the original predicate (given by the third argument),
% the pred_id of the original predicate (given by the fourth
% argument), and a unique counter value (the last argument).
; tn_unused_args(pred_or_func, int, list(int)).
% The new predicate name includes the proc_id of the original
% predicate (given by the second argument), as well a list
% of the argument numbers of the unused arguments.
:- type stm_clone_kind
---> stmck_top_level
; stmck_rollback
; stmck_wrapper
; stmck_simple_wrapper
; stmck_or_else.
% make_transformed_pred_sym_name(ModuleName, OrigName, Transform,
% TransformedSymName):
% make_transformed_pred_name(OrigName, Transform, TransformedName):
%
% Given the original name of a predicate or function, return the name
% we want to give to a version of it that has been transformed by
% Transform.
%
% The first version returns the transformed name as a sym_name
% qualified with ModuleName, because some of our callers want the result
% in this sym_name form.
%
:- pred make_transformed_pred_sym_name(module_name::in, string::in,
transform_name::in, sym_name::out) is det.
:- pred make_transformed_pred_name(string::in,
transform_name::in, string::out) is det.
%---------------------%
% Make the name of the introduced pred used to check a particular
% instance of a particular class method.
%
% XXX This isn't quite perfect, I suspect.
%
:- pred make_instance_method_pred_name(class_id::in,
sym_name::in, user_arity::in, list(mer_type)::in, string::out) is det.
% Given a list of types, mangle the names so into a string which
% identifies them. The types must all have their top level functor
% bound, with any arguments free variables.
%
:- pred make_instance_string(list(mer_type)::in, string::out) is det.
%---------------------%
% Return the predicate name we should use for promise of the given type
% at the given location.
%
:- func promise_pred_name(promise_type, string, int) = string.
%---------------------%
% Return the predicate name we should use for the given uci (special) pred
% for the given type_ctor.
%
:- func uci_pred_name(special_pred_id, type_ctor) = string.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
%
% Second part:
%
% We should be able to use this type as a structured representation
% of a name, to implement *structural* name mangling/unmangling, i.e.
% to solve the problem of how to represent the structure of a predicate's
% origins in a string, for inclusion in target language code and
% eventually in executables, in a way that allows the structure
% to be unambiguously recovered later. This is distinct from *lexical*
% mangling/unmangling, which ensures that the string is acceptable
% to the target language compiler as (usually) an identifier, which
% requires mapping any characters that may not appear in identifiers
% to characters that may appear there.
%
% The idea is that we should generate the names of the procedures
% we output to target language source code *and* in the RTTI program
% representations we generate for the debugger and the profilers
% from the pred_origin field of the pred_info, not the name field.
% The reason for this is that the mangling process can be considerably
% simpler if it has access to a *structured* representation of all the
% info that the target language name must include. Our old (and still
% current) approach of encoding this info in a single string effectively
% forced piecemeal development of the predicate name mangling scheme,
% by requiring the developer who added a new kind of pred_origin to
% pick its string representation *without* access to the string
% representation of all the *other* pred origins, since those were
% scattered throughout the rest of the compiler. This is why our current
% undemangle algorithm does not have a convincing correctness argument,
% which means that it is quite likely that in the presence of
% unfortunately (or maliciously) chosen names for the base predicates,
% it can generate incorrect output.
%
% On the other hand, an algorithm for converting a pred_origin
% into a mangled target language name would have all the code
% implementing the naming scheme in one place, which would
%
% - allow us to design and implement a simpler and more consistent
% naming scheme than the current one, and
%
% - allow us to develop the mangling algorithm using that scheme
% to be developed hand-in-hand with the corresponding updated unmangling
% algorithm, which *should* allow a correctness argument for the
% proposition that unmangle(mangle(PredOrigin) is always PredOrigin.
%
% The strings we use to represent the names and parameters of
% program transformations and of compiler components that create
% procedures should never include characters or substrings that
% need to be lexically mangled, but they may include user provided names
% (of predicates, functions, types classes, mutables etc) that
% may require lexical mangling. Unlike our old approach, the new approach
% should allow this lexical mangling to be done just on the user-provided
% parts of the string, without requiring the *whole* string to be
% lexically mangled. And we can simply forego the lexical mangling
% in situatins in which it is not required, e.g. in HLDS dumps.
:- type pred_origin
---> origin_user(user_made)
; origin_compiler(compiler_made)
; origin_pred_transform(pred_transform, pred_origin, pred_id)
% The predicate is a transformed version of another predicate,
% whose origin and identity are given by the second and third
% arguments.
; origin_proc_transform(proc_transform, pred_origin,
pred_id, proc_id).
% The predicate is a transformed version of one procedure of
% another predicate. The origin of that predicate is given
% by the second argument, and the identity of the procedure
% are given by the third and fourth arguments.
:- type user_made
---> user_made_pred(pred_or_func, sym_name, user_arity)
% The predicate is a normal user-written predicate or function.
% The first argument says which, the second and third arguments
% give its name and arity.
; user_made_lambda(string, int, int)
% The predicate is a higher-order manifest constant.
% The first two arguments specify its location in the source,
% as a filename/line number pair, and the third argument is
% a sequence number used to distinguish multiple lambdas
% on the same line.
; user_made_class_method(class_id, pred_pf_name_arity)
% The predicate is a class method implementation.
; user_made_instance_method(pred_pf_name_arity,
instance_method_constraints)
% The predicate is a class method implementation for the class
% whose class_id is in the instance_method_constraints.
% Record the method name and arity, and extra information about
% the class context to allow polymorphism.m to correctly set up
% the extra type_info and typeclass_info arguments.
; user_made_assertion(promise_type, string, int).
% The predicate represents an assertion of the given promise_type
% at the given filename and line number.
:- type compiler_made
---> made_for_uci(special_pred_id, type_ctor)
% If the predicate is a unify, compare or index predicate,
% specify which one, and for which type constructor.
; made_for_deforestation(int, int)
% The predicate was created by deforestation from two or more
% goals, so that it would be incorrect to record it being
% a transformed version of any one of them.
%
% The first integer gives the line number of one of the goals,
% and the second is a deforestation action sequence number,
% which will be different in different predicates created by
% deforestation. (We don't record the filename part of the context,
% because it will be the source file containing the module
% except in the *extremely* rare cases where the module contains
% a #line directive.
; made_for_solver_repn(type_ctor, solver_type_pred_kind)
% The predicate is a representation change predicate
% either to or from either ground or any, as indicated by
% the solver_type_pred_kind, for the type constructor given by
% the sym_name and arity.
; made_for_tabling(pred_pf_name_arity, tabling_aux_pred_kind)
% The predicate is an auxiliary predicate of the indicated kind
% for the tabled predicate identified by the pf_sym_name_arity.
; made_for_mutable(module_name, string, mutable_pred_kind)
% The predicate is a predicate that operates on the mutable
% with the given name in the given module. The last argument
% says whether the predicate is an init, pre_init, get, set,
% lock, or unlock predicate on that mutable.
; made_for_initialise(string, int)
% The predicate implements a standalone initialise declaration
% (standalone means that it is NOT created to initialise
% a mutable). The arguments specify the declaration's context
% as a filename and line number.
; made_for_finalise(string, int).
% The predicate implements a standalone finalise declaration.
% The arguments specify the declaration's context as a
% filename and line number.
:- type pred_transform
---> pred_transform_pragma_type_spec(
% The predicate was created in response to a type_spec
% pragma containing this substitution from type variables
% (represented by the integers) to types.
one_or_more(pair(int, mer_type))
)
; pred_transform_distance_granularity(
% The distance parameter of the transformation.
int
)
; pred_transform_table_generator
; pred_transform_ssdebug(pred_or_func)
; pred_transform_structure_reuse.
% pred_transform_structure_reuse should probably be
% proc_transform_structure_reuse, but until structure reuse
% work reliably, it does not matter.
:- type proc_transform
---> proc_transform_user_type_spec(
% User-directed type specialization.
%
% The pred and proc ids of the caller which caused
% this new predicate to be created by the compiler.
% XXX Why is this relevant?
pred_id,
proc_id
)
; proc_transform_higher_order_spec(
% Non-user-directed type specialization.
%
% Sequence number among the higher order specializations
% of the original predicate.
% XXX Shouldn't this be "of the module"?
int
)
; proc_transform_accumulator(
% The line number from the context of the original
% procedure's code.
int,
% The list of the numbers of the variables in the original
% predicate interface that have been converted to accumulators.
list(int)
)
; proc_transform_unused_args(
% The list of eliminated argument numbers.
list(int)
)
; proc_transform_loop_inv(
% The line number from the context of the original
% procedure's code.
int,
% A per-context-unique sequence number for this particular
% loop invariant transformation. (It will be 1 unless there
% is more than one such transformation at its context, in
% which case they will have sequence numbers 1, 2 etc.)
int
)
; proc_transform_tuple(
% The line number from the context of the original
% procedure's code.
int,
% A unique-in-the-module sequence number for this particular
% tuple transformation.
int
)
; proc_transform_untuple(
% The line number from the context of the original
% procedure's code.
int,
% A unique-in-the-module sequence number for this particular
% untuple transformation.
int
)
; proc_transform_dep_par_conj(
% The arguments in these positions are inside futures.
list(int)
)
; proc_transform_par_loop_ctrl
; proc_transform_lcmc(
% A unique-for-the-procedure sequence number for
% this particular lcmc transformation.
int,
% The arguments in these positions are returned via pointer.
list(int)
)
; proc_transform_stm_expansion
; proc_transform_io_tabling
; proc_transform_direct_arg_in_out.
% Describes the class constraints on an instance method implementation.
% This information is used by polymorphism.m to ensure that the
% type_info and typeclass_info arguments are added in the order in
% which they will be passed in by do_call_class_method.
%
:- type instance_method_constraints
---> instance_method_constraints(
class_id,
% The types in the head of the instance declaration.
list(mer_type),
% The universal constraints on the instance declaration.
list(prog_constraint),
% The constraints on the method's type declaration in the
% `:- typeclass' declaration.
univ_exist_constraints
).
%---------------------------------------------------------------------------%
%
% These two functions and this predicate are three different ways to convert
% a pred_origin into a string. They have different uses cases that impose
% different criteria about what characteristics the output should have.
% Some of their differences result from this, but some are simply caused
% by the fact that they were developed independently of each other,
% so even parts of the output that they *could* be consistent about
% they are not necessarily consistent about.
%
% pred_origin_to_user_string returns a string that is suitable to identify
% a predicate to a user
%
% - in progress messages,
% - in error messages, and
% - as the expansion of $pred.
%
% For user written predicates, the result will look like this:
%
% predicate `foo.bar'/3
% function `foo.myfoo'/5
%
% For predicates created by the compiler, the result be a description
% such as
%
% unification predicate for `map'/2
%
% For predicates that are the transformed version of another predicate,
% the result will identify the original predicate at the start of the
% transformation chain (which may contain more than one transformation)
% and will say that a transformation happened, but will not say
% how many transformations happened, or what the transformations were,
% because
%
% - such details are not needed in progress messages, and
% - they *should* not be needed for error messages, since we should
% not be reporting any errors for transformed predicates at all.
%
% The versions that also specify a proc_id do the same job, only
% they also append the procedure's mode number.
%
:- func pred_origin_to_user_string(pred_origin) = string.
% pred_origin_to_dev_string returns a string that is suitable to identify
% a predicate to a developer
%
% - in HLDS dumps (the parts other than the full pred provenance),
% - in compiler output intended to debug the compiler itself, and
% - in progress messages intended to help make sense of such output.
%
% The output will differ from pred_id_to_user_string in two main ways:
%
% - it will contain no quotes, because the unbalanced `' quote style
% we usually use screws up syntax highlighting in HLDS dumps, and
%
% - it will contain a description of each transformation applied to
% the base predicate.
%
% The versions that also specify a proc_id do the same job, only
% they also append the procedure's mode number.
%
:- func pred_origin_to_dev_string(pred_origin) = string.
% Write out a predicate's origin in a format suitable to describe
% a predicate's origin in that predicate's entry in HLDS dumps,
% after the prefix given by the third argument,
% Moved here from hlds_pred.m.
%
:- func dump_origin(tvarset, var_name_print, string, pred_origin) = string.
% Generated an identification of the predicate with the given origin
% and name to put into layout structures for the debugger and the deep
% profiler. Moved here from layout_out.m.
%
:- func layout_origin_name(pred_origin, string) = string.
% Return a representation of the pred_origin as a string that
%
% - can be put into layout structures in an executable,
% after any quote characters in it are escaped, and
%
% - can be used by debuggers and profilers to recover a representation
% of the original pred_origin that is sufficient both to uniquely
% identify the predicate, and to give information its origin
% that is sufficient for the purposes of the debugger or profiler.
%
% The string should be parseable from the front, meaning that
% at no point should you have to go to the end of either the whole string,
% or of a part of it, and scan backwards.
%
:- func layout_origin_name_new(pred_origin) = string.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.special_pred.
:- import_module parse_tree.parse_tree_out_misc.
:- import_module parse_tree.parse_tree_out_sym_name.
:- import_module parse_tree.parse_tree_out_type.
:- import_module parse_tree.prog_type.
:- import_module int.
:- import_module string.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
make_transformed_pred_sym_name(ModuleName, OrigName, Transform,
TransformedSymName) :-
make_transformed_pred_name(OrigName, Transform, TransformedName),
TransformedSymName = qualified(ModuleName, TransformedName).
make_transformed_pred_name(OrigName, Transform, TransformedName) :-
(
Transform = tn_higher_order(_PredOrFunc, Counter),
% XXX Ignoring _PredOrFunc seems to me to be a bug.
% XXX The string we construct here does not fit into our current
% naming scheme at all.
string.format("%s__ho%d", [s(OrigName), i(Counter)], TransformedName)
;
Transform = tn_user_type_spec(_PredOrFunc, _PredId, ProcId, Version),
ProcNum = proc_id_to_int(ProcId),
% As documented above, for this transform, OrigName and ProcId
% both belong the caller at the call site being optimized, *not*
% the procedure being transformed, which looks very weird.
% It would probably also be a bug, if the name actually mattered.
% Note that _PredOrFunc belongs to the predicate being transformed,
% but it is ignored ...
% XXX Ignoring _PredOrFunc seems to me (zs) to be a bug.
% XXX As is separating OrigName from the suffix with only a single '_'.
% XXX The string we construct here does not fit into our current
% naming scheme at all.
string.format("%s_%d_%d", [s(OrigName), i(ProcNum), i(Version)],
TransformedName)
;
Transform = tn_aux_tabling(_PredOrFunc, UserArity, AuxTablingPredKind,
SingleProc, ProcIdInt),
% XXX Ignoring _PredOrFunc seems to me to be a bug.
% XXX The string we construct here does not fit into our current
% general naming scheme at all. However, the reference manual
% does require us (in section 20.2) to generate the names that
% we generate here.
UserArity = user_arity(UserArityInt),
( AuxTablingPredKind = atpk_statistics, KindStr = "statistics"
; AuxTablingPredKind = atpk_reset, KindStr = "reset"
),
(
SingleProc = is_single_proc,
string.format("table_%s_for_%s_%d",
[s(KindStr), s(OrigName), i(UserArityInt)], TransformedName)
;
SingleProc = is_not_single_proc,
string.format("table_%s_for_%s_%d_%d",
[s(KindStr), s(OrigName), i(UserArityInt), i(ProcIdInt)],
TransformedName)
)
;
Transform =
tn_stm_expanded(_PredOrFunc, CloneKind, Arity, PredNum, Counter),
( CloneKind = stmck_top_level, CloneKindStr = "top_level"
; CloneKind = stmck_rollback, CloneKindStr = "rollback"
; CloneKind = stmck_wrapper, CloneKindStr = "wrapper"
; CloneKind = stmck_simple_wrapper, CloneKindStr = "simple_wrapper"
; CloneKind = stmck_or_else, CloneKindStr = "or_else"
),
% XXX The string we construct here does not fit into our current
% naming scheme at all, but while stm does not work, this does not
% matter.
string.format("StmExpanded_%s_%s_%d_%d_%d",
[s(CloneKindStr), s(OrigName), i(Arity), i(PredNum), i(Counter)],
TransformedName)
;
( Transform = tn_accumulator(_, _)
; Transform = tn_deforestation(_, _)
; Transform = tn_lambda(_, _)
; Transform = tn_loop_inv(_, _, _)
; Transform = tn_tupling(_, _, _)
; Transform = tn_untupling(_, _, _)
; Transform = tn_last_call_modulo_cons(_, _)
; Transform = tn_ssdb_stdlib_proxy(_)
; Transform = tn_dep_par_conj(_, _, _)
; Transform = tn_par_distance_granularity(_, _)
; Transform = tn_par_loop_control(_, _)
; Transform = tn_structure_reuse(_, _, _)
; Transform = tn_pragma_type_spec(_, _, _)
; Transform = tn_io_tabling(_)
; Transform = tn_minimal_model_generator(_, _)
; Transform = tn_unused_args(_, _, _)
),
(
(
Transform = tn_accumulator(PredOrFunc, LNC),
TransformId = "AccFrom"
;
Transform = tn_deforestation(PredOrFunc, LNC),
TransformId = "DeforestationIn"
;
Transform = tn_lambda(PredOrFunc, LNC),
TransformId = "IntroducedFrom"
),
string.format("%s__%s",
[s(TransformId), s(pred_or_func_to_str(PredOrFunc))], Prefix),
LNC = lnc(Line, Counter),
string.format("%d__%d", [i(Line), i(Counter)], Suffix)
;
(
Transform = tn_loop_inv(PredOrFunc, ProcNum, LNC),
TransformId = "loop_inv"
;
Transform = tn_tupling(PredOrFunc, ProcNum, LNC),
TransformId = "tupling"
;
Transform = tn_untupling(PredOrFunc, ProcNum, LNC),
TransformId = "untupling"
),
string.format("%s__%s",
[s(TransformId), s(pred_or_func_to_str(PredOrFunc))], Prefix),
LNC = lnc(Line, Counter),
string.format("%d__%d_%d",
[i(Line), i(Counter), i(ProcNum)], Suffix)
;
Transform = tn_last_call_modulo_cons(PredOrFunc, VariantNum),
string.format("LCMC__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
string.format("%i", [i(VariantNum)], Suffix)
;
Transform = tn_ssdb_stdlib_proxy(PredOrFunc),
string.format("SSDB__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
% XXX Having an empty Suffix leaves Name ending with
% two consecutive underscores.
Suffix = ""
;
Transform = tn_dep_par_conj(PredOrFunc, ProcNum, ArgNums),
string.format("Parallel__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
string.format("%s_%i",
[s(bracketed_ints_to_string(ArgNums)), i(ProcNum)], Suffix)
;
Transform = tn_par_distance_granularity(PredOrFunc, Distance),
string.format("DistanceGranularityFor__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
string.format("%i", [i(Distance)], Suffix)
;
Transform = tn_par_loop_control(PredOrFunc, ProcNum),
string.format("LoopControl__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
% XXX Starting Suffix with _ leaves Name containing
% *three* consecutive underscores.
string.format("_%i", [i(ProcNum)], Suffix)
;
Transform = tn_structure_reuse(PredOrFunc, ProcNum, ArgNums),
string.format("ctgc__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
% XXX All other Transform values that specify a ProcNum
% put it at the *end* of the suffix.
string.format("%i__%s",
[i(ProcNum), s(bracketed_ints_to_string(ArgNums))], Suffix)
;
Transform =
tn_pragma_type_spec(MaybePredOrFunc, VarSet, TypeSubst),
(
MaybePredOrFunc = yes(PredOrFunc),
PredOrFuncStr = pred_or_func_to_str(PredOrFunc)
;
MaybePredOrFunc = no,
PredOrFuncStr = "pred_or_func"
),
string.format("TypeSpecOf__%s", [s(PredOrFuncStr)], Prefix),
Suffix = type_subst_to_string(VarSet, TypeSubst)
;
Transform = tn_io_tabling(PredOrFunc),
string.format("OutlinedForIOTablingFrom__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
% XXX Having an empty Suffix leaves Name ending with
% two consecutive underscores.
Suffix = ""
;
Transform = tn_minimal_model_generator(PredOrFunc, ProcNum),
string.format("GeneratorFor_%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
string.format("%i", [i(ProcNum)], Suffix)
;
Transform = tn_unused_args(PredOrFunc, ProcNum, ArgNums),
string.format("UnusedArgs__%s",
[s(pred_or_func_to_str(PredOrFunc))], Prefix),
string.format("%s_%i",
[s(bracketed_ints_to_string(ArgNums)), i(ProcNum)], Suffix)
),
% XXX The format of Suffix depends on Prefix; therefore it should
% immediately follow Prefix.
string.format("%s__%s__%s",
[s(Prefix), s(OrigName), s(Suffix)], TransformedName)
).
%---------------------------------------------------------------------------%
make_instance_method_pred_name(ClassId, MethodName, UserArity, InstanceTypes,
PredName) :-
ClassId = class_id(ClassName, _ClassArity),
ClassNameStr = sym_name_to_string_sep(ClassName, "__"),
MethodNameStr = sym_name_to_string_sep(MethodName, "__"),
% Perhaps we should include the arity in this mangled string?
make_instance_string(InstanceTypes, InstanceStr),
UserArity = user_arity(UserArityInt),
string.format("ClassMethod_for_%s____%s____%s_%d",
[s(ClassNameStr), s(InstanceStr), s(MethodNameStr), i(UserArityInt)],
PredName).
make_instance_string(InstanceTypes, InstanceStr) :-
% Note that for historical reasons, builtin types are treated as being
% unqualified (`int') rather than being qualified (`builtin.int')
% at this point.
list.map(instance_type_ctor_to_string, InstanceTypes, InstanceStrs),
string.append_list(InstanceStrs, InstanceStr).
:- pred instance_type_ctor_to_string(mer_type::in, string::out) is det.
instance_type_ctor_to_string(Type, Str) :-
type_to_ctor_det(Type, TypeCtor),
TypeCtor = type_ctor(TypeName, TypeArity),
TypeNameStr = sym_name_to_string_sep(TypeName, "__"),
string.format("%s__arity%i__", [s(TypeNameStr), i(TypeArity)], Str).
%---------------------------------------------------------------------------%
promise_pred_name(PromiseType, FileName, LineNumber) = Name :-
% This naming scheme avoids naming conflicts only by luck.
PromiseTypeStr = parse_tree_out_misc.promise_to_string(PromiseType),
string.format("%s__%d__%s",
[s(PromiseTypeStr), i(LineNumber), s(FileName)], Name).
%---------------------------------------------------------------------------%
uci_pred_name(SpecialPred, type_ctor(SymName, Arity)) = Name :-
BaseName = get_special_pred_id_target_name(SpecialPred),
% XXX The name demanglers don't yet understand predicate names for
% uci preds that have the type name and arity appended, and the
% hand-written unify/compare predicates for builtin types such as
% typeinfo have the plain base names. Therefore replacing semidet_fail
% with semidet_succeed here is useful only for debugging the compiler.
( if semidet_fail then
Name = BaseName ++ sym_name_to_string(SymName)
++ "/" ++ int_to_string(Arity)
else
Name = BaseName
).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
pred_origin_to_user_string(Origin) = Str :-
(
Origin = origin_user(OriginUser),
Str = origin_user_to_user_dev_string(user, OriginUser)
;
Origin = origin_compiler(OriginCompiler),
Str = origin_compiler_to_user_dev_string(user, OriginCompiler)
;
( Origin = origin_pred_transform(_, SubOrigin, _)
; Origin = origin_proc_transform(_, SubOrigin, _, _)
),
BaseOrigin = get_base_origin(SubOrigin),
BaseOriginStr = pred_origin_to_user_string(BaseOrigin),
string.format("a compiler-transformed version of %s",
[s(BaseOriginStr)], Str)
).
pred_origin_to_dev_string(Origin) = Str :-
(
Origin = origin_user(OriginUser),
Str = origin_user_to_user_dev_string(dev, OriginUser)
;
Origin = origin_compiler(OriginCompiler),
Str = origin_compiler_to_user_dev_string(dev, OriginCompiler)
;
(
Origin = origin_pred_transform(PredTransform, SubOrigin, _),
TransformStr = pred_transform_to_dev_string(PredTransform)
;
Origin = origin_proc_transform(ProcTransform, SubOrigin, _, _),
TransformStr = proc_transform_to_dev_string(ProcTransform)
),
SubOriginStr = pred_origin_to_dev_string(SubOrigin),
string.format("%s transformed by %s",
[s(SubOriginStr), s(TransformStr)], Str)
).
:- type user_or_dev
---> user
; dev.
:- inst user for user_or_dev/0
---> user.
:- inst dev for user_or_dev/0
---> dev.
:- func origin_user_to_user_dev_string(user_or_dev, user_made) = string.
:- mode origin_user_to_user_dev_string(in(user), in) = out is det.
:- mode origin_user_to_user_dev_string(in(dev), in) = out is det.
origin_user_to_user_dev_string(UserOrDev, OriginUser) = Str :-
(
OriginUser = user_made_pred(PredOrFunc, SymName, UserArity),
UserArity = user_arity(UserArityInt),
(
UserOrDev = user,
Str = pf_sym_name_user_arity_to_string(PredOrFunc,
SymName, UserArityInt)
;
UserOrDev = dev,
Str = pf_sym_name_user_arity_to_unquoted_string(PredOrFunc,
SymName, UserArityInt)
)
;
OriginUser = user_made_lambda(FileName, LineNumber, SeqNum),
string.format("lambda expression #%d at %s/%d",
[i(SeqNum), s(FileName), i(LineNumber)], Str)
;
OriginUser = user_made_class_method(ClassId, MethodId),
(
UserOrDev = user,
MethodIdStr = pf_sym_name_user_arity_to_string(MethodId)
;
UserOrDev = dev,
MethodIdStr = pf_sym_name_user_arity_to_unquoted_string(MethodId)
),
ClassId = class_id(ClassSymName, ClassArity),
ClassNameStr = sym_name_to_string(ClassSymName),
string.format("class method %s for %s/%d",
[s(MethodIdStr), s(ClassNameStr), i(ClassArity)], Str)
;
OriginUser = user_made_instance_method(MethodId,
MethodConstraints),
(
UserOrDev = user,
MethodIdStr = pf_sym_name_user_arity_to_string(MethodId)
;
UserOrDev = dev,
MethodIdStr = pf_sym_name_user_arity_to_unquoted_string(MethodId)
),
MethodConstraints = instance_method_constraints(ClassId,
InstanceTypes, _, _),
ClassId = class_id(ClassName, _),
ClassStr = sym_name_to_string(ClassName),
TypeStrs = mercury_types_to_string(varset.init, print_name_only,
InstanceTypes),
(
UserOrDev = user,
string.format("instance method %s for `%s(%s)'",
[s(MethodIdStr), s(ClassStr), s(TypeStrs)], Str)
;
UserOrDev = dev,
string.format("instance method %s for %s(%s)",
[s(MethodIdStr), s(ClassStr), s(TypeStrs)], Str)
)
;
OriginUser = user_made_assertion(PromiseType, FileName, LineNumber),
PromiseTypeStr = parse_tree_out_misc.promise_to_string(PromiseType),
string.format("%s declaration at %s:%d",
[s(PromiseTypeStr), s(FileName), i(LineNumber)], Str)
).
:- func origin_compiler_to_user_dev_string(user_or_dev, compiler_made)
= string.
:- mode origin_compiler_to_user_dev_string(in(user), in) = out is det.
:- mode origin_compiler_to_user_dev_string(in(dev), in) = out is det.
origin_compiler_to_user_dev_string(UserOrDev, OriginCompiler) = Str :-
(
OriginCompiler = made_for_uci(SpecialId, TypeCtor),
special_pred_description(SpecialId, PredDescr),
TypeCtor = type_ctor(TypeSymName, TypeArity),
( if TypeArity = 0 then
string.format("%s for type %s",
[s(PredDescr), s(sym_name_to_string(TypeSymName))], Str)
else
string.format("%s for type constructor %s/%d",
[s(PredDescr), s(sym_name_to_string(TypeSymName)),
i(TypeArity)], Str)
)
;
OriginCompiler = made_for_tabling(BasePredId, TablingAuxPredKind),
(
UserOrDev = user,
BasePredIdStr = pf_sym_name_user_arity_to_string(BasePredId)
;
UserOrDev = dev,
BasePredIdStr =
pf_sym_name_user_arity_to_unquoted_string(BasePredId)
),
(
TablingAuxPredKind = tabling_aux_pred_stats,
Str = "table statistics predicate for " ++ BasePredIdStr
;
TablingAuxPredKind = tabling_aux_pred_reset,
Str = "table reset predicate for " ++ BasePredIdStr
)
;
OriginCompiler = made_for_solver_repn(TypeCtor, SolverAuxPredKind),
TypeCtorStr = type_ctor_to_string(TypeCtor),
(
SolverAuxPredKind = solver_type_to_ground_pred,
Str = "to ground representation predicate for " ++ TypeCtorStr
;
SolverAuxPredKind = solver_type_to_any_pred,
Str = "to any representation predicate for " ++ TypeCtorStr
;
SolverAuxPredKind = solver_type_from_ground_pred,
Str = "from ground representation predicate for " ++ TypeCtorStr
;
SolverAuxPredKind = solver_type_from_any_pred,
Str = "from any representation predicate for " ++ TypeCtorStr
)
;
OriginCompiler = made_for_deforestation(LineNumber, SeqNum),
string.format("deforestation-created predicate #%d near line %d",
[i(SeqNum), i(LineNumber)], Str)
;
OriginCompiler = made_for_mutable(_ModuleName, Name, MutablePredKind),
MutablePredKindStr = mutable_kind_to_user_dev_string(MutablePredKind),
string.format("%s for mutable %s",
[s(MutablePredKindStr), s(Name)], Str)
;
OriginCompiler = made_for_initialise(FileName, LineNumber),
string.format("initialise declaration at %s:%d",
[s(FileName), i(LineNumber)], Str)
;
OriginCompiler = made_for_finalise(FileName, LineNumber),
string.format("finalise declaration at %s:%d",
[s(FileName), i(LineNumber)], Str)
).
:- func mutable_kind_to_user_dev_string(mutable_pred_kind) = string.
mutable_kind_to_user_dev_string(MutablePredKind) = MutablePredKindStr :-
(
MutablePredKind = mutable_pred_std_get,
MutablePredKindStr = "std get predicate"
;
MutablePredKind = mutable_pred_std_set,
MutablePredKindStr = "std set predicate"
;
MutablePredKind = mutable_pred_io_get,
MutablePredKindStr = "io get predicate"
;
MutablePredKind = mutable_pred_io_set,
MutablePredKindStr = "io set predicate"
;
MutablePredKind = mutable_pred_unsafe_get,
MutablePredKindStr = "unsafe get predicate"
;
MutablePredKind = mutable_pred_unsafe_set,
MutablePredKindStr = "unsafe set predicate"
;
MutablePredKind = mutable_pred_constant_get,
MutablePredKindStr = "constant get predicate"
;
MutablePredKind = mutable_pred_constant_secret_set,
MutablePredKindStr = "constant secret set predicate"
;
MutablePredKind = mutable_pred_lock,
MutablePredKindStr = "lock predicate"
;
MutablePredKind = mutable_pred_unlock,
MutablePredKindStr = "unlock predicate"
;
MutablePredKind = mutable_pred_pre_init,
MutablePredKindStr = "preinit predicate"
;
MutablePredKind = mutable_pred_init,
MutablePredKindStr = "init predicate"
).
:- inst base_pred_origin for pred_origin/0
---> origin_user(ground)
; origin_compiler(ground).
:- func get_base_origin(pred_origin) = pred_origin.
:- mode get_base_origin(in) = out(base_pred_origin) is det.
get_base_origin(Origin) = BaseOrigin :-
(
( Origin = origin_user(_)
; Origin = origin_compiler(_)
),
BaseOrigin = Origin
;
( Origin = origin_pred_transform(_, SubOrigin, _)
; Origin = origin_proc_transform(_, SubOrigin, _, _)
),
BaseOrigin = get_base_origin(SubOrigin)
).
:- func pred_transform_to_dev_string(pred_transform) = string.
pred_transform_to_dev_string(PredTransform) = Str :-
(
PredTransform = pred_transform_pragma_type_spec(Substs),
SubstStrs = list.map(dump_subst, one_or_more_to_list(Substs)),
SubstsStr = string.join_list(", ", SubstStrs),
string.format("type specialization %s", [s(SubstsStr)], Str)
;
PredTransform = pred_transform_distance_granularity(Distance),
string.format("distance granularity with distance %d",
[i(Distance)], Str)
;
PredTransform = pred_transform_table_generator,
Str = "generator for own-stack minimal model tabling"
;
PredTransform = pred_transform_structure_reuse,
Str = "structure reuse"
;
PredTransform = pred_transform_ssdebug(PredOrFunc),
string.format("proxy for stdlib %s for source-to-source debugging",
[s(pred_or_func_to_full_str(PredOrFunc))], Str)
).
:- func proc_transform_to_dev_string(proc_transform) = string.
proc_transform_to_dev_string(ProcTransform) = Str :-
(
ProcTransform = proc_transform_user_type_spec(CallerPredId,
CallerProcId),
CallerPredIdInt = pred_id_to_int(CallerPredId),
CallerProcIdInt = proc_id_to_int(CallerProcId),
string.format("user-direct type specialization for pred %d, proc %d",
[i(CallerPredIdInt), i(CallerProcIdInt)], Str)
;
ProcTransform = proc_transform_higher_order_spec(SeqNum),
string.format("higher order specialization #%d", [i(SeqNum)], Str)
;
ProcTransform = proc_transform_unused_args(Posns),
PosnsStr = string.join_list(", ", list.map(int_to_string, Posns)),
( if Posns = [_, _ | _] then Plural = "s" else Plural = "" ),
string.format("unused arg elimination for arg%s %s",
[s(Plural), s(PosnsStr)], Str)
;
ProcTransform = proc_transform_accumulator(_LineNum, Posns),
PosnsStr = string.join_list(", ", list.map(int_to_string, Posns)),
( if Posns = [_, _ | _] then Plural = "s" else Plural = "" ),
string.format("accumulator introduction on arg%s %s",
[s(Plural), s(PosnsStr)], Str)
;
ProcTransform = proc_transform_loop_inv(LineNum, SeqNum),
string.format("loop invariant hoisting on line %d, #%d",
[i(LineNum), i(SeqNum)], Str)
;
ProcTransform = proc_transform_tuple(LineNum, SeqNum),
string.format("tupling on line %d, #%d",
[i(LineNum), i(SeqNum)], Str)
;
ProcTransform = proc_transform_untuple(LineNum, SeqNum),
string.format("untupling on line %d, #%d",
[i(LineNum), i(SeqNum)], Str)
;
ProcTransform = proc_transform_dep_par_conj(_),
Str = "dependent parallel conjunction transform"
;
ProcTransform = proc_transform_par_loop_ctrl,
Str = "parallel loop control transform"
;
ProcTransform = proc_transform_lcmc(SeqNum, Posns),
PosnsStr = string.join_list(", ", list.map(int_to_string, Posns)),
( if Posns = [_, _ | _] then Plural = "s" else Plural = "" ),
string.format("last-call-modulo-construct on arg%s %s, #%d",
[s(Plural), s(PosnsStr), i(SeqNum)], Str)
;
ProcTransform = proc_transform_stm_expansion,
Str = "software transactional memory transform"
;
ProcTransform = proc_transform_io_tabling,
Str = "I/O tabling"
;
ProcTransform = proc_transform_direct_arg_in_out,
Str = "direct arg in out transform"
).
%---------------------------------------------------------------------------%
dump_origin(TVarSet, VarNamePrint, Prefix, Origin) = Str :-
(
Origin = origin_user(OriginUser),
(
OriginUser = user_made_pred(PredOrFunc, SymName, UserArity),
UserArity = user_arity(UserArityInt),
string.format("%s user defined %s %s/%d\n",
[s(Prefix), s(pred_or_func_to_full_str(PredOrFunc)),
s(sym_name_to_string(SymName)), i(UserArityInt)], Str)
;
OriginUser = user_made_lambda(FileName, LineNumber, SeqNum),
string.format("%s lambda expression file %s, line %d, seqnum %d\n",
[s(Prefix), s(FileName), i(LineNumber), i(SeqNum)], Str)
;
OriginUser = user_made_class_method(ClassId, MethodId),
ClassId = class_id(ClassSymName, ClassArity),
MethodId = pred_pf_name_arity(MethodPredOrFunc,
MethodSymName, MethodUserArity),
MethodUserArity = user_arity(MethodUserArityInt),
string.format("%s class method %s %s/%d for %s/%d\n",
[s(Prefix), s(pred_or_func_to_full_str(MethodPredOrFunc)),
s(sym_name_to_string(MethodSymName)), i(MethodUserArityInt),
s(sym_name_to_string(ClassSymName)), i(ClassArity)], Str)
;
OriginUser = user_made_instance_method(MethodId,
MethodConstraints),
MethodId = pred_pf_name_arity(MethodPredOrFunc,
MethodSymName, MethodUserArity),
MethodUserArity = user_arity(MethodUserArityInt),
MethodConstraints = instance_method_constraints(ClassId,
InstanceTypes, InstanceConstraints, ClassMethodConstraints),
ClassId = class_id(ClassSymName, ClassArity),
ClassConstraint = constraint(ClassSymName, InstanceTypes),
string.format("%s instance method %s %s/%d for class %s/%d\n",
[s(Prefix), s(pred_or_func_to_str(MethodPredOrFunc)),
s(sym_name_to_string(MethodSymName)), i(MethodUserArityInt),
s(sym_name_to_string(ClassSymName)), i(ClassArity)], Line1),
Line2 = "% instance type vector:\n",
Line3 = mercury_constraint_to_string(TVarSet, VarNamePrint,
ClassConstraint),
Lines4 = dump_origin_constraints("instance constraints",
TVarSet, VarNamePrint, InstanceConstraints),
ClassMethodConstraints = univ_exist_constraints(
MethodUnivConstraints, MethodExistConstraints),
Lines5 = dump_origin_constraints("method universal constraints",
TVarSet, VarNamePrint, MethodUnivConstraints),
Lines6 = dump_origin_constraints("method existential constraints",
TVarSet, VarNamePrint, MethodExistConstraints),
Str = Line1 ++ Line2 ++ Line3 ++ Lines4 ++ Lines5 ++ Lines6
;
OriginUser = user_made_assertion(PromiseType,
FileName, LineNumber),
PromiseTypeStr =
parse_tree_out_misc.promise_to_string(PromiseType),
string.format("%s %s declaration at %s:%d",
[s(Prefix), s(PromiseTypeStr), s(FileName), i(LineNumber)],
Str)
)
;
Origin = origin_compiler(OriginCompiler),
(
OriginCompiler = made_for_uci(SpecialPredId, TypeCtor),
(
SpecialPredId = spec_pred_unify,
SpecialPredIdStr = "unify"
;
SpecialPredId = spec_pred_compare,
SpecialPredIdStr = "compare"
;
SpecialPredId = spec_pred_index,
SpecialPredIdStr = "index"
),
string.format("%s %s pred for %s\n",
[s(Prefix), s(SpecialPredIdStr),
s(type_name_to_string(TypeCtor))], Str)
;
OriginCompiler = made_for_deforestation(LineNum, SeqNum),
string.format("%s deforestation: line %d, seqnum %d\n",
[s(Prefix), i(LineNum), i(SeqNum)], Str)
;
OriginCompiler = made_for_solver_repn(TypeCtor, SolverAuxPredKind),
TypeCtorStr = type_ctor_to_string(TypeCtor),
(
SolverAuxPredKind = solver_type_to_ground_pred,
SolverAuxPredKindStr = "to ground conversion predicate"
;
SolverAuxPredKind = solver_type_to_any_pred,
SolverAuxPredKindStr = "to any conversion predicate"
;
SolverAuxPredKind = solver_type_from_ground_pred,
SolverAuxPredKindStr = "from ground conversion predicate"
;
SolverAuxPredKind = solver_type_from_any_pred,
SolverAuxPredKindStr = "from any conversion predicate"
),
string.format("%s %s for %s\n",
[s(Prefix), s(SolverAuxPredKindStr), s(TypeCtorStr)], Str)
;
OriginCompiler = made_for_tabling(BasePredCallId,
TablingAuxPredKind),
BasePredStr = pf_sym_name_user_arity_to_string(BasePredCallId),
(
TablingAuxPredKind = tabling_aux_pred_stats,
TablingAuxPredKindStr = "table statistics predicate"
;
TablingAuxPredKind = tabling_aux_pred_reset,
TablingAuxPredKindStr = "table reset predicate"
),
string.format("%s %s for %s\n",
[s(Prefix), s(TablingAuxPredKindStr), s(BasePredStr)], Str)
;
OriginCompiler = made_for_mutable(MutableModuleName, MutableName,
MutablePredKind),
MutableModuleNameStr = sym_name_to_string(MutableModuleName),
MutablePredKindStr =
mutable_kind_to_user_dev_string(MutablePredKind),
string.format("%s %s for mutable %s in module %s\n",
[s(Prefix), s(MutablePredKindStr), s(MutableName),
s(MutableModuleNameStr)], Str)
;
OriginCompiler = made_for_initialise(FileName, LineNumber),
string.format("%s initialise predicate, file %s, line %d\n",
[s(Prefix), s(FileName), i(LineNumber)], Str)
;
OriginCompiler = made_for_finalise(FileName, LineNumber),
string.format("%s finalise predicate, file %s, line %d\n",
[s(Prefix), s(FileName), i(LineNumber)], Str)
)
;
( Origin = origin_pred_transform(_, _, _)
; Origin = origin_proc_transform(_, _, _, _)
),
dump_transformed_origin(TVarSet, VarNamePrint, Origin, _, Strs),
string.append_list(Strs, Str)
).
:- pred dump_transformed_origin(tvarset::in, var_name_print::in,
pred_origin::in, int::out, list(string)::out) is det.
dump_transformed_origin(TVarSet, VarNamePrint, Origin,
TransformsPrinted, Strs) :-
(
( Origin = origin_user(_)
; Origin = origin_compiler(_)
),
TransformsPrinted = 0,
Prefix = "% Origin base:",
OriginStr = dump_origin(TVarSet, VarNamePrint, Prefix, Origin),
Strs = [OriginStr]
;
Origin = origin_pred_transform(PredTransform, SubOrigin, PredId),
dump_transformed_origin(TVarSet, VarNamePrint, SubOrigin,
SubTransformsPrinted, SubStrs),
TransformsPrinted = SubTransformsPrinted + 1,
PredIdInt = pred_id_to_int(PredId),
TransformStr = pred_transform_to_dev_string(PredTransform),
string.format("%% Transform %d on pred %d:\n%% %s\n",
[i(TransformsPrinted), i(PredIdInt), s(TransformStr)], MainStr),
Strs = SubStrs ++ [MainStr]
;
Origin = origin_proc_transform(ProcTransform, SubOrigin,
PredId, ProcId),
dump_transformed_origin(TVarSet, VarNamePrint, SubOrigin,
SubTransformsPrinted, SubStrs),
TransformsPrinted = SubTransformsPrinted + 1,
PredIdInt = pred_id_to_int(PredId),
ProcIdInt = proc_id_to_int(ProcId),
TransformStr = proc_transform_to_dev_string(ProcTransform),
string.format("%% Transform %d on pred %d, proc %d:\n%% %s\n",
[i(TransformsPrinted), i(PredIdInt), i(ProcIdInt),
s(TransformStr)], MainStr),
Strs = SubStrs ++ [MainStr]
).
:- func dump_origin_constraints(string, tvarset, var_name_print,
list(prog_constraint)) = string.
dump_origin_constraints(Msg, TVarSet, VarNamePrint, Constraints) = Str :-
(
Constraints = [],
string.format("%% %s: none\n", [s(Msg)], Str)
;
Constraints = [_ | _],
string.format("%% %s:\n", [s(Msg)], HeaderLine),
ConstraintLines = list.map(
dump_origin_constraint(TVarSet, VarNamePrint),
Constraints),
string.append_list([HeaderLine | ConstraintLines], Str)
).
:- func dump_origin_constraint(tvarset, var_name_print, prog_constraint)
= string.
dump_origin_constraint(TVarSet, VarNamePrint, Constraint) = Str :-
Str = string.format("%% %s\n",
[s(mercury_constraint_to_string(TVarSet, VarNamePrint, Constraint))]).
%---------------------------------------------------------------------------%
layout_origin_name(Origin, Name0) = Name :-
(
Origin = origin_user(OriginUser),
(
( OriginUser = user_made_pred(_, _, _)
; OriginUser = user_made_class_method(_, _)
; OriginUser = user_made_instance_method(_, _)
; OriginUser = user_made_assertion(_, _, _)
),
Name = Name0
;
OriginUser = user_made_lambda(FileName0, LineNum, SeqNum),
( if string.append("IntroducedFrom", _, Name0) then
string.replace_all(FileName0, ".", "_", FileName),
( if SeqNum > 1 then
string.format("lambda%d_%s_%d",
[i(SeqNum), s(FileName), i(LineNum)], Name)
else
string.format("lambda_%s_%d",
[s(FileName), i(LineNum)], Name)
)
else
% If the lambda pred has a meaningful name, use it.
% This happens when the lambda is a partial application
% that happens to supply zero arguments.
Name = Name0
)
)
;
Origin = origin_compiler(OriginCompiler),
(
OriginCompiler = made_for_uci(_SpecialPredId, _TypeCtor),
Name = Name0
% We can't use the following code until we have adapted the code
% in the runtime and trace directories to handle the names
% of special preds the same way as we do user-defined names.
% (
% SpecialPredId = unify,
% SpecialName = "unify"
% ;
% SpecialPredId = compare,
% SpecialName = "compare"
% ;
% SpecialPredId = index,
% SpecialName = "index"
% ),
% TypeCtor = TypeSymName - TypeArity,
% TypeName = sym_name_to_string(TypeSymName),
% string.format("%s_for_%s_%d",
% [s(SpecialName), s(TypeName), i(TypeArity)], Name)
;
( OriginCompiler = made_for_deforestation(_, _)
; OriginCompiler = made_for_solver_repn(_, _)
; OriginCompiler = made_for_tabling(_, _)
; OriginCompiler = made_for_mutable(_, _, _)
; OriginCompiler = made_for_initialise(_, _)
; OriginCompiler = made_for_finalise(_, _)
),
Name = Name0
)
;
Origin = origin_pred_transform(PredTransform, OldOrigin, _),
OldName = layout_origin_name(OldOrigin, ""),
( if OldName = "" then
Name = Name0
else
Name = OldName ++ "_" ++ layout_pred_transform_name(PredTransform)
)
;
Origin = origin_proc_transform(ProcTransform, OldOrigin, _, ProcId),
OldName = layout_origin_name(OldOrigin, ""),
( if
% for io_tabling, this preserves old behavior
( OldName = ""
; ProcTransform = proc_transform_io_tabling
)
then
Name = Name0
else
Name = OldName ++ "_" ++
layout_proc_transform_name(ProcTransform, ProcId)
)
).
:- func layout_pred_transform_name(pred_transform) = string.
layout_pred_transform_name(PredTransform) = Name :-
(
PredTransform = pred_transform_pragma_type_spec(Substs),
Name = string.join_list("_", list.map(subst_to_name,
one_or_more_to_list(Substs)))
;
PredTransform = pred_transform_distance_granularity(Distance),
Name = "distance_granularity_" ++ int_to_string(Distance)
;
PredTransform = pred_transform_table_generator,
Name = "table_gen"
;
PredTransform = pred_transform_structure_reuse,
Name = "structure_reuse"
;
PredTransform = pred_transform_ssdebug(_),
Name = "ssdebug"
).
:- func layout_proc_transform_name(proc_transform, proc_id) = string.
layout_proc_transform_name(ProcTransform, ProcId) = Name :-
(
ProcTransform = proc_transform_user_type_spec(_CallerPredId,
CallerProcId),
Name = "hoproc" ++ int_to_string(proc_id_to_int(CallerProcId))
;
ProcTransform = proc_transform_higher_order_spec(SeqNum),
Name = "ho" ++ int_to_string(SeqNum)
;
ProcTransform = proc_transform_unused_args(Posns),
Name = "ua_" ++ string.join_list("_", list.map(int_to_string, Posns))
;
ProcTransform = proc_transform_accumulator(_LineNum, Posns),
Name = "acc_" ++ string.join_list("_", list.map(int_to_string, Posns))
;
ProcTransform = proc_transform_loop_inv(_LineNum, _SeqNum),
Name = "inv_" ++ int_to_string(proc_id_to_int(ProcId))
;
ProcTransform = proc_transform_tuple(_LineNum, _SeqNum),
Name = "tup_" ++ int_to_string(proc_id_to_int(ProcId))
;
ProcTransform = proc_transform_untuple(_LineNum, _SeqNum),
Name = "untup_" ++ int_to_string(proc_id_to_int(ProcId))
;
ProcTransform = proc_transform_dep_par_conj(_),
Name = "dep_par_conj_"
;
ProcTransform = proc_transform_par_loop_ctrl,
Name = "par_lc"
;
ProcTransform = proc_transform_lcmc(_SeqNum, ArgPos),
Name = "retptr_" ++ int_to_string(proc_id_to_int(ProcId)) ++
"_args" ++ underscore_ints_to_string(ArgPos)
;
ProcTransform = proc_transform_stm_expansion,
Name = "stm_expansion"
;
ProcTransform = proc_transform_io_tabling,
Name = "io_tabling"
;
ProcTransform = proc_transform_direct_arg_in_out,
Name = "daio"
).
%---------------------------------------------------------------------------%
layout_origin_name_new(Origin) = Str :-
% The structure of the pred_origin will be indicated by occurrences
% of the string "mrtq". The initial "mrt" stands for "Mercury runtime",
% and the "q" is there to reduce the need for stuffing (see below).
%
% Each pred and proc transform starts with "mrtq_", and any string
% we get from the user will have its end indicated by "_mrtq_".
% To make this work, those user-provided strings will be "mrtq-stuffed",
% which means that all occurrences of "mrtq" in them replaced by "mrtqq".
% This prevents "mrtq_" from occurring in the stuffed strings.
% Debuggers and profilers will have to "unstuff" these user-provided parts
% of the stuffed strings once they have parsed the relevant part of
% the string.
%
% Likewise, the parts of the predicate origins that deal with types
% will have the structure of those types indicated by occurrences of "txq",
% where the "t" stands for "type" and the "xq" is there to reduce the need
% for "txq-stuffing".
%
% NOTE To make this code suitable for generating names for the functions/
% methods that implement the predicates whose origins we are processing,
% all the user-provided strings we handle would have to be converted
% (in a reversible way) to use only characters that the target language
% allows in identifiers. This means letters, numbers and underscores.
% The way we construct Str, we guarantee that it starts with one of
% "pred_", "func_" or "mrtq_", which guarantees that we don't fall foul
% of limitations about what characters can *start* an identifier
% in our target languages.
(
Origin = origin_user(OriginUser),
(
OriginUser = user_made_pred(PorF, SymName, UserArity),
PorFStr = pred_or_func_to_str(PorF),
StuffedNameStr = mrtq_stuff_sym_name(SymName),
UserArity = user_arity(UserArityInt),
% NOTE We could add an "mrtq_" prefix to Str. This should
% not be needed in layout structures, but when we use
% a generalized version of this code to generate target language
% identifiers, having *all* procedure names start with "mrtq_"
% could in theory allow us to stop adding a "mercury_" prefix
% to those names. Unfortunately, this is not practical, because
% the handwritten code of the runtime system uses the "mercury_"
% prefix, and any switchover to using a "mrtq_" prefix instead
% would require this code to be changed, or the callers of
% predicates defined in the runtime would have to replace
% the "mrtq_" prefix constructed here with "mercury_".
% Neither is easy to do.
string.format("%s_%s_mrtq_%d",
[s(PorFStr), s(StuffedNameStr), i(UserArityInt)], Str)
;
OriginUser = user_made_class_method(ClassId, PFSymNameArity),
ClassId = class_id(ClassSymName, ClassArity),
StuffedClassNameStr = mrtq_stuff_sym_name(ClassSymName),
PFSymNameArity = pred_pf_name_arity(PorF, MethodSymName,
MethodUserArity),
PorFStr = pred_or_func_to_str(PorF),
StuffedMethodNameStr = mrtq_stuff_sym_name(MethodSymName),
MethodUserArity = user_arity(MethodUserArityInt),
string.format("mrtq_class_%s_mrtq_%d_%s_%s_mrtq_%d",
[s(StuffedClassNameStr), i(ClassArity),
s(PorFStr), s(StuffedMethodNameStr), i(MethodUserArityInt)],
Str)
;
OriginUser = user_made_instance_method(PFSymNameArity,
MethodConstraints),
PFSymNameArity = pred_pf_name_arity(PorF, MethodSymName,
MethodUserArity),
PorFStr = pred_or_func_to_str(PorF),
StuffedMethodNameStr = mrtq_stuff_sym_name(MethodSymName),
MethodUserArity = user_arity(MethodUserArityInt),
MethodConstraints = instance_method_constraints(ClassId,
InstanceTypes, _, _),
ClassId = class_id(ClassSymName, ClassArity),
StuffedClassNameStr = mrtq_stuff_sym_name(ClassSymName),
InstanceTypeStrs = list.map(type_to_txq_mrtq_stuffed_string,
InstanceTypes),
MoreInstanceTypeStrs = list.map((func(S) = "_mrtq_m_" ++ S),
InstanceTypeStrs),
MoreInstanceTypesStr = string.append_list(MoreInstanceTypeStrs),
string.format("mrtq_instance_%s_mrtq_%d_%s_%s_mrtq_%d_%s_mrtq",
[s(StuffedClassNameStr), i(ClassArity),
s(PorFStr), s(StuffedMethodNameStr), i(MethodUserArityInt),
s(MoreInstanceTypesStr)], Str)
;
OriginUser = user_made_assertion(PromiseType, FileName0, LineNum),
(
PromiseType = promise_type_true,
PromiseStr = "assert"
;
PromiseType = promise_type_exclusive,
PromiseStr = "excl"
;
PromiseType = promise_type_exhaustive,
PromiseStr = "exh"
;
PromiseType = promise_type_exclusive_exhaustive,
PromiseStr = "exclexh"
),
string.replace_all(FileName0, ".", "_", FileName1),
FileName = mrtq_stuff(FileName1),
string.format("mrtq_%s_%s_mrtq_%d",
[s(PromiseStr), s(FileName), i(LineNum)], Str)
;
OriginUser = user_made_lambda(FileName0, LineNum, SeqNum),
string.replace_all(FileName0, ".", "_", FileName1),
FileName = mrtq_stuff(FileName1),
string.format("mrtq_lambda_%d_%s_mrtq_%d",
[i(SeqNum), s(FileName), i(LineNum)], Str)
)
;
Origin = origin_compiler(OriginCompiler),
(
OriginCompiler = made_for_uci(Kind, TypeCtor),
( Kind = spec_pred_unify, UciName = "uni"
; Kind = spec_pred_compare, UciName = "cmp"
; Kind = spec_pred_index, UciName = "idx"
),
TypeCtor = type_ctor(TypeCtorSymName, TypeCtorArity),
TypeCtorStr = sym_name_to_string(TypeCtorSymName),
StuffedTypeCtorStr = mrtq_stuff(TypeCtorStr),
string.format("mrtq_%s_%s_%d",
[s(UciName), s(StuffedTypeCtorStr), i(TypeCtorArity)], Str)
;
OriginCompiler = made_for_deforestation(LineNum, SeqNum),
string.format("mrtq_deforst_%d_%d", [i(LineNum), i(SeqNum)], Str)
;
OriginCompiler = made_for_solver_repn(TypeCtor, PredKind),
TypeCtor = type_ctor(TypeCtorSymName, TypeCtorArity),
TypeCtorStr = sym_name_to_string(TypeCtorSymName),
StuffedTypeCtorStr = mrtq_stuff(TypeCtorStr),
(
PredKind = solver_type_to_ground_pred,
PredKindStr = "tognd"
;
PredKind = solver_type_to_any_pred,
PredKindStr = "toany"
;
PredKind = solver_type_from_ground_pred,
PredKindStr = "fromgnd"
;
PredKind = solver_type_from_any_pred,
PredKindStr = "fromany"
),
string.format("mrtq_solver_%s_%s_mrtq_%d",
[s(PredKindStr), s(StuffedTypeCtorStr), i(TypeCtorArity)], Str)
;
OriginCompiler = made_for_tabling(PFSymNameArity, Kind),
PFSymNameArity = pred_pf_name_arity(PorF, SymName, UserArity),
PorFStr = pred_or_func_to_str(PorF),
StuffedNameStr = mrtq_stuff_sym_name(SymName),
UserArity = user_arity(UserArityInt),
( Kind = tabling_aux_pred_stats, KindStr = "stats"
; Kind = tabling_aux_pred_reset, KindStr = "reset"
),
string.format("mrtq_table_%s_%s_%s_mrtq_%d",
[s(KindStr), s(PorFStr), s(StuffedNameStr), i(UserArityInt)],
Str)
;
OriginCompiler = made_for_mutable(_ModuleName, MutableName,
Kind),
StuffedNameStr = mrtq_stuff(MutableName),
( Kind = mutable_pred_std_get, KindStr = "get"
; Kind = mutable_pred_std_set, KindStr = "set"
; Kind = mutable_pred_io_get, KindStr = "ioget"
; Kind = mutable_pred_io_set, KindStr = "ioset"
; Kind = mutable_pred_unsafe_get, KindStr = "uget"
; Kind = mutable_pred_unsafe_set, KindStr = "uset"
; Kind = mutable_pred_constant_get, KindStr = "cget"
; Kind = mutable_pred_constant_secret_set, KindStr = "cset"
; Kind = mutable_pred_lock, KindStr = "lock"
; Kind = mutable_pred_unlock, KindStr = "unlock"
; Kind = mutable_pred_pre_init, KindStr = "preinit"
; Kind = mutable_pred_init, KindStr = "init"
),
string.format("mrtq_mutable_%s_%s",
[s(KindStr), s(StuffedNameStr)], Str)
;
(
OriginCompiler = made_for_initialise(FileName0, LineNum),
KindStr = "initialise"
;
OriginCompiler = made_for_finalise(FileName0, LineNum),
KindStr = "finalise"
),
string.replace_all(FileName0, ".", "_", FileName1),
FileName = mrtq_stuff(FileName1),
string.format("mrtq_%s_%s_mrtq_%d",
[s(KindStr), s(FileName), i(LineNum)], Str)
)
;
Origin = origin_pred_transform(PredTransform, OldOrigin, _),
OldStr = layout_origin_name_new(OldOrigin),
PredTransformStr = layout_pred_transform_name_new(PredTransform),
% "pts" and "pte" stand for "pred transform start/end".
string.format("%s_mrtq_pts_%s_mrtq_pte",
[s(OldStr), s(PredTransformStr)], Str)
;
Origin = origin_proc_transform(ProcTransform, OldOrigin, _, ProcId),
OldStr = layout_origin_name_new(OldOrigin),
ProcTransformStr =
layout_proc_transform_name_new(ProcTransform, ProcId),
% "pmts" and "pmte" stand for "pred mode transform start/end".
string.format("%s_mrtq_pmts_%s_mrtq_pmte",
[s(OldStr), s(ProcTransformStr)], Str)
).
% Return a representation of the pred_transform. The result string
% will not start or end with an underscore, and will not contain
% the string "mrtq_".
%
:- func layout_pred_transform_name_new(pred_transform) = string.
layout_pred_transform_name_new(PredTransform) = Str :-
(
PredTransform = pred_transform_pragma_type_spec(Substs),
SubstList = one_or_more_to_list(Substs),
SubstStrs = list.map(subst_to_mrtq_stuffed_string, SubstList),
SubstsStr = string.join_list("_txq_s_", SubstStrs),
string.format("typespec_%s", [s(SubstsStr)], Str)
;
PredTransform = pred_transform_distance_granularity(Distance),
string.format("distgran_%d", [i(Distance)], Str)
;
PredTransform = pred_transform_table_generator,
Str = "tablegen"
;
PredTransform = pred_transform_structure_reuse,
Str = "structreuse"
;
PredTransform = pred_transform_ssdebug(_),
Str = "ssdb"
).
% Return a representation of the proc_transform. The result string
% will not start or end with an underscore, and will not contain
% the string "mrtq_".
%
:- func layout_proc_transform_name_new(proc_transform, proc_id) = string.
layout_proc_transform_name_new(ProcTransform, ProcId) = Str :-
ProcIdInt = proc_id_to_int(ProcId),
(
ProcTransform = proc_transform_user_type_spec(_CallerPredId,
_CallerProcId),
% XXX This seems to be inadequate, because a predicate or function
% may have more than one type_spec pragma for it with different type
% substitutions, and this does not distinguish between them.
% When constructing names using tn_user_type_spec, we include the
% proc_id, but this does not address the issue.
Str = "usertypespec"
;
ProcTransform = proc_transform_higher_order_spec(SeqNum),
string.format("ho_%d", [i(SeqNum)], Str)
;
ProcTransform = proc_transform_unused_args(ArgPosns),
% Since ArgPosns may not be empty, "ua" will be followed
% by the underscore before the first argument position number.
string.format("ua%s", [s(underscore_ints_to_string(ArgPosns))], Str)
;
ProcTransform = proc_transform_accumulator(_LineNum, ArgPosns),
% Since ArgPosns may not be empty, "acc" will be followed
% by the underscore before the first argument position number.
string.format("acc%s", [s(underscore_ints_to_string(ArgPosns))], Str)
;
ProcTransform = proc_transform_loop_inv(LineNum, SeqNum),
string.format("loopinv_%d_%d_%d",
[i(ProcIdInt), i(LineNum), i(SeqNum)], Str)
;
ProcTransform = proc_transform_tuple(LineNum, SeqNum),
string.format("tup_%d_%d_%d",
[i(ProcIdInt), i(LineNum), i(SeqNum)], Str)
;
ProcTransform = proc_transform_untuple(LineNum, SeqNum),
string.format("untup_%d_%d_%d",
[i(ProcIdInt), i(LineNum), i(SeqNum)], Str)
;
ProcTransform = proc_transform_dep_par_conj(ArgPosns),
string.format("depparconj%s",
[s(underscore_ints_to_string(ArgPosns))], Str)
;
ProcTransform = proc_transform_par_loop_ctrl,
Str = "parlc"
;
ProcTransform = proc_transform_lcmc(_SeqNum, ArgPosns),
string.format("lcmc %d%s",
[i(ProcIdInt), s(underscore_ints_to_string(ArgPosns))], Str)
;
ProcTransform = proc_transform_stm_expansion,
Str = "stm"
;
ProcTransform = proc_transform_io_tabling,
Str = "iotabling"
;
ProcTransform = proc_transform_direct_arg_in_out,
Str = "daio"
).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- func type_subst_to_string(tvarset, type_subst) = string.
type_subst_to_string(VarSet, TypeSubst) = Str :-
TVarStrs = list.map(type_var_subst_to_string(VarSet),
one_or_more_to_list(TypeSubst)),
% XXX The use of , and [] here *requires* mangling the names
% we construct.
TVarsStr = string.join_list(", ", TVarStrs),
string.format("[%s]", [s(TVarsStr)], Str).
:- func type_var_subst_to_string(tvarset, tvar_subst) = string.
type_var_subst_to_string(VarSet, tvar_subst(Var, Type)) = Str :-
varset.lookup_name(VarSet, Var, VarName),
TypeStr = mercury_type_to_string(VarSet, print_name_only, Type),
% XXX The use of = here *requires* mangling the names we construct.
string.format("%s = %s", [s(VarName), s(TypeStr)], Str).
:- func dump_subst(pair(int, mer_type)) = string.
dump_subst(TVar - Type) = Str :-
TypeStr = mercury_type_to_string(varset.init, print_name_only, Type),
Str = string.format("%d => %s", [i(TVar), s(TypeStr)]).
:- func subst_to_name(pair(int, mer_type)) = string.
subst_to_name(TVar - Type) = Str :-
TypeStr = mercury_type_to_string(varset.init, print_name_only, Type),
Str = string.format("%d/%s", [i(TVar), s(TypeStr)]).
:- func subst_to_mrtq_stuffed_string(pair(int, mer_type)) = string.
subst_to_mrtq_stuffed_string(TVar - Type) = Str :-
TypeStr = type_to_txq_mrtq_stuffed_string(Type),
string.format("_%d_%s_txq_sub", [i(TVar), s(TypeStr)], Str).
% txq_X:
%
% X = k: type is kinded variable (reserved; not yet used)
% X = v: type is type variable
% X = b: type is builtin type
% X = d: type is defined type
% X = t: type is tuple type
% X = a: type is apply_n type
% X = h: type is higher order type
%
% X = n: end of name of type constructor
% X = m: (at least) one more type in argument type list
% X = e: end of argument type list
%
:- func type_to_txq_mrtq_stuffed_string(mer_type) = string.
type_to_txq_mrtq_stuffed_string(Type) = Str :-
(
Type = kinded_type(SubType, _Kind),
Str = type_to_txq_mrtq_stuffed_string(SubType)
;
Type = type_variable(TVar, _),
string.format("txq_v_%d", [i(var_to_int(TVar))], Str)
;
Type = builtin_type(BuiltinType),
builtin_type_name(BuiltinType, BuiltinTypeStr),
string.format("txq_b_%s", [s(BuiltinTypeStr)], Str)
;
(
Type = defined_type(TypeCtorSymName, ArgTypes, _),
StuffedTypeCtorStr = txq_mrtq_stuff_sym_name(TypeCtorSymName),
string.format("txq_d_%s_txq_n", [s(StuffedTypeCtorStr)], StartStr)
;
Type = tuple_type(ArgTypes, _),
StartStr = "txq_t"
;
Type = apply_n_type(TVar, ArgTypes, _),
string.format("txq_a_%d", [i(var_to_int(TVar))], StartStr)
;
Type = higher_order_type(PorF, ArgTypes, _HOInst, Purity),
( PorF = pf_predicate, PorFStr = "p"
; PorF = pf_function, PorFStr = "f"
),
( Purity = purity_pure, PurityStr = "p"
; Purity = purity_semipure, PurityStr = "s"
; Purity = purity_impure, PurityStr = "i"
),
string.format("txq_h_%s%s", [s(PorFStr), s(PurityStr)], StartStr)
),
ArgTypeStrs = list.map(type_to_txq_mrtq_stuffed_string, ArgTypes),
MoreArgTypeStrs = list.map((func(S) = "_txq_m_" ++ S), ArgTypeStrs),
MoreArgTypesStr = string.append_list(MoreArgTypeStrs),
string.format("%s_%s_txq_e", [s(StartStr), s(MoreArgTypesStr)], Str)
).
%---------------------------------------------------------------------------%
:- func underscore_ints_to_string(list(int)) = string.
underscore_ints_to_string([]) = "".
underscore_ints_to_string([N | Ns]) =
"_" ++ int_to_string(N) ++ underscore_ints_to_string(Ns).
:- func bracketed_ints_to_string(list(int)) = string.
bracketed_ints_to_string(Ints) = Str :-
IntStrs = list.map(string.int_to_string, Ints),
% XXX The use of , and [] here *requires* mangling the names
% we construct.
IntsStr = string.join_list(", ", IntStrs),
string.format("[%s]", [s(IntsStr)], Str).
%---------------------------------------------------------------------------%
:- func mrtq_stuff_sym_name(sym_name) = string.
mrtq_stuff_sym_name(SymName) = StuffedStr :-
NameStr = sym_name_to_string(SymName),
StuffedStr = mrtq_stuff(NameStr).
:- func txq_mrtq_stuff_sym_name(sym_name) = string.
txq_mrtq_stuff_sym_name(SymName) = StuffedStr :-
NameStr = sym_name_to_string(SymName),
StuffedStr = txq_mrtq_stuff(NameStr).
:- func mrtq_stuff(string) = string.
mrtq_stuff(Str) = StuffedStr :-
( if sub_string_search(Str, "mrtq", _StartIndex) then
Pieces = split_at_string(Str, "mrtq"),
StuffedStr = string.join_list("mrtqq", Pieces)
else
StuffedStr = Str
).
:- func txq_mrtq_stuff(string) = string.
txq_mrtq_stuff(Str) = DoubleStuffedStr :-
( if sub_string_search(Str, "txq", _StartIndex) then
Pieces = split_at_string(Str, "txq"),
StuffedStr = string.join_list("txqq", Pieces)
else
StuffedStr = Str
),
DoubleStuffedStr = mrtq_stuff(StuffedStr).
%---------------------------------------------------------------------------%
:- end_module hlds.pred_name.
%---------------------------------------------------------------------------%