Files
mercury/compiler/hlds_rtti.m
Zoltan Somogyi 44d1f0db9c Give some predicates shorter names.
compiler/prog_type_subst.m:
compiler/type_util.m:
    Apply s/apply_variable_renaming_to_/apply_renaming_to_/ and
    s/_to_x_list/_to_xs/ to the names of predicate.

    Conform to the change in hlds_class.m below.

compiler/hlds_class.m:
    This module used to define types named (a) hlds_constraint, and
    (b) hlds_constraints, and the latter was NOT a list of items
    of type hlds_constraint. Rename the latter to hlds_constraint_db
    to free up the name apply_renaming_to_constraints to apply
    to list(hlds_constraint). However, the rename also makes code
    operating on hlds_constraint_dbs easier to understand. Before
    this diff, several modules used variables named Constraints
    to refer to a list(hlds_constraint) in some places and to
    what is now a hlds_constraint_db in other places, which is confusing;
    the latter are now named ConstraintDb.

compiler/type_assign.m:
    Conform to the changes above.

    Add an XXX about some existing variable names that *look* right
    but turn out to be subtly misleading.

compiler/add_pragma_type_spec.m:
compiler/add_type.m:
compiler/check_typeclass.m:
compiler/comp_unit_interface.m:
compiler/cse_detection.m:
compiler/ctgc.util.m:
compiler/decide_type_repn.m:
compiler/deforest.m:
compiler/equiv_type.m:
compiler/equiv_type_hlds.m:
compiler/higher_order.higher_order_global_info.m:
compiler/higher_order.make_specialized_preds.m:
compiler/higher_order.specialize_calls.m:
compiler/hlds_rtti.m:
compiler/inlining.m:
compiler/modecheck_coerce.m:
compiler/old_type_constraints.m:
compiler/polymorphism_clause.m:
compiler/polymorphism_goal.m:
compiler/polymorphism_type_class_info.m:
compiler/prog_type_unify.m:
compiler/qual_info.m:
compiler/recompilation.version.m:
compiler/resolve_unify_functor.m:
compiler/typecheck.m:
compiler/typecheck_clauses.m:
compiler/typecheck_cons_infos.m:
compiler/typecheck_debug.m:
compiler/typecheck_error_type_assign.m:
compiler/typecheck_errors.m:
compiler/typecheck_unify_var_functor.m:
compiler/typecheck_util.m:
compiler/typeclasses.m:
compiler/unify_proc.m:
compiler/var_table.m:
compiler/vartypes.m:
    Conform to the changes above.
2025-10-21 18:21:35 +11:00

907 lines
35 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1996-2007, 2009-2012 The University of Melbourne.
% Copyright (C) 2014-2016, 2018, 2021-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.
%---------------------------------------------------------------------------%
%
% File: hlds_rtti.m.
% Main authors: Mark Brown.
%
% This module defines the part of the HLDS that keeps track of information
% relating to RTTI.
%
%---------------------------------------------------------------------------%
:- module hlds.hlds_rtti.
:- interface.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.pred_name.
:- 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.set_of_var.
:- import_module parse_tree.var_table.
:- import_module array.
:- import_module assoc_list.
:- import_module bool.
:- import_module list.
%---------------------------------------------------------------------------%
:- type prog_var_name == string.
% The rtti_proc_label type holds all the information about a procedure
% that we need to compute the entry label for that procedure
% in the target language (the llds.code_addr or mlds.code_addr).
:- type rtti_proc_label
---> rtti_proc_label(
rpl_pred_or_func :: pred_or_func,
rpl_this_module :: module_name,
rpl_proc_module :: module_name,
rpl_proc_name :: string,
rpl_proc_arity :: pred_form_arity,
rpl_proc_arg_types :: list(mer_type),
rpl_pred_id :: pred_id,
rpl_proc_id :: proc_id,
rpl_proc_headvars :: assoc_list(prog_var,
prog_var_name),
rpl_proc_top_modes :: list(top_functor_mode),
rpl_proc_interface_detism :: determinism,
% The following booleans hold values computed from the
% pred_info, using procedures
% pred_info_is_imported/1,
% pred_info_is_pseudo_imported/1,
% pred_info_get_origin/1
% respectively.
% We store booleans here, rather than storing the
% pred_info, to avoid retaining a reference to the
% parts of the pred_info that we aren't interested in,
% so that those parts can be garbage collected.
% We use booleans rather than an import_status
% so that we can continue to use the above-mentioned
% abstract interfaces rather than hard-coding tests
% on the import_status.
rpl_pred_is_imported :: bool,
rpl_pred_is_pseudo_imported :: bool,
rpl_pred_info_origin :: pred_origin,
% The following boolean holds a value computed from the
% proc_info, using procedure_is_exported/2
rpl_proc_is_exported :: bool,
% The following bool is true if the procedure was
% imported, either because the containing predicate
% was imported, or because it was pseudoimported
% and the procedure is an in-in unify procedure.
rpl_proc_is_imported :: bool
).
% Construct an rtti_proc_label for a given procedure.
%
:- func make_rtti_proc_label(module_info, pred_id, proc_id) = rtti_proc_label.
% The inverse of make_rtti_proc_label.
%
:- pred proc_label_pred_proc_id(rtti_proc_label::in,
pred_id::out, proc_id::out) is det.
%---------------------------------------------------------------------------%
%
% Types and predicates to store information about RTTI.
%
% A type_info_locn specifies how to access a type_info.
%
:- type type_info_locn
---> type_info(prog_var)
% It is a normal type_info, i.e. the type is not constrained.
; typeclass_info(prog_var, int).
% The type_info is packed inside a typeclass_info. If the int is N,
% it is the Nth type_info inside the typeclass_info, but there
% may be several superclass pointers before the block of
% type_infos, so it won't be the Nth word of the typeclass_info.
%
% To find the type_info inside the typeclass_info, use the
% predicate type_info_from_typeclass_info from Mercury code;
% from C code use the macro MR_typeclass_info_superclass_info.
% type_info_locn_var(TypeInfoLocn, Var):
%
% Var is the variable corresponding to the TypeInfoLocn. Note that
% this does *not* mean that Var is a type_info; it may be a typeclass_info
% in which the type_info is nested.
%
:- pred type_info_locn_var(type_info_locn::in, prog_var::out) is det.
:- pred type_info_locn_set_var(prog_var::in,
type_info_locn::in, type_info_locn::out) is det.
% This type describes the contents of a prog_var.
%
:- type rtti_var_info
---> type_info_var(mer_type)
% The variable holds a type_info for the given type.
; typeclass_info_var(prog_constraint)
% The variable holds a typeclass_info for the given
% constraint.
; non_rtti_var.
% The variable does not directly hold any run time
% type information.
% This records information about how type_infos and typeclass_infos
% were introduced in the polymorphism transformation.
%
:- type rtti_varmaps.
% Returns an empty rtti_varmaps structure.
%
:- pred rtti_varmaps_init(rtti_varmaps::out) is det.
% Given an array in which the entry for a variable's integer form is true
% iff the variable is actually used in a procedure body, restrict the
% rtti_varmaps for that procedure to the variables needed.
%
:- pred restrict_rtti_varmaps(array(bool)::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% Succeeds iff the rtti_varmaps contain no information about any
% type variables.
%
:- pred rtti_varmaps_no_tvars(rtti_varmaps::in) is semidet.
% Find the location of a type_info.
%
:- pred rtti_lookup_type_info_locn(rtti_varmaps::in, tvar::in,
type_info_locn::out) is det.
% Find the location of a type_info, if it is known.
%
:- pred rtti_search_type_info_locn(rtti_varmaps::in, tvar::in,
type_info_locn::out) is semidet.
% Find the prog_var which contains the typeclass_info for a given
% constraint and which can be reused.
%
:- pred rtti_lookup_typeclass_info_var(rtti_varmaps::in, prog_constraint::in,
prog_var::out) is det.
% Find the prog_var which contains the typeclass_info for a given
% constraint and which can be reused, if it is known.
%
:- pred rtti_search_typeclass_info_var(rtti_varmaps::in, prog_constraint::in,
prog_var::out) is semidet.
% Find what RTTI, if any, is stored in a prog_var.
%
:- pred rtti_varmaps_var_info(rtti_varmaps::in, prog_var::in,
rtti_var_info::out) is det.
% Insert the location of a type_info. Abort if such information
% already exists.
%
:- pred rtti_det_insert_type_info_locn(tvar::in, type_info_locn::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% Set the location of a type_info, overwriting any previous information.
%
:- pred rtti_set_type_info_locn(tvar::in, type_info_locn::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% Insert the prog_var which contains the typeclass_info for a
% given constraint. Abort if such information already exists.
%
:- pred rtti_det_insert_typeclass_info_var(prog_constraint::in, prog_var::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% Set the prog_var which contains the typeclass_info for a given
% constraint, overwriting any previous information.
%
:- pred rtti_set_typeclass_info_var(prog_constraint::in, prog_var::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% Make the given typeclass_info var available for reuse in later goals.
% Abort if we know nothing about this variable.
%
:- pred rtti_reuse_typeclass_info_var(prog_var::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% For a prog_var which holds a type_info, set the type that the type_info
% is for. Abort if such information already exists.
%
:- pred rtti_det_insert_type_info_type(prog_var::in, mer_type::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% For a prog_var which holds a type_info, set the type that the type_info
% is for, overwriting any previous information.
%
:- pred rtti_set_type_info_type(prog_var::in, mer_type::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% rtti_var_info_duplicate(Var, NewVar, !RttiVarMaps)
%
% Duplicate the rtti_var_info we have about Var for NewVar.
%
:- pred rtti_var_info_duplicate(prog_var::in, prog_var::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% rtti_var_info_duplicate_replace(Var, NewVar, !RttiVarMaps)
%
% Duplicate the rtti_var_info we have about Var for NewVar.
% Replace old information about Var which already exists.
%
:- pred rtti_var_info_duplicate_replace(prog_var::in, prog_var::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% Returns all of the tvars that we have information about in the
% rtti_varmaps structure.
%
:- pred rtti_varmaps_tvars(rtti_varmaps::in, list(tvar)::out) is det.
% Returns all of the types that we have information about in the
% rtti_varmaps structure, including those types which appear in the
% arguments of constraints.
%
:- pred rtti_varmaps_types(rtti_varmaps::in, list(mer_type)::out) is det.
% Returns all of the prog_constraints which have typeclass_infos
% stored in a prog_var we can reuse.
%
:- pred rtti_varmaps_reusable_constraints(rtti_varmaps::in,
list(prog_constraint)::out) is det.
% Returns all of the prog_vars which are known to contain a type_info
% or typeclass_info.
%
:- pred rtti_varmaps_rtti_prog_vars(rtti_varmaps::in, list(prog_var)::out)
is det.
% apply_substitutions_to_rtti_varmaps(TRenaming, TSubst, Subst,
% !RttiVarMaps):
%
% Apply substitutions to the rtti_varmaps data. First apply TRenaming
% to all types, then apply TSubst to all types. Apply Subst to all
% prog_vars.
%
:- pred apply_substitutions_to_rtti_varmaps(tvar_renaming::in, tsubst::in,
prog_var_renaming::in, rtti_varmaps::in, rtti_varmaps::out) is det.
% rtti_varmaps_transform_types(Pred, !RttiVarMaps):
%
% Apply the transformation predicate to every type appearing in the
% rtti_varmaps structure, including those in the arguments of constraints.
%
:- pred rtti_varmaps_transform_types(
pred(mer_type, mer_type)::in(pred(in, out) is det),
rtti_varmaps::in, rtti_varmaps::out) is det.
% rtti_varmaps_overlay(A, B, C):
%
% Merge the information in rtti_varmaps A and B to produce C.
% Where information conflicts, use the information in B rather than A.
%
:- pred rtti_varmaps_overlay(rtti_varmaps::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
% For a set of variables V, find all the type variables in the types
% of the variables in V, and return set of typeinfo variables for
% those type variables. (find all typeinfos for variables in V).
%
% This set of typeinfos is often needed in liveness computation
% for accurate garbage collection - live variables need to have
% their typeinfos stay live too.
%
:- pred get_typeinfo_vars(var_table::in, rtti_varmaps::in,
set_of_progvar::in, set_of_progvar::out) is det.
:- pred maybe_complete_with_typeinfo_vars(var_table::in, rtti_varmaps::in,
bool::in, set_of_progvar::in, set_of_progvar::out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.hlds_proc_util.
:- import_module hlds.mode_top_functor.
:- import_module parse_tree.prog_type_scan.
:- import_module parse_tree.prog_type_subst.
:- import_module map.
:- import_module pair.
:- import_module require.
:- import_module set_tree234.
:- import_module string.
:- import_module term.
%---------------------------------------------------------------------------%
make_rtti_proc_label(ModuleInfo, PredId, ProcId) = ProcLabel :-
module_info_get_name(ModuleInfo, ThisModule),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, PredInfo, ProcInfo),
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
PredModule = pred_info_module(PredInfo),
PredName = pred_info_name(PredInfo),
PredFormArity = pred_info_pred_form_arity(PredInfo),
pred_info_get_arg_types(PredInfo, ArgTypes),
proc_info_get_var_table(ProcInfo, ProcVarTable),
proc_info_get_headvars(ProcInfo, ProcHeadVars),
proc_info_get_argmodes(ProcInfo, ProcModes),
proc_info_interface_determinism(ProcInfo, ProcDetism),
modes_to_top_functor_modes(ModuleInfo, ProcModes, ArgTypes, ProcTopModes),
PredIsImported =
(if pred_info_is_imported(PredInfo) then yes else no),
PredIsPseudoImp =
(if pred_info_is_pseudo_imported(PredInfo) then yes else no),
ProcIsExported =
(if procedure_is_exported(ModuleInfo, PredInfo, ProcId)
then yes else no),
pred_info_get_origin(PredInfo, Origin),
ProcHeadVarsWithNames = list.map(
( func(Var) = Var - Name :-
Name = var_table_entry_name(ProcVarTable, Var)
), ProcHeadVars),
( if
(
PredIsImported = yes
;
PredIsPseudoImp = yes,
hlds_pred.in_in_unification_proc_id(ProcId)
)
then
ProcIsImported = yes
else
ProcIsImported = no
),
ProcLabel = rtti_proc_label(PredOrFunc, ThisModule, PredModule,
PredName, PredFormArity, ArgTypes, PredId, ProcId,
ProcHeadVarsWithNames, ProcTopModes, ProcDetism,
PredIsImported, PredIsPseudoImp, Origin,
ProcIsExported, ProcIsImported).
proc_label_pred_proc_id(RttiProcLabel, PredId, ProcId) :-
PredId = RttiProcLabel ^ rpl_pred_id,
ProcId = RttiProcLabel ^ rpl_proc_id.
%---------------------------------------------------------------------------%
type_info_locn_var(type_info(Var), Var).
type_info_locn_var(typeclass_info(Var, _), Var).
type_info_locn_set_var(Var, type_info(_), type_info(Var)).
type_info_locn_set_var(Var, typeclass_info(_, Num), typeclass_info(Var, Num)).
:- type rtti_varmaps
---> rtti_varmaps(
rv_tci_varmap :: typeclass_info_varmap,
rv_ti_varmap :: type_info_varmap,
rv_ti_type_map :: type_info_type_map,
rv_tci_constraint_map :: typeclass_info_constraint_map
).
% A typeclass_info_varmap is a map which for each type class constraint
% records which variable contains the typeclass_info for that constraint.
% The constraints covered by this map are those which are passed in
% as head arguments and those which are produced as existential constraints
% from calls or deconstructions. These are constraints for which it is safe
% to reuse the variable associated with the constraint.
%
:- type typeclass_info_varmap == map(prog_constraint, prog_var).
% A type_info_varmap is a map which for each type variable records
% where the type_info for that type variable is stored.
%
% XXX This doesn't record the information that we want. For a constraint
% such as foo(list(T)) we can't properly record the location of the
% type_info for T, since it does not occupy a slot in the typeclass_info
% directly, but is inside the type_info for list(T).
%
% XXX Even the information that is recorded has the wrong key. Consider
% a conjunction between:
%
% - a call that returns an existentially typed result, and
% - a goal that uses that existentially typed variable.
%
% Let us say that the conjunction looks like
%
% gen_result(X_1, TypeInfo_for_T_2), use_result(TypeInfo_for_T_2, X_1).
%
% This conjunction can be duplicated, e.g. by switch detection (it could be
% in a switch arm that is guarded by a disjunction that handles different
% values of the switched-on variable differently) or by tabling.
% (This is what happens in Mantis bug #154.)
%
% In such cases, the renamed-apart duplicated goal would be something like
%
% gen_result(X_3, TypeInfo_for_T_4), use_result(TypeInfo_for_T_4, X_3).
%
% Yet the rtti_var_map for the procedure would say that X_3 is of the same
% type as X_1, which means that the compiler would think that X_1 and X_3
% use the same type_info variable to represent their types. This would be
% TypeInfo_for_T_2, even though it won't exist on the execution branch
% containing the copied version of the goal.
%
% I (zs) can see two possible fixes.
%
% - First, we could have type_info_varmap map each tvar to a nonempty set
% of type_info_locns, exactly one of which would be available on every
% execution path. It would be the responsibility of other parts of the
% compiler to pick the right one.
%
% - Second, instead of mapping prog_vars to types, and the tvars in those
% types to the prog_vars holding their type_infos, we could map each
% prog_var directly to a {tvar -> typeinfo progvar} map.
%
:- type type_info_varmap == map(tvar, type_info_locn).
% Every program variable which holds a type_info is a key in this map.
% The value associated with a given key is the type that the type_info
% is for.
%
:- type type_info_type_map == map(prog_var, mer_type).
% Every program variable which holds a typeclass_info is a key in this map.
% The value associated with a given key is the prog_constraint that
% the typeclass_info is for.
%
:- type typeclass_info_constraint_map == map(prog_var, prog_constraint).
rtti_varmaps_init(rtti_varmaps(TCIMap, TIMap, TypeMap, ConstraintMap)) :-
map.init(TCIMap),
map.init(TIMap),
map.init(TypeMap),
map.init(ConstraintMap).
restrict_rtti_varmaps(VarUses, !RttiVarMaps) :-
% This code makes the assumption that if a type_ctor_info, type_info,
% base_typeclass_info or typeclass_info variable is not needed, then
% any code that refers to the constraints reachable from those variables
% has also been removed from the procedure. (This would happen by being
% moved to a procedure of its own by lambda.m.)
!.RttiVarMaps = rtti_varmaps(TCIMap0, TIMap0, TypeMap0, ConstraintMap0),
map.to_assoc_list(TIMap0, TIList0),
filter_type_info_varmap(TIList0, VarUses, [], RevTIList),
map.from_rev_sorted_assoc_list(RevTIList, TIMap),
map.to_assoc_list(TypeMap0, TypeList0),
filter_type_info_map(TypeList0, VarUses, [], RevTypeList),
map.from_rev_sorted_assoc_list(RevTypeList, TypeMap),
map.to_assoc_list(ConstraintMap0, ConstraintList0),
filter_constraint_map(ConstraintList0, VarUses, [], RevConstraintList,
TCIMap0, TCIMap),
map.from_rev_sorted_assoc_list(RevConstraintList, ConstraintMap),
!:RttiVarMaps = rtti_varmaps(TCIMap, TIMap, TypeMap, ConstraintMap).
:- pred filter_type_info_varmap(assoc_list(tvar, type_info_locn)::in,
array(bool)::in,
assoc_list(tvar, type_info_locn)::in,
assoc_list(tvar, type_info_locn)::out) is det.
filter_type_info_varmap([], _VarUses, !RevTVarLocns).
filter_type_info_varmap([TVarLocn | TVarLocns], VarUses, !RevTVarLocns) :-
TVarLocn = _TVar - Locn,
( Locn = type_info(Var)
; Locn = typeclass_info(Var, _)
),
VarNum = var_to_int(Var),
array.unsafe_lookup(VarUses, VarNum, Used),
(
Used = yes,
!:RevTVarLocns = [TVarLocn | !.RevTVarLocns]
;
Used = no
),
filter_type_info_varmap(TVarLocns, VarUses, !RevTVarLocns).
:- pred filter_type_info_map(assoc_list(prog_var, mer_type)::in,
array(bool)::in,
assoc_list(prog_var, mer_type)::in, assoc_list(prog_var, mer_type)::out)
is det.
filter_type_info_map([], _VarUses, !RevVarTypes).
filter_type_info_map([VarType | VarTypes], VarUses, !RevVarTypes) :-
VarType = Var - _Type,
VarNum = var_to_int(Var),
array.unsafe_lookup(VarUses, VarNum, Used),
(
Used = yes,
!:RevVarTypes = [VarType | !.RevVarTypes]
;
Used = no
),
filter_type_info_map(VarTypes, VarUses, !RevVarTypes).
:- pred filter_constraint_map(assoc_list(prog_var, prog_constraint)::in,
array(bool)::in,
assoc_list(prog_var, prog_constraint)::in,
assoc_list(prog_var, prog_constraint)::out,
typeclass_info_varmap::in, typeclass_info_varmap::out) is det.
filter_constraint_map([], _VarUses, !RevVarConstraints, !TCIMap).
filter_constraint_map([VarConstraint | VarConstraints], VarUses,
!RevVarConstraints, !TCIMap) :-
VarConstraint = Var - Constraint,
VarNum = var_to_int(Var),
array.unsafe_lookup(VarUses, VarNum, Used),
(
Used = yes,
!:RevVarConstraints = [VarConstraint | !.RevVarConstraints]
;
Used = no,
map.delete(Constraint, !TCIMap)
),
filter_constraint_map(VarConstraints, VarUses,
!RevVarConstraints, !TCIMap).
rtti_varmaps_no_tvars(RttiVarMaps) :-
map.is_empty(RttiVarMaps ^ rv_ti_varmap).
rtti_lookup_type_info_locn(RttiVarMaps, TVar, Locn) :-
map.lookup(RttiVarMaps ^ rv_ti_varmap, TVar, Locn).
rtti_search_type_info_locn(RttiVarMaps, TVar, Locn) :-
map.search(RttiVarMaps ^ rv_ti_varmap, TVar, Locn).
rtti_lookup_typeclass_info_var(RttiVarMaps, Constraint, ProgVar) :-
map.lookup(RttiVarMaps ^ rv_tci_varmap, Constraint, ProgVar).
rtti_search_typeclass_info_var(RttiVarMaps, Constraint, ProgVar) :-
map.search(RttiVarMaps ^ rv_tci_varmap, Constraint, ProgVar).
rtti_varmaps_var_info(RttiVarMaps, Var, VarInfo) :-
( if
map.search(RttiVarMaps ^ rv_ti_type_map, Var, Type)
then
VarInfo = type_info_var(Type)
else if
map.search(RttiVarMaps ^ rv_tci_constraint_map, Var, Constraint)
then
VarInfo = typeclass_info_var(Constraint)
else
VarInfo = non_rtti_var
).
rtti_det_insert_type_info_locn(TVar, Locn, !RttiVarMaps) :-
Map0 = !.RttiVarMaps ^ rv_ti_varmap,
map.det_insert(TVar, Locn, Map0, Map),
!RttiVarMaps ^ rv_ti_varmap := Map,
maybe_check_type_info_var(Locn, TVar, !RttiVarMaps).
rtti_set_type_info_locn(TVar, Locn, !RttiVarMaps) :-
Map0 = !.RttiVarMaps ^ rv_ti_varmap,
map.set(TVar, Locn, Map0, Map),
!RttiVarMaps ^ rv_ti_varmap := Map,
maybe_check_type_info_var(Locn, TVar, !RttiVarMaps).
:- pred maybe_check_type_info_var(type_info_locn::in, tvar::in,
rtti_varmaps::in, rtti_varmaps::out) is det.
maybe_check_type_info_var(type_info(Var), TVar, RttiVarMaps, RttiVarMaps) :-
% We do an unneeded return of RttiVarMaps to ensure that
% calls to this predicate, and therefore this sanity check,
% do not get optimized away.
map.lookup(RttiVarMaps ^ rv_ti_type_map, Var, Type),
( if Type = type_variable(TVar, _) then
true
else
unexpected($pred, "inconsistent info in rtti_varmaps")
).
maybe_check_type_info_var(typeclass_info(_, _), _, RttiVarMaps, RttiVarMaps).
rtti_det_insert_typeclass_info_var(Constraint, ProgVar, !RttiVarMaps) :-
Map0 = !.RttiVarMaps ^ rv_tci_constraint_map,
map.det_insert(ProgVar, Constraint, Map0, Map),
!RttiVarMaps ^ rv_tci_constraint_map := Map.
rtti_set_typeclass_info_var(Constraint, ProgVar, !RttiVarMaps) :-
Map0 = !.RttiVarMaps ^ rv_tci_constraint_map,
map.set(ProgVar, Constraint, Map0, Map),
!RttiVarMaps ^ rv_tci_constraint_map := Map.
rtti_reuse_typeclass_info_var(ProgVar, !RttiVarMaps) :-
map.lookup(!.RttiVarMaps ^ rv_tci_constraint_map, ProgVar, Constraint),
Map0 = !.RttiVarMaps ^ rv_tci_varmap,
map.set(Constraint, ProgVar, Map0, Map),
!RttiVarMaps ^ rv_tci_varmap := Map.
rtti_det_insert_type_info_type(ProgVar, Type, !RttiVarMaps) :-
Map0 = !.RttiVarMaps ^ rv_ti_type_map,
map.det_insert(ProgVar, Type, Map0, Map),
!RttiVarMaps ^ rv_ti_type_map := Map.
rtti_set_type_info_type(ProgVar, Type, !RttiVarMaps) :-
Map0 = !.RttiVarMaps ^ rv_ti_type_map,
map.set(ProgVar, Type, Map0, Map),
!RttiVarMaps ^ rv_ti_type_map := Map.
rtti_var_info_duplicate(Var, NewVar, !RttiVarMaps) :-
rtti_varmaps_var_info(!.RttiVarMaps, Var, VarInfo),
(
VarInfo = type_info_var(Type),
rtti_det_insert_type_info_type(NewVar, Type, !RttiVarMaps)
;
VarInfo = typeclass_info_var(Constraint),
rtti_det_insert_typeclass_info_var(Constraint, NewVar, !RttiVarMaps)
;
VarInfo = non_rtti_var
).
rtti_var_info_duplicate_replace(Var, NewVar, !RttiVarMaps) :-
rtti_varmaps_var_info(!.RttiVarMaps, Var, VarInfo),
(
VarInfo = type_info_var(Type),
rtti_set_type_info_type(NewVar, Type, !RttiVarMaps)
;
VarInfo = typeclass_info_var(Constraint),
rtti_set_typeclass_info_var(Constraint, NewVar, !RttiVarMaps)
;
VarInfo = non_rtti_var
).
rtti_varmaps_tvars(RttiVarMaps, TVars) :-
map.keys(RttiVarMaps ^ rv_ti_varmap, TVars).
rtti_varmaps_types(RttiVarMaps, Types) :-
TypeMap = RttiVarMaps ^ rv_ti_type_map,
ConstraintMap = RttiVarMaps ^ rv_tci_constraint_map,
TypeSet0 = set_tree234.init,
map.foldl_values(set_tree234.insert, TypeMap, TypeSet0, TypeSet1),
map.foldl_values(accumulate_types_in_prog_constraint, ConstraintMap,
TypeSet1, TypeSet),
Types = set_tree234.to_sorted_list(TypeSet).
:- pred accumulate_types_in_prog_constraint(prog_constraint::in,
set_tree234(mer_type)::in, set_tree234(mer_type)::out) is det.
accumulate_types_in_prog_constraint(Constraint, !TypeSet) :-
Constraint = constraint(_, ArgTypes),
set_tree234.insert_list(ArgTypes, !TypeSet).
rtti_varmaps_reusable_constraints(RttiVarMaps, Constraints) :-
map.keys(RttiVarMaps ^ rv_tci_varmap, Constraints).
rtti_varmaps_rtti_prog_vars(RttiVarMaps, Vars) :-
map.keys(RttiVarMaps ^ rv_ti_type_map, TIVars),
map.keys(RttiVarMaps ^ rv_tci_constraint_map, TCIVars),
list.append(TIVars, TCIVars, Vars).
apply_substitutions_to_rtti_varmaps(TRenaming, TSubst, Subst, !RttiVarMaps) :-
( if
% Optimize the simple case.
map.is_empty(Subst),
map.is_empty(TSubst),
map.is_empty(TRenaming)
then
true
else
!.RttiVarMaps = rtti_varmaps(TCIMap0, TIMap0, TypeMap0,
ConstraintMap0),
map.foldl(apply_substs_to_tci_map(TRenaming, TSubst, Subst),
TCIMap0, map.init, TCIMap),
map.foldl(apply_substs_to_ti_map(TRenaming, TSubst, Subst),
TIMap0, map.init, TIMap),
map.foldl(apply_substs_to_type_map(TRenaming, TSubst, Subst),
TypeMap0, map.init, TypeMap),
map.foldl(apply_substs_to_constraint_map(TRenaming, TSubst, Subst),
ConstraintMap0, map.init, ConstraintMap),
!:RttiVarMaps = rtti_varmaps(TCIMap, TIMap, TypeMap, ConstraintMap)
).
:- pred apply_subst_to_prog_var(prog_var_renaming::in,
prog_var::in, prog_var::out) is det.
apply_subst_to_prog_var(Subst, Var0, Var) :-
( if map.search(Subst, Var0, Var1) then
Var = Var1
else
Var = Var0
).
:- pred apply_substs_to_tci_map(tvar_renaming::in, tsubst::in,
prog_var_renaming::in, prog_constraint::in, prog_var::in,
typeclass_info_varmap::in, typeclass_info_varmap::out) is det.
apply_substs_to_tci_map(TRenaming, TSubst, Subst, Constraint0, Var0, !Map) :-
apply_renaming_to_prog_constraint(TRenaming, Constraint0,
Constraint1),
apply_rec_subst_to_prog_constraint(TSubst, Constraint1, Constraint),
apply_subst_to_prog_var(Subst, Var0, Var),
map.set(Constraint, Var, !Map).
% Update a map entry from tvar to type_info_locn, using the type renaming
% and substitution to rename tvars and a variable substitution to rename
% vars. The type renaming is applied before the type substitution.
%
% If tvar maps to a another type variable, we keep the new variable, if
% it maps to a type, we remove it from the map.
%
:- pred apply_substs_to_ti_map(tvar_renaming::in, tsubst::in,
prog_var_renaming::in, tvar::in, type_info_locn::in,
type_info_varmap::in, type_info_varmap::out) is det.
apply_substs_to_ti_map(TRenaming, TSubst, Subst, TVar, Locn, !Map) :-
type_info_locn_var(Locn, Var),
apply_subst_to_prog_var(Subst, Var, NewVar),
type_info_locn_set_var(NewVar, Locn, NewLocn),
apply_renaming_to_tvar(TRenaming, TVar, NewTVar1),
% We don't use the correct kinds here, but that doesn't matter because
% the resulting kind will be thrown away anyway.
apply_rec_subst_to_tvar(map.init, TSubst, NewTVar1, NewType),
(
% If the tvar is still a variable, insert it into the map with the
% new var.
NewType = type_variable(NewTVar, _),
% Don't abort if two old type variables map to the same new type
% variable.
map.set(NewTVar, NewLocn, !Map)
;
( NewType = builtin_type(_)
; NewType = defined_type(_, _, _)
; NewType = tuple_type(_, _)
; NewType = higher_order_type(_, _, _, _)
; NewType = apply_n_type(_, _, _)
; NewType = kinded_type(_, _)
)
).
:- pred apply_substs_to_type_map(tvar_renaming::in, tsubst::in,
prog_var_renaming::in, prog_var::in, mer_type::in,
type_info_type_map::in, type_info_type_map::out) is det.
apply_substs_to_type_map(TRenaming, TSubst, Subst, Var0, Type0, !Map) :-
apply_renaming_to_type(TRenaming, Type0, Type1),
apply_rec_subst_to_type(TSubst, Type1, Type),
apply_subst_to_prog_var(Subst, Var0, Var),
( if map.search(!.Map, Var, ExistingType) then
( if Type = ExistingType then
true
else
unexpected($pred,
string.format("inconsistent type_infos: "
++ " Type: %s ExistingType: %s",
[s(string(Type)), s(string(ExistingType))]))
)
else
map.det_insert(Var, Type, !Map)
).
:- pred apply_substs_to_constraint_map(tvar_renaming::in, tsubst::in,
prog_var_renaming::in, prog_var::in, prog_constraint::in,
typeclass_info_constraint_map::in, typeclass_info_constraint_map::out)
is det.
apply_substs_to_constraint_map(TRenaming, TSubst, Subst, Var0, Constraint0,
!Map) :-
apply_renaming_to_prog_constraint(TRenaming, Constraint0, Constraint1),
apply_rec_subst_to_prog_constraint(TSubst, Constraint1, Constraint),
apply_subst_to_prog_var(Subst, Var0, Var),
( if map.search(!.Map, Var, ExistingConstraint) then
( if Constraint = ExistingConstraint then
true
else
unexpected($pred, "inconsistent typeclass_infos")
)
else
map.det_insert(Var, Constraint, !Map)
).
rtti_varmaps_transform_types(Pred, !RttiVarMaps) :-
TciMap0 = !.RttiVarMaps ^ rv_tci_varmap,
TypeMap0 = !.RttiVarMaps ^ rv_ti_type_map,
ConstraintMap0 = !.RttiVarMaps ^ rv_tci_constraint_map,
map.foldl(apply_constraint_key_transformation(Pred), TciMap0,
map.init, TciMap),
map.map_values_only(Pred, TypeMap0, TypeMap),
map.map_values(apply_constraint_value_transformation(Pred),
ConstraintMap0, ConstraintMap),
!RttiVarMaps ^ rv_tci_varmap := TciMap,
!RttiVarMaps ^ rv_ti_type_map := TypeMap,
!RttiVarMaps ^ rv_tci_constraint_map := ConstraintMap.
:- pred apply_constraint_key_transformation(
pred(mer_type, mer_type)::in(pred(in, out) is det),
prog_constraint::in, prog_var::in,
typeclass_info_varmap::in, typeclass_info_varmap::out) is det.
apply_constraint_key_transformation(Pred, Constraint0, Var, !Map) :-
Constraint0 = constraint(Name, Args0),
list.map(Pred, Args0, Args),
Constraint = constraint(Name, Args),
map.set(Constraint, Var, !Map).
:- pred apply_constraint_value_transformation(
pred(mer_type, mer_type)::in(pred(in, out) is det),
prog_var::in, prog_constraint::in, prog_constraint::out) is det.
apply_constraint_value_transformation(Pred, _, Constraint0, Constraint) :-
Constraint0 = constraint(Name, Args0),
list.map(Pred, Args0, Args),
Constraint = constraint(Name, Args).
rtti_varmaps_overlay(VarMapsA, VarMapsB, VarMaps) :-
VarMapsA = rtti_varmaps(TCImapA, TImapA, TypeMapA, ConstraintMapA),
VarMapsB = rtti_varmaps(TCImapB, TImapB, TypeMapB, ConstraintMapB),
% Prefer VarMapsB for this information.
map.overlay(TCImapA, TCImapB, TCImap),
map.overlay(TImapA, TImapB, TImap),
% On the other hand, we insist that this information is consistent.
map.old_merge(TypeMapA, TypeMapB, TypeMap),
map.old_merge(ConstraintMapA, ConstraintMapB, ConstraintMap),
VarMaps = rtti_varmaps(TCImap, TImap, TypeMap, ConstraintMap).
%---------------------------------------------------------------------------%
get_typeinfo_vars(VarTable, RttiVarMaps, Vars, TypeInfoVars) :-
TVarMap = RttiVarMaps ^ rv_ti_varmap,
VarList = set_of_var.to_sorted_list(Vars),
get_typeinfo_vars_acc(VarTable, TVarMap, VarList,
set_of_var.init, TypeInfoVars).
% Auxiliary predicate - traverses variables and builds a list of
% variables that store typeinfos for these variables.
%
:- pred get_typeinfo_vars_acc(var_table::in, type_info_varmap::in,
list(prog_var)::in, set_of_progvar::in, set_of_progvar::out) is det.
get_typeinfo_vars_acc(_, _, [], !TypeInfoVars).
get_typeinfo_vars_acc(VarTable, TVarMap, [Var | Vars], !TypeInfoVars) :-
lookup_var_type(VarTable, Var, Type),
type_vars_in_type(Type, TypeVars),
(
TypeVars = []
% Optimize common case,
;
TypeVars = [_ | _],
% XXX It is possible there are some complications with higher order
% pred types here -- if so, maybe treat them specially.
% The type_info is either stored in a variable, or in a
% typeclass_info. Either get the type_info variable or
% the typeclass_info variable.
LookupVar =
( pred(TVar::in, TVarVar::out) is det :-
map.lookup(TVarMap, TVar, Locn),
type_info_locn_var(Locn, TVarVar)
),
list.map(LookupVar, TypeVars, TypeInfoVarsHead),
set_of_var.insert_list(TypeInfoVarsHead, !TypeInfoVars)
),
get_typeinfo_vars_acc(VarTable, TVarMap, Vars, !TypeInfoVars).
%---------------------%
maybe_complete_with_typeinfo_vars(VarTable, RttiVarMaps, TypeInfoLiveness,
Vars0, Vars) :-
(
TypeInfoLiveness = yes,
get_typeinfo_vars(VarTable, RttiVarMaps, Vars0, TypeInfoVars),
set_of_var.union(Vars0, TypeInfoVars, Vars)
;
TypeInfoLiveness = no,
Vars = Vars0
).
%---------------------------------------------------------------------------%
:- end_module hlds.hlds_rtti.
%---------------------------------------------------------------------------%