Files
mercury/compiler/polymorphism.m
Zoltan Somogyi 6d1bc24d0b Make vartypes an abstract data type, in preparation for exploring
Estimated hours taken: 4
Branches: main

compiler/prog_data.m:
	Make vartypes an abstract data type, in preparation for exploring
	better representations for it.

compiler/mode_util.m:
	Provide two different versions of a predicate. The generic version
	continues to use map lookups. The other version knows it works on
	prog_vars, so it can use the abstract operations on them provided
	by prog_data.m.

compiler/accumulator.m:
compiler/add_class.m:
compiler/add_heap_ops.m:
compiler/add_pragma.m:
compiler/add_pred.m:
compiler/add_trail_ops.m:
compiler/arg_info.m:
compiler/builtin_lib_types.m:
compiler/bytecode_gen.m:
compiler/call_gen.m:
compiler/clause_to_proc.m:
compiler/closure_analysis.m:
compiler/code_info.m:
compiler/common.m:
compiler/complexity.m:
compiler/const_prop.m:
compiler/constraint.m:
compiler/continuation_info.m:
compiler/cse_detection.m:
compiler/ctgc.datastruct.m:
compiler/ctgc.util.m:
compiler/deep_profiling.m:
compiler/deforest.m:
compiler/dep_par_conj.m:
compiler/det_analysis.m:
compiler/det_report.m:
compiler/det_util.m:
compiler/disj_gen.m:
compiler/equiv_type_hlds.m:
compiler/erl_call_gen.m:
compiler/erl_code_gen.m:
compiler/erl_code_util.m:
compiler/exception_analysis.m:
compiler/float_regs.m:
compiler/follow_vars.m:
compiler/format_call.m:
compiler/goal_path.m:
compiler/goal_util.m:
compiler/hhf.m:
compiler/higher_order.m:
compiler/hlds_clauses.m:
compiler/hlds_goal.m:
compiler/hlds_out_goal.m:
compiler/hlds_out_pred.m:
compiler/hlds_pred.m:
compiler/hlds_rtti.m:
compiler/inlining.m:
compiler/instmap.m:
compiler/intermod.m:
compiler/interval.m:
compiler/lambda.m:
compiler/lco.m:
compiler/live_vars.m:
compiler/liveness.m:
compiler/lookup_switch.m:
compiler/mercury_to_mercury.m:
compiler/ml_accurate_gc.m:
compiler/ml_closure_gen.m:
compiler/ml_code_gen.m:
compiler/ml_code_util.m:
compiler/ml_disj_gen.m:
compiler/ml_lookup_switch.m:
compiler/ml_proc_gen.m:
compiler/ml_unify_gen.m:
compiler/mode_info.m:
compiler/modecheck_call.m:
compiler/modecheck_conj.m:
compiler/modecheck_goal.m:
compiler/modecheck_unify.m:
compiler/modecheck_util.m:
compiler/modes.m:
compiler/par_loop_control.m:
compiler/pd_info.m:
compiler/pd_util.m:
compiler/polymorphism.m:
compiler/post_typecheck.m:
compiler/prog_type_subst.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/qual_info.m:
compiler/rbmm.points_to_info.m:
compiler/rbmm.region_liveness_info.m:
compiler/rbmm.region_transformation.m:
compiler/saved_vars.m:
compiler/simplify.m:
compiler/size_prof.m:
compiler/ssdebug.m:
compiler/stack_alloc.m:
compiler/stack_opt.m:
compiler/store_alloc.m:
compiler/structure_reuse.analysis.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/structure_reuse.direct.detect_garbage.m:
compiler/structure_reuse.indirect.m:
compiler/structure_sharing.analysis.m:
compiler/structure_sharing.domain.m:
compiler/switch_detection.m:
compiler/table_gen.m:
compiler/term_constr_build.m:
compiler/term_constr_util.m:
compiler/term_traversal.m:
compiler/term_util.m:
compiler/trace_gen.m:
compiler/trailing_analysis.m:
compiler/try_expand.m:
compiler/tupling.m:
compiler/type_constraints.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/typecheck_errors.m:
compiler/typecheck_info.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/unique_modes.m:
compiler/untupling.m:
compiler/unused_args.m:
compiler/var_locn.m:
	Conform to the above.

compiler/prog_type.m:
compiler/rbmm.points_to_graph.m:
	Conform to the above.

	Move some comments where they belong.

compiler/stm_expand.m:
	Conform to the above.

	Do not export a predicate that is not used outside this module.

	Disable some debugging output unless it is asked for.

	Remove unnecessary prefixes on variable names.

library/version_array.m:
	Instead writing code for field access lookalike functions and defining
	lookup, set etc in terms of them, write code for lookup, set etc,
	and define the field access lookalike functions in terms of them.

	Change argument orders of some internal predicates to be
	more state variable friendly.

	Fix typos in comments.

tests/hard_coded/version_array_test.exp:
	Conform to the change to version_array.m.
2012-07-02 01:16:39 +00:00

4638 lines
200 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1995-2012 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: polymorphism.m.
% Main authors: fjh and zs.
%
% This module is a pass over the HLDS.
% It does a syntactic transformation to implement polymorphism, including
% typeclasses, by passing extra `type_info' and `typeclass_info' arguments.
% These arguments are structures that contain, amongst other things,
% higher order predicate terms for the polymorphic procedures or methods.
%
% See notes/type_class_transformation.html for a description of the
% transformation and data structures used to implement type classes.
%
% XXX The way the code in this module handles existential type classes
% and type class constraints is a bit ad hoc, in general; there are
% definitely parts of this code (marked with XXXs below) that could
% do with a rewrite to make it more consistent and hence more maintainable.
%
%-----------------------------------------------------------------------------%
%
% Transformation of polymorphic code:
%
% Every polymorphic predicate is transformed so that it takes one additional
% argument for every type variable in the predicate's type declaration.
% The argument gives information about the type, including higher order
% predicate variables for each of the builtin polymorphic operations
% (currently unify/2, compare/3).
%
%-----------------------------------------------------------------------------%
%
% Representation of type information:
%
% IMPORTANT: ANY CHANGES TO THE DOCUMENTATION HERE MUST BE REFLECTED BY
% SIMILAR CHANGES TO THE #defines IN "runtime/mercury_type_info.h" AND
% TO THE TYPE SPECIALIZATION CODE IN "compiler/higher_order.m".
%
% Type information is represented using one or two cells. The cell which
% is always present is the type_ctor_info structure, whose structure is
% defined in runtime/mercury_type_info.h. The other cell is the type_info
% structure, laid out like this:
%
% word 0 <pointer to the type_ctor_info structure>
% word 1+ <the type_infos for the type params, at least one>
%
% (but see note below for how variable arity types differ)
%
%-----------------------------------------------------------------------------%
%
% Optimization of common case (zero arity types):
%
% The type_info structure itself is redundant if the type has no type
% parameters (i.e. its arity is zero). Therefore if the arity is zero,
% we pass the address of the type_ctor_info structure directly, instead of
% wrapping it up in another cell. The runtime system will look at the first
% field of the cell it is passed. If this field is zero, the cell is a
% type_ctor_info structure for an arity zero type. If this field is not zero,
% the cell is a new type_info structure, with the first field being the
% pointer to the type_ctor_info structure.
%
%-----------------------------------------------------------------------------%
%
% Variable arity types:
%
% There is a slight variation on this for variable-arity type constructors, of
% there are exactly three: pred, func and tuple. Typeinfos of these types
% always have a pointer to the pred/0, func/0 or tuple/0 type_ctor_info,
% regardless of their true arity, so we store the real arity in the type_info
% as well.
%
% word 0 <pointer to the arity 0 type_ctor_info structure>
% word 1 <arity of predicate>
% word 2+ <the type_infos for the type params, if any>
%
%-----------------------------------------------------------------------------%
%
% Sharing type_ctor_info structures:
%
% For compilation models that can put code addresses in static ground terms,
% we can arrange to create one copy of the type_ctor_info structure statically,
% avoiding the need to create other copies at runtime. For compilation models
% that cannot put code addresses in static ground terms, there are a couple
% of things we could do:
%
% 1. allocate all cells at runtime.
% 2. use a shared static type_ctor_info, but initialize its code
% addresses during startup (that is, during the module
% initialization code).
%
% We use option 2.
%
%-----------------------------------------------------------------------------%
%
% Example of transformation:
%
% Take the following code as an example, ignoring the requirement for
% superhomogeneous form for clarity:
%
% :- pred p(T1).
% :- pred q(T2).
% :- pred r(T3).
%
% p(X) :- q([X]), r(0).
%
% We add an extra argument for each type variable:
%
% :- pred p(type_info(T1), T1).
% :- pred q(type_info(T2), T2).
% :- pred r(type_info(T3), T3).
%
% We transform the body of p to this:
%
% p(TypeInfoT1, X) :-
% TypeCtorInfoT2 = type_ctor_info(list/1),
% TypeInfoT2 = type_info(TypeCtorInfoT2, TypeInfoT1),
% q(TypeInfoT2, [X]),
% TypeInfoT3 = type_ctor_info(int/0),
% r(TypeInfoT3, 0).
%
% Note that type_ctor_infos are actually generated as references to a
% single shared type_ctor_info.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
%
% Transformation of code using existentially quantified types:
%
% The transformation for existential types is similar to the transformation
% for universally quantified types, except that the type_infos and
% type_class_infos have mode `out' rather than mode `in'.
%
% The argument passing convention is that the new parameters
% introduced by this pass are placed in the following order:
%
% First the type_infos for unconstrained universally quantified type
% variables, in the order that the type variables first appear in the
% argument types;
%
% then the type_infos for unconstrained existentially quantified type
% variables, in the order that the type variables first appear in the
% argument types;
%
% then the typeclass_infos for universally quantified constraints,
% in the order that the constraints appear in the class context;
%
% then the typeclass_infos for existentially quantified constraints,
% in the order that the constraints appear in the class context;
%
% and finally the original arguments of the predicate.
%
% Bear in mind that for the purposes of this (and most other) calculations,
% the return parameter of a function counts as the _last_ argument.
%
% The convention for class method implementations is slightly different
% to match the order that the type_infos and typeclass_infos are passed
% in by do_call_class_method (in runtime/mercury_ho_call.c):
%
% First the type_infos for the unconstrained type variables in the
% instance declaration, in the order that the type variables first appear
% in the instance arguments;
%
% then the typeclass_infos for the class constraints on the instance
% declaration, in the order that the constraints appear in the declaration;
%
% then the remainder of the arguments as above.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module check_hlds.polymorphism.
:- interface.
:- import_module hlds.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.hlds_rtti.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module list.
:- import_module maybe.
:- import_module term.
%-----------------------------------------------------------------------------%
% Run the polymorphism pass over the whole HLDS.
%
:- pred polymorphism_process_module(module_info::in, module_info::out) is det.
% Run the polymorphism pass over a single pred. This is used to transform
% clauses introduced by unify_proc.m for complicated unification predicates
% for types for which unification predicates are generated lazily.
%
% This predicate should be used with caution. polymorphism.m expects that
% the argument types of called predicates have not been transformed yet.
% This predicate will not work correctly after the original pass of
% polymorphism has been run if the predicate to be processed calls
% any polymorphic predicates which require type_infos or typeclass_infos
% to be added to the argument list.
%
:- pred polymorphism_process_generated_pred(pred_id::in,
module_info::in, module_info::out) is det.
% Add the type_info variables for a complicated unification to
% the appropriate fields in the unification and the goal_info.
%
:- pred unification_typeinfos_rtti_varmaps(mer_type::in, rtti_varmaps::in,
unification::in, unification::out, hlds_goal_info::in, hlds_goal_info::out)
is det.
% Add the type_info variables for a new call goal. This predicate assumes
% that process_module has already been run so the called pred has already
% been processed.
%
% XXX This predicate does not yet handle calls whose arguments include
% existentially quantified types or type class constraints.
%
:- pred polymorphism_process_new_call(pred_info::in, proc_info::in,
pred_id::in, proc_id::in, list(prog_var)::in, builtin_state::in,
maybe(call_unify_context)::in, sym_name::in, hlds_goal_info::in,
hlds_goal::out, poly_info::in, poly_info::out) is det.
% Given a list of types, create a list of variables to hold the type_info
% for those types, and create a list of goals to initialize those type_info
% variables to the appropriate type_info structures for the types.
% Update the varset and vartypes accordingly.
%
:- pred polymorphism_make_type_info_vars(list(mer_type)::in, term.context::in,
list(prog_var)::out, list(hlds_goal)::out, poly_info::in, poly_info::out)
is det.
% Likewise, but for a single type.
%
:- pred polymorphism_make_type_info_var(mer_type::in, term.context::in,
prog_var::out, list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
:- type int_or_var
---> iov_int(int)
; iov_var(prog_var).
% gen_extract_type_info(ModuleInfo, TypeVar, Kind, TypeClassInfoVar,
% IndexIntOrVar, Goals, TypeInfoVar, ...):
%
% Generate code to extract a type_info variable from a given slot of a
% typeclass_info variable, by calling type_info_from_typeclass_info from
% private_builtin. TypeVar is the type variable to which this type_info
% variable corresponds. Kind is the kind of the type variable.
% TypeClassInfoVar is the variable holding the type_class_info.
% Index specifies which slot it is. The procedure returns TypeInfoVar,
% which is a fresh variable holding the type_info, and Goals, which is
% the code generated to initialize TypeInfoVar.
%
:- pred gen_extract_type_info(module_info::in, tvar::in, kind::in,
prog_var::in, int_or_var::in, list(hlds_goal)::out, prog_var::out,
prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
rtti_varmaps::in, rtti_varmaps::out) is det.
:- type poly_info.
% Extract some fields from a pred_info and proc_info and use them to
% create a poly_info, for use by the polymorphism transformation.
%
:- pred create_poly_info(module_info::in, pred_info::in,
proc_info::in, poly_info::out) is det.
% Update the fields in a pred_info and proc_info with
% the values in a poly_info.
%
:- pred poly_info_extract(poly_info::in, pred_info::in, pred_info::out,
proc_info::in, proc_info::out, module_info::out) is det.
% Build the type describing the typeclass_info for the
% given prog_constraint.
%
:- pred build_typeclass_info_type(prog_constraint::in, mer_type::out) is det.
% Check if a type is the `typeclass_info' type introduced by this pass.
%
:- pred type_is_typeclass_info(mer_type::in) is semidet.
% Check if a type is either the `type_info' type or the
% `type_ctor_info' type introduced by this pass.
%
:- pred type_is_type_info_or_ctor_type(mer_type::in) is semidet.
% Construct the type of the type_info for the given type.
%
:- pred build_type_info_type(mer_type::in, mer_type::out) is det.
% Look up the pred_id and proc_id for a type specific
% unification/comparison/index/initialise predicate.
%
:- pred get_special_proc(mer_type::in, special_pred_id::in,
module_info::in, sym_name::out, pred_id::out, proc_id::out) is semidet.
:- pred get_special_proc_det(mer_type::in, special_pred_id::in,
module_info::in, sym_name::out, pred_id::out, proc_id::out) is det.
% Convert a higher order pred term to a lambda goal.
%
:- pred convert_pred_to_lambda_goal(purity::in, lambda_eval_method::in,
prog_var::in, pred_id::in, proc_id::in, list(prog_var)::in,
list(mer_type)::in, unify_context::in, hlds_goal_info::in, context::in,
module_info::in, unify_rhs::out, prog_varset::in, prog_varset::out,
vartypes::in, vartypes::out) is det.
% fix_undetermined_mode_lambda_goal(ProcId, Functor0, Functor, ModuleInfo)
%
% This is called by mode checking when it figures out which mode that a
% lambda goal converted from a higher order pred term should call.
% Functor0 must have been produced by `convert_pred_to_lambda_goal'.
%
:- pred fix_undetermined_mode_lambda_goal(proc_id::in,
unify_rhs::in(rhs_lambda_goal), unify_rhs::out(rhs_lambda_goal),
module_info::in) is det.
% init_type_info_var(Type, ArgVars, TypeInfoVar, TypeInfoGoal,
% !VarSet, !VarTypes) :-
%
% Create the unification the constructs the second cell of a type_info
% for Type. ArgVars should contain the arguments of this unification.
%
% This unification WILL lead to the creation of cells on the heap
% at runtime.
%
% The first variable in ArgVars should be bound to the type_ctor_info
% for Type's principal type constructor. If that type constructor is
% variable arity, the next variable in ArgVars should be bound to an
% integer giving Type's actual arity. The remaining variables in
% ArgVars should be bound to the type_infos or type_ctor_infos giving
% Type's argument types.
%
:- pred init_type_info_var(mer_type::in, list(prog_var)::in,
maybe(prog_var)::in, prog_var::out, hlds_goal::out,
prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
rtti_varmaps::in, rtti_varmaps::out) is det.
% init_const_type_ctor_info_var(Type, TypeCtor,
% TypeCtorInfoVar, TypeCtorConsId, TypeCtorInfoGoal,
% !VarSet, !VarTypes, !RttiVarMaps):
%
% Create the unification (returned as TypeCtorInfoGoal) that binds a
% new variable (returned as TypeCtorInfoVar) to the type_ctor_info
% representing TypeCtor. This will be the constant represented by
% TypeCtorConsId.
%
% This unification WILL NOT lead to the creation of a cell on the
% heap at runtime; it will cause TypeCtorInfoVar to refer to the
% statically allocated type_ctor_info cell for the type, allocated
% in the module that defines the type.
%
% We take Type as input for historical reasons: we record Type as
% the type whose type constructor TypeCtor is, in the type of
% TypeCtorInfoVar.
%
:- pred init_const_type_ctor_info_var(mer_type::in, type_ctor::in,
prog_var::out, cons_id::out, hlds_goal::out,
prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
rtti_varmaps::in, rtti_varmaps::out) is det.
:- type type_info_kind
---> type_info
; type_ctor_info.
:- pred new_type_info_var_raw(mer_type::in, type_info_kind::in,
prog_var::out, prog_varset::in, prog_varset::out,
vartypes::in, vartypes::out, rtti_varmaps::in, rtti_varmaps::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds.clause_to_proc.
:- import_module check_hlds.mode_util.
:- import_module check_hlds.type_util.
:- import_module hlds.from_ground_term_util.
:- import_module hlds.const_struct.
:- import_module hlds.goal_util.
:- import_module hlds.hlds_args.
:- import_module hlds.hlds_clauses.
:- import_module hlds.hlds_code_util.
:- import_module hlds.hlds_data.
:- import_module hlds.instmap.
:- import_module hlds.passes_aux.
:- import_module hlds.pred_table.
:- import_module hlds.quantification.
:- import_module hlds.special_pred.
:- import_module libs.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module mdbcomp.goal_path.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.program_representation.
:- import_module parse_tree.builtin_lib_types.
:- import_module parse_tree.prog_mode.
:- import_module parse_tree.prog_type.
:- import_module parse_tree.prog_type_subst.
:- import_module parse_tree.set_of_var.
:- import_module assoc_list.
:- import_module bool.
:- import_module int.
:- import_module io.
:- import_module map.
:- import_module pair.
:- import_module require.
:- import_module set.
:- import_module solutions.
:- import_module string.
:- import_module term.
:- import_module varset.
%-----------------------------------------------------------------------------%
%
% This whole section just traverses the module structure.
% We do two passes, the first to fix up the clauses_info and proc_infos
% (and in fact everything except the pred_info argtypes), the second to fix up
% the pred_info argtypes. The reason we need two passes is that the first pass
% looks at the argtypes of the called predicates, and so we need to make
% sure we don't muck them up before we've finished the first pass.
polymorphism_process_module(!ModuleInfo) :-
module_info_get_preds(!.ModuleInfo, Preds0),
map.keys(Preds0, PredIds0),
list.foldl(maybe_polymorphism_process_pred, PredIds0, !ModuleInfo),
module_info_get_preds(!.ModuleInfo, Preds1),
map.keys(Preds1, PredIds1),
list.foldl(fixup_pred_polymorphism, PredIds1, !ModuleInfo),
expand_class_method_bodies(!ModuleInfo).
:- pred maybe_polymorphism_process_pred(pred_id::in,
module_info::in, module_info::out) is det.
maybe_polymorphism_process_pred(PredId, !ModuleInfo) :-
module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
(
PredModule = pred_info_module(PredInfo),
PredName = pred_info_name(PredInfo),
PredArity = pred_info_orig_arity(PredInfo),
no_type_info_builtin(PredModule, PredName, PredArity)
->
% Just copy the clauses to the proc_infos.
copy_module_clauses_to_procs([PredId], !ModuleInfo)
;
polymorphism_process_pred_msg(PredId, !ModuleInfo)
).
%---------------------------------------------------------------------------%
:- pred fixup_pred_polymorphism(pred_id::in,
module_info::in, module_info::out) is det.
fixup_pred_polymorphism(PredId, !ModuleInfo) :-
% Recompute the arg types by finding the headvars and the var->type mapping
% (from the clauses_info) and applying the type mapping to the extra
% headvars to get the new arg types. Note that we are careful to only apply
% the mapping to the extra head vars, not to the originals, because
% otherwise we would stuff up the arg types for unification predicates for
% equivalence types.
module_info_get_preds(!.ModuleInfo, PredTable0),
map.lookup(PredTable0, PredId, PredInfo0),
pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
clauses_info_get_vartypes(ClausesInfo0, VarTypes0),
clauses_info_get_headvars(ClausesInfo0, HeadVars),
pred_info_get_arg_types(PredInfo0, TypeVarSet, ExistQVars, ArgTypes0),
proc_arg_vector_partition_poly_args(HeadVars, ExtraHeadVarList,
OldHeadVarList),
lookup_var_types(VarTypes0, ExtraHeadVarList, ExtraArgTypes),
ArgTypes = ExtraArgTypes ++ ArgTypes0,
pred_info_set_arg_types(TypeVarSet, ExistQVars, ArgTypes,
PredInfo0, PredInfo1),
% If the clauses bind some existentially quantified type variables,
% introduce exists_casts goals for affected head variables, including
% the new type_info and typeclass_info arguments. Make sure the types
% of the internal versions of type_infos for those type variables in the
% variable types map are as specific as possible.
(
ExistQVars = [_ | _],
% This can fail for unification procedures of equivalence types.
lookup_var_types(VarTypes0, OldHeadVarList, OldHeadVarTypes),
type_list_subsumes(ArgTypes0, OldHeadVarTypes, Subn),
\+ map.is_empty(Subn)
->
pred_info_set_existq_tvar_binding(Subn, PredInfo1, PredInfo2),
polymorphism_introduce_exists_casts_pred(!.ModuleInfo, PredInfo2,
PredInfo)
;
PredInfo = PredInfo1
),
map.det_update(PredId, PredInfo, PredTable0, PredTable),
module_info_set_preds(PredTable, !ModuleInfo).
:- pred polymorphism_introduce_exists_casts_pred(module_info::in,
pred_info::in, pred_info::out) is det.
polymorphism_introduce_exists_casts_pred(ModuleInfo, !PredInfo) :-
pred_info_get_procedures(!.PredInfo, Procs0),
map.map_values_only(
(pred(!.ProcInfo::in, !:ProcInfo::out) is det :-
% Add the extra goals to each procedure.
introduce_exists_casts_proc(ModuleInfo, !.PredInfo, !ProcInfo)
), Procs0, Procs),
pred_info_set_procedures(Procs, !PredInfo).
%---------------------------------------------------------------------------%
:- pred polymorphism_process_pred_msg(pred_id::in,
module_info::in, module_info::out) is det.
polymorphism_process_pred_msg(PredId, !ModuleInfo) :-
% Since polymorphism transforms not just the procedures defined
% in the module being compiled, but also all the procedures in
% all the imported modules, this message can be printed A LOT,
% even though it is almost never of interest.
% That is why we enable it only when requested.
trace [compiletime(flag("poly_msgs")), io(!IO)] (
write_pred_progress_message("% Transforming polymorphism for ",
PredId, !.ModuleInfo, !IO)
),
polymorphism_process_pred(PredId, !ModuleInfo).
polymorphism_process_generated_pred(PredId, !ModuleInfo) :-
polymorphism_process_pred(PredId, !ModuleInfo),
fixup_pred_polymorphism(PredId, !ModuleInfo).
:- mutable(selected_pred, bool, no, ground, [untrailed]).
:- mutable(level, int, 0, ground, [untrailed]).
:- pred polymorphism_process_pred(pred_id::in,
module_info::in, module_info::out) is det.
polymorphism_process_pred(PredId, !ModuleInfo) :-
trace [compiletime(flag("debug_poly_caches"))] (
promise_pure (
% Replace 99999 with the id of the predicate you want to debug.
( pred_id_to_int(PredId) = 15 ->
impure set_selected_pred(yes)
;
true
)
)
),
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
% Run the polymorphism pass over the clauses_info, updating the headvars,
% goals, varsets, types, etc., and computing some information in the
% poly_info.
pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
polymorphism_process_clause_info(!.ModuleInfo, PredInfo0,
ClausesInfo0, ClausesInfo, Info, ExtraArgModes),
poly_info_get_module_info(Info, !:ModuleInfo),
poly_info_get_const_struct_db(Info, ConstStructDb),
module_info_set_const_struct_db(ConstStructDb, !ModuleInfo),
poly_info_get_typevarset(Info, TypeVarSet),
pred_info_set_typevarset(TypeVarSet, PredInfo0, PredInfo1),
pred_info_set_clauses_info(ClausesInfo, PredInfo1, PredInfo2),
% Do a pass over the proc_infos, copying the relevant information
% from the clauses_info and the poly_info, and updating all the argmodes
% with modes for the extra arguments.
ProcIds = pred_info_procids(PredInfo2),
pred_info_get_procedures(PredInfo2, Procs0),
list.foldl(polymorphism_process_proc_in_table(PredInfo2, ClausesInfo,
ExtraArgModes), ProcIds, Procs0, Procs),
pred_info_set_procedures(Procs, PredInfo2, PredInfo),
trace [compiletime(flag("debug_poly_caches"))] (
promise_pure (
impure set_selected_pred(no)
)
),
module_info_set_pred_info(PredId, PredInfo, !ModuleInfo).
:- pred polymorphism_process_clause_info(module_info::in, pred_info::in,
clauses_info::in, clauses_info::out, poly_info::out,
poly_arg_vector(mer_mode)::out) is det.
polymorphism_process_clause_info(ModuleInfo0, PredInfo0, !ClausesInfo, !:Info,
ExtraArgModes) :-
init_poly_info(ModuleInfo0, PredInfo0, !.ClausesInfo, !:Info),
!.ClausesInfo = clauses_info(_VarSet, ExplicitVarTypes, _TVarNameMap,
_VarTypes, HeadVars0, ClausesRep0, ItemNumbers,
_RttiVarMaps, HaveForeignClauses),
setup_headvars(PredInfo0, HeadVars0, HeadVars,
ExtraArgModes, UnconstrainedTVars,
ExtraTypeInfoHeadVars, ExistTypeClassInfoHeadVars, !Info),
get_clause_list(ClausesRep0, Clauses0),
list.map_foldl(
polymorphism_process_clause(PredInfo0, HeadVars0, HeadVars,
UnconstrainedTVars, ExtraTypeInfoHeadVars,
ExistTypeClassInfoHeadVars),
Clauses0, Clauses, !Info),
% Set the new values of the fields in clauses_info.
poly_info_get_varset(!.Info, VarSet),
poly_info_get_var_types(!.Info, VarTypes),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps),
set_clause_list(Clauses, ClausesRep),
map.init(TVarNameMap), % This is only used while adding the clauses.
!:ClausesInfo = clauses_info(VarSet, ExplicitVarTypes, TVarNameMap,
VarTypes, HeadVars, ClausesRep, ItemNumbers,
RttiVarMaps, HaveForeignClauses).
:- pred polymorphism_process_clause(pred_info::in,
proc_arg_vector(prog_var)::in, proc_arg_vector(prog_var)::in,
list(tvar)::in, list(prog_var)::in, list(prog_var)::in,
clause::in, clause::out, poly_info::in, poly_info::out) is det.
polymorphism_process_clause(PredInfo0, OldHeadVars, NewHeadVars,
UnconstrainedTVars, ExtraTypeInfoHeadVars,
ExistTypeClassInfoHeadVars, !Clause, !Info) :-
( pred_info_is_imported(PredInfo0) ->
true
;
Goal0 = !.Clause ^ clause_body,
% Process any polymorphic calls inside the goal.
empty_cache_maps(!Info),
poly_info_set_num_reuses(0, !Info),
polymorphism_process_goal(Goal0, Goal1, !Info),
% Generate code to construct the typeclass_infos and type_infos
% for existentially quantified type vars.
produce_existq_tvars(PredInfo0, OldHeadVars,
UnconstrainedTVars, ExtraTypeInfoHeadVars,
ExistTypeClassInfoHeadVars, Goal1, Goal2, !Info),
pred_info_get_exist_quant_tvars(PredInfo0, ExistQVars),
fixup_quantification(NewHeadVars, ExistQVars, Goal2, Goal, !Info),
!Clause ^ clause_body := Goal
).
:- pred polymorphism_process_proc_in_table(pred_info::in, clauses_info::in,
poly_arg_vector(mer_mode)::in, proc_id::in,
proc_table::in, proc_table::out) is det.
polymorphism_process_proc_in_table(PredInfo, ClausesInfo, ExtraArgModes,
ProcId, !ProcTable) :-
map.lookup(!.ProcTable, ProcId, ProcInfo0),
polymorphism_process_proc(PredInfo, ClausesInfo, ExtraArgModes, ProcId,
ProcInfo0, ProcInfo),
map.det_update(ProcId, ProcInfo, !ProcTable).
:- pred polymorphism_process_proc(pred_info::in, clauses_info::in,
poly_arg_vector(mer_mode)::in, proc_id::in, proc_info::in, proc_info::out)
is det.
polymorphism_process_proc(PredInfo, ClausesInfo, ExtraArgModes, ProcId,
!ProcInfo) :-
% Copy all the information from the clauses_info into the proc_info.
(
(
pred_info_is_imported(PredInfo)
;
pred_info_is_pseudo_imported(PredInfo),
hlds_pred.in_in_unification_proc_id(ProcId)
)
->
% We need to set these fields in the proc_info here, because some parts
% of the compiler (e.g. unused_args.m) depend on these fields being
% valid even for imported procedures.
% XXX ARGVEC - when the proc_info uses the proc_arg_vector just
% pass the headvar vector directly to the proc_info.
clauses_info_get_headvars(ClausesInfo, HeadVars),
HeadVarList = proc_arg_vector_to_list(HeadVars),
clauses_info_get_rtti_varmaps(ClausesInfo, RttiVarMaps),
clauses_info_get_varset(ClausesInfo, VarSet),
clauses_info_get_vartypes(ClausesInfo, VarTypes),
proc_info_set_headvars(HeadVarList, !ProcInfo),
proc_info_set_rtti_varmaps(RttiVarMaps, !ProcInfo),
proc_info_set_varset(VarSet, !ProcInfo),
proc_info_set_vartypes(VarTypes, !ProcInfo)
;
copy_clauses_to_proc(ProcId, ClausesInfo, !ProcInfo)
),
% Add the ExtraArgModes to the proc_info argmodes.
% XXX ARGVEC - revisit this when the proc_info uses proc_arg_vectors.
proc_info_get_argmodes(!.ProcInfo, ArgModes1),
ExtraArgModesList = poly_arg_vector_to_list(ExtraArgModes),
ArgModes = ExtraArgModesList ++ ArgModes1,
proc_info_set_argmodes(ArgModes, !ProcInfo).
% XXX document me
%
% XXX the following code ought to be rewritten to handle
% existential/universal type_infos and type_class_infos
% in a more consistent manner.
%
:- pred setup_headvars(pred_info::in, proc_arg_vector(prog_var)::in,
proc_arg_vector(prog_var)::out, poly_arg_vector(mer_mode)::out,
list(tvar)::out, list(prog_var)::out, list(prog_var)::out,
poly_info::in, poly_info::out) is det.
setup_headvars(PredInfo, !HeadVars, ExtraArgModes,
UnconstrainedTVars, ExtraHeadTypeInfoVars,
ExistHeadTypeClassInfoVars, !Info) :-
pred_info_get_origin(PredInfo, Origin),
ExtraArgModes0 = poly_arg_vector_init : poly_arg_vector(mer_mode),
(
Origin = origin_instance_method(_, InstanceMethodConstraints),
setup_headvars_instance_method(PredInfo,
InstanceMethodConstraints, !HeadVars,
UnconstrainedTVars, ExtraHeadTypeInfoVars,
ExistHeadTypeClassInfoVars,
ExtraArgModes0, ExtraArgModes, !Info)
;
( Origin = origin_special_pred(_)
; Origin = origin_transformed(_, _, _)
; Origin = origin_created(_)
; Origin = origin_assertion(_, _)
; Origin = origin_lambda(_, _, _)
; Origin = origin_user(_)
),
pred_info_get_class_context(PredInfo, ClassContext),
InstanceTVars = [],
InstanceUnconstrainedTVars = [],
InstanceUnconstrainedTypeInfoVars = [],
setup_headvars_2(PredInfo, ClassContext, InstanceTVars,
InstanceUnconstrainedTVars, InstanceUnconstrainedTypeInfoVars,
!HeadVars, UnconstrainedTVars,
ExtraHeadTypeInfoVars, ExistHeadTypeClassInfoVars,
ExtraArgModes0, ExtraArgModes, !Info)
).
% For class method implementations, do_call_class_method takes the
% type_infos and typeclass_infos from the typeclass_info and pastes them
% onto the front of the argument list. We need to match that order here.
%
:- pred setup_headvars_instance_method(pred_info::in,
instance_method_constraints::in,
proc_arg_vector(prog_var)::in, proc_arg_vector(prog_var)::out,
list(tvar)::out, list(prog_var)::out, list(prog_var)::out,
poly_arg_vector(mer_mode)::in, poly_arg_vector(mer_mode)::out,
poly_info::in, poly_info::out) is det.
setup_headvars_instance_method(PredInfo,
InstanceMethodConstraints, !HeadVars,
UnconstrainedTVars, ExtraHeadTypeInfoVars,
ExistHeadTypeClassInfoVars, !ExtraArgModes, !Info) :-
InstanceMethodConstraints = instance_method_constraints(_,
InstanceTypes, InstanceConstraints, ClassContext),
type_vars_list(InstanceTypes, InstanceTVars),
get_unconstrained_tvars(InstanceTVars, InstanceConstraints,
UnconstrainedInstanceTVars),
pred_info_get_arg_types(PredInfo, ArgTypeVarSet, _, _),
make_head_vars(UnconstrainedInstanceTVars,
ArgTypeVarSet, UnconstrainedInstanceTypeInfoVars, !Info),
make_typeclass_info_head_vars(do_record_type_info_locns,
InstanceConstraints, InstanceHeadTypeClassInfoVars, !Info),
proc_arg_vector_set_instance_type_infos(UnconstrainedInstanceTypeInfoVars,
!HeadVars),
proc_arg_vector_set_instance_typeclass_infos(InstanceHeadTypeClassInfoVars,
!HeadVars),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
list.foldl(rtti_reuse_typeclass_info_var,
InstanceHeadTypeClassInfoVars, RttiVarMaps0, RttiVarMaps),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info),
in_mode(InMode),
list.duplicate(list.length(UnconstrainedInstanceTypeInfoVars),
InMode, UnconstrainedInstanceTypeInfoModes),
list.duplicate(list.length(InstanceHeadTypeClassInfoVars),
InMode, InstanceHeadTypeClassInfoModes),
poly_arg_vector_set_instance_type_infos(
UnconstrainedInstanceTypeInfoModes, !ExtraArgModes),
poly_arg_vector_set_instance_typeclass_infos(
InstanceHeadTypeClassInfoModes, !ExtraArgModes),
setup_headvars_2(PredInfo, ClassContext,
InstanceTVars,
UnconstrainedInstanceTVars, UnconstrainedInstanceTypeInfoVars,
!HeadVars,
UnconstrainedTVars, ExtraHeadTypeInfoVars,
ExistHeadTypeClassInfoVars, !ExtraArgModes, !Info).
:- pred setup_headvars_2(pred_info::in, prog_constraints::in,
list(tvar)::in, list(tvar)::in, list(prog_var)::in,
proc_arg_vector(prog_var)::in, proc_arg_vector(prog_var)::out,
list(tvar)::out, list(prog_var)::out, list(prog_var)::out,
poly_arg_vector(mer_mode)::in, poly_arg_vector(mer_mode)::out,
poly_info::in, poly_info::out) is det.
setup_headvars_2(PredInfo, ClassContext,
InstanceTVars, UnconstrainedInstanceTVars,
UnconstrainedInstanceTypeInfoVars, HeadVars0,
HeadVars, AllUnconstrainedTVars,
AllExtraHeadTypeInfoVars, ExistHeadTypeClassInfoVars,
!ExtraArgModes, !Info) :-
% Grab the appropriate fields from the pred_info.
pred_info_get_arg_types(PredInfo, ArgTypeVarSet, ExistQVars, ArgTypes),
% Insert extra head variables to hold the address of the type_infos
% and typeclass_infos. We insert one variable for each unconstrained
% type variable (for the type_info) and one variable for each
% constraint (for the typeclass_info).
%
% The order of these variables is important, and must match the order
% specified at the top of this file.
% Make a fresh variable for each class constraint, returning a list of
% variables that appear in the constraints, along with the location of
% the type infos for them. For the existential constraints, we want
% the rtti_varmaps to contain the internal view of the types (that is,
% with type variables bound) so we may need to look up the actual
% constraints in the constraint map. For the universal constraints there
% is no distinction between the internal views and the external view, so
% we just use the constraints from the class context.
ClassContext = constraints(UnivConstraints, ExistConstraints),
prog_type.constraint_list_get_tvars(UnivConstraints,
UnivConstrainedTVars),
prog_type.constraint_list_get_tvars(ExistConstraints,
ExistConstrainedTVars),
poly_info_get_constraint_map(!.Info, ConstraintMap),
get_improved_exists_head_constraints(ConstraintMap, ExistConstraints,
ActualExistConstraints),
(
pred_info_get_markers(PredInfo, PredMarkers),
check_marker(PredMarkers, marker_class_method)
->
% For class methods we record the type_info_locns even for the
% existential constraints. It is easier to do it here than when we
% are expanding class method bodies, and we know there won't be any
% references to the type_info after the instance method call so
% recording them now won't be a problem.
RecordExistQLocns = do_record_type_info_locns
;
RecordExistQLocns = do_not_record_type_info_locns
),
make_typeclass_info_head_vars(RecordExistQLocns, ActualExistConstraints,
ExistHeadTypeClassInfoVars, !Info),
make_typeclass_info_head_vars(do_record_type_info_locns, UnivConstraints,
UnivHeadTypeClassInfoVars, !Info),
type_vars_list(ArgTypes, HeadTypeVars),
list.delete_elems(HeadTypeVars, UnivConstrainedTVars,
UnconstrainedTVars0),
list.delete_elems(UnconstrainedTVars0, ExistConstrainedTVars,
UnconstrainedTVars1),
% Typeinfos for the instance tvars have already been introduced by
% setup_headvars_instance_method.
list.delete_elems(UnconstrainedTVars1, InstanceTVars,
UnconstrainedTVars2),
list.remove_dups(UnconstrainedTVars2, UnconstrainedTVars),
(
ExistQVars = [],
% Optimize common case.
UnconstrainedUnivTVars = UnconstrainedTVars,
UnconstrainedExistTVars = [],
ExistHeadTypeInfoVars = []
;
ExistQVars = [_ | _],
list.delete_elems(UnconstrainedTVars, ExistQVars,
UnconstrainedUnivTVars),
list.delete_elems(UnconstrainedTVars, UnconstrainedUnivTVars,
UnconstrainedExistTVars),
make_head_vars(UnconstrainedExistTVars, ArgTypeVarSet,
ExistHeadTypeInfoVars, !Info)
),
make_head_vars(UnconstrainedUnivTVars, ArgTypeVarSet,
UnivHeadTypeInfoVars, !Info),
ExtraHeadTypeInfoVars = UnivHeadTypeInfoVars ++ ExistHeadTypeInfoVars,
AllExtraHeadTypeInfoVars = UnconstrainedInstanceTypeInfoVars
++ ExtraHeadTypeInfoVars,
list.condense([UnconstrainedInstanceTVars, UnconstrainedUnivTVars,
UnconstrainedExistTVars], AllUnconstrainedTVars),
proc_arg_vector_set_univ_type_infos(UnivHeadTypeInfoVars,
HeadVars0, HeadVars1),
proc_arg_vector_set_exist_type_infos(ExistHeadTypeInfoVars,
HeadVars1, HeadVars2),
proc_arg_vector_set_univ_typeclass_infos(UnivHeadTypeClassInfoVars,
HeadVars2, HeadVars3),
proc_arg_vector_set_exist_typeclass_infos(ExistHeadTypeClassInfoVars,
HeadVars3, HeadVars),
% Figure out the modes of the introduced type_info and typeclass_info
% arguments.
in_mode(In),
out_mode(Out),
list.length(UnconstrainedUnivTVars, NumUnconstrainedUnivTVars),
list.length(UnconstrainedExistTVars, NumUnconstrainedExistTVars),
list.length(UnivHeadTypeClassInfoVars, NumUnivClassInfoVars),
list.length(ExistHeadTypeClassInfoVars, NumExistClassInfoVars),
list.duplicate(NumUnconstrainedUnivTVars, In, UnivTypeInfoModes),
list.duplicate(NumUnconstrainedExistTVars, Out, ExistTypeInfoModes),
list.duplicate(NumUnivClassInfoVars, In, UnivTypeClassInfoModes),
list.duplicate(NumExistClassInfoVars, Out, ExistTypeClassInfoModes),
poly_arg_vector_set_univ_type_infos(UnivTypeInfoModes, !ExtraArgModes),
poly_arg_vector_set_exist_type_infos(ExistTypeInfoModes, !ExtraArgModes),
poly_arg_vector_set_univ_typeclass_infos(UnivTypeClassInfoModes,
!ExtraArgModes),
poly_arg_vector_set_exist_typeclass_infos(ExistTypeClassInfoModes,
!ExtraArgModes),
% Add the locations of the typeinfos for unconstrained, universally
% quantified type variables to the initial rtti_varmaps. Also add the
% locations of typeclass_infos.
%
some [!RttiVarMaps] (
poly_info_get_rtti_varmaps(!.Info, !:RttiVarMaps),
ToLocn = (pred(TheVar::in, TheLocn::out) is det :-
TheLocn = type_info(TheVar)),
list.map(ToLocn, UnivHeadTypeInfoVars, UnivTypeLocns),
list.foldl_corresponding(rtti_det_insert_type_info_locn,
UnconstrainedUnivTVars, UnivTypeLocns, !RttiVarMaps),
list.map(ToLocn, ExistHeadTypeInfoVars, ExistTypeLocns),
list.foldl_corresponding(rtti_det_insert_type_info_locn,
UnconstrainedExistTVars, ExistTypeLocns, !RttiVarMaps),
list.map(ToLocn, UnconstrainedInstanceTypeInfoVars,
UnconstrainedInstanceTypeLocns),
list.foldl_corresponding(rtti_det_insert_type_info_locn,
UnconstrainedInstanceTVars,
UnconstrainedInstanceTypeLocns, !RttiVarMaps),
list.foldl(rtti_reuse_typeclass_info_var,
UnivHeadTypeClassInfoVars, !RttiVarMaps),
poly_info_set_rtti_varmaps(!.RttiVarMaps, !Info)
).
% Generate code to produce the values of type_infos and typeclass_infos
% for existentially quantified type variables in the head.
%
% XXX The following code ought to be rewritten to handle
% existential/universal type_infos and type_class_infos
% in a more consistent manner.
%
:- pred produce_existq_tvars(pred_info::in, proc_arg_vector(prog_var)::in,
list(tvar)::in, list(prog_var)::in, list(prog_var)::in,
hlds_goal::in, hlds_goal::out, poly_info::in, poly_info::out) is det.
produce_existq_tvars(PredInfo, HeadVars, UnconstrainedTVars,
TypeInfoHeadVars, ExistTypeClassInfoHeadVars, Goal0, Goal, !Info) :-
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_constraint_map(!.Info, ConstraintMap),
pred_info_get_arg_types(PredInfo, ArgTypes),
pred_info_get_tvar_kinds(PredInfo, KindMap),
pred_info_get_class_context(PredInfo, PredClassContext),
% Generate code to produce values for any existentially quantified
% typeclass_info variables in the head.
PredExistConstraints = PredClassContext ^ exist_constraints,
get_improved_exists_head_constraints(ConstraintMap, PredExistConstraints,
ActualExistConstraints),
ExistQVarsForCall = [],
Goal0 = hlds_goal(_, GoalInfo),
Context = goal_info_get_context(GoalInfo),
make_typeclass_info_vars(ActualExistConstraints, ExistQVarsForCall,
Context, ExistTypeClassVarsMCAs, ExtraTypeClassGoals, !Info),
assoc_list.keys(ExistTypeClassVarsMCAs, ExistTypeClassVars),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
list.foldl(rtti_reuse_typeclass_info_var, ExistTypeClassVars,
RttiVarMaps0, RttiVarMaps),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info),
assign_var_list(ExistTypeClassInfoHeadVars,
ExistTypeClassVars, ExtraTypeClassUnifyGoals),
% Figure out the bindings for any unconstrained existentially quantified
% type variables in the head.
( vartypes_is_empty(VarTypes0) ->
% This can happen for compiler generated procedures.
map.init(PredToActualTypeSubst)
;
HeadVarList = proc_arg_vector_to_list(HeadVars),
lookup_var_types(VarTypes0, HeadVarList, ActualArgTypes),
type_list_subsumes(ArgTypes, ActualArgTypes, ArgTypeSubst)
->
PredToActualTypeSubst = ArgTypeSubst
;
% This can happen for unification procedures of equivalence types
% error("polymorphism.m: type_list_subsumes failed")
map.init(PredToActualTypeSubst)
),
% Apply the type bindings to the unconstrained type variables to give
% the actual types, and then generate code to initialize the type_infos
% for those types.
apply_subst_to_tvar_list(KindMap, PredToActualTypeSubst,
UnconstrainedTVars, ActualTypes),
polymorphism_do_make_type_info_vars(ActualTypes, Context,
TypeInfoVarsMCAs, ExtraTypeInfoGoals, !Info),
assoc_list.keys(TypeInfoVarsMCAs, TypeInfoVars),
assign_var_list(TypeInfoHeadVars, TypeInfoVars, ExtraTypeInfoUnifyGoals),
list.condense([[Goal0 | ExtraTypeClassGoals], ExtraTypeClassUnifyGoals,
ExtraTypeInfoGoals, ExtraTypeInfoUnifyGoals], GoalList),
conj_list_to_goal(GoalList, GoalInfo, Goal).
:- pred assign_var_list(list(prog_var)::in, list(prog_var)::in,
list(hlds_goal)::out) is det.
assign_var_list([], [_ | _], _) :-
unexpected($module, $pred, "length mismatch").
assign_var_list([_ | _], [], _) :-
unexpected($module, $pred, "length mismatch").
assign_var_list([], [], []).
assign_var_list([Var1 | Vars1], [Var2 | Vars2], [Goal | Goals]) :-
assign_var(Var1, Var2, Goal),
assign_var_list(Vars1, Vars2, Goals).
:- pred assign_var(prog_var::in, prog_var::in, hlds_goal::out) is det.
assign_var(Var1, Var2, Goal) :-
( Var1 = Var2 ->
Goal = true_goal
;
term.context_init(Context),
create_pure_atomic_complicated_unification(Var1, rhs_var(Var2),
Context, umc_explicit, [], Goal)
).
:- pred get_improved_exists_head_constraints(constraint_map::in,
list(prog_constraint)::in, list(prog_constraint)::out) is det.
get_improved_exists_head_constraints(ConstraintMap, ExistConstraints,
ActualExistConstraints) :-
list.length(ExistConstraints, NumExistConstraints),
(
search_hlds_constraint_list(ConstraintMap, unproven, goal_id(0),
NumExistConstraints, ActualExistConstraints0)
->
ActualExistConstraints = ActualExistConstraints0
;
% Some predicates, for example typeclass methods and predicates for
% which we inferred the type, don't have constraint map entries for
% the head constraints. In these cases we can just use the external
% constraints, since there can't be any difference between them and
% the internal ones.
ActualExistConstraints = ExistConstraints
).
%-----------------------------------------------------------------------------%
:- pred polymorphism_process_goal(hlds_goal::in, hlds_goal::out,
poly_info::in, poly_info::out) is det.
polymorphism_process_goal(Goal0, Goal, !Info) :-
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
(
% We don't need to add type_infos for higher order calls, since the
% type_infos are added when the closures are constructed, not when
% they are called.
GoalExpr0 = generic_call(_, _, _, _, _),
Goal = Goal0
;
GoalExpr0 = plain_call(PredId, _, ArgVars0, _, _, _),
polymorphism_process_call(PredId, ArgVars0, GoalInfo0, GoalInfo,
ExtraVars, ExtraGoals, !Info),
ArgVars = ExtraVars ++ ArgVars0,
CallExpr = GoalExpr0 ^ call_args := ArgVars,
Call = hlds_goal(CallExpr, GoalInfo),
GoalList = ExtraGoals ++ [Call],
conj_list_to_goal(GoalList, GoalInfo0, Goal)
;
GoalExpr0 = call_foreign_proc(_, PredId, _, _, _, _, _),
poly_info_get_module_info(!.Info, ModuleInfo),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
PredModule = pred_info_module(PredInfo),
PredName = pred_info_name(PredInfo),
PredArity = pred_info_orig_arity(PredInfo),
( no_type_info_builtin(PredModule, PredName, PredArity) ->
Goal = Goal0
;
polymorphism_process_foreign_proc(PredInfo, GoalExpr0, GoalInfo0,
Goal, !Info)
)
;
GoalExpr0 = unify(XVar, Y, Mode, Unification, UnifyContext),
polymorphism_process_unify(XVar, Y, Mode, Unification, UnifyContext,
GoalInfo0, Goal, !Info)
;
% The rest of the cases just process goals recursively.
(
GoalExpr0 = conj(ConjType, Goals0),
(
ConjType = plain_conj,
polymorphism_process_plain_conj(Goals0, Goals, !Info)
;
ConjType = parallel_conj,
get_cache_maps_snapshot("parconj", InitialSnapshot, !Info),
polymorphism_process_par_conj(Goals0, Goals, InitialSnapshot,
!Info)
% Unlike with disjunctions, we do not have to reset to
% InitialSnapshot.
),
GoalExpr = conj(ConjType, Goals)
;
GoalExpr0 = disj(Goals0),
get_cache_maps_snapshot("disj", InitialSnapshot, !Info),
polymorphism_process_disj(Goals0, Goals, InitialSnapshot, !Info),
set_cache_maps_snapshot("after disj", InitialSnapshot, !Info),
GoalExpr = disj(Goals)
;
GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
get_cache_maps_snapshot("ite", InitialSnapshot, !Info),
polymorphism_process_goal(Cond0, Cond, !Info),
% If we allowed a type_info created inside Cond to be reused
% in Then, then we are adding an output variable to Cond.
% If Cond scope had no outputs to begin with, this would change
% its determinism.
set_cache_maps_snapshot("before then", InitialSnapshot, !Info),
polymorphism_process_goal(Then0, Then, !Info),
set_cache_maps_snapshot("before else", InitialSnapshot, !Info),
polymorphism_process_goal(Else0, Else, !Info),
set_cache_maps_snapshot("after ite", InitialSnapshot, !Info),
GoalExpr = if_then_else(Vars, Cond, Then, Else)
;
GoalExpr0 = negation(SubGoal0),
get_cache_maps_snapshot("neg", InitialSnapshot, !Info),
polymorphism_process_goal(SubGoal0, SubGoal, !Info),
set_cache_maps_snapshot("after neg", InitialSnapshot, !Info),
GoalExpr = negation(SubGoal)
;
GoalExpr0 = switch(Var, CanFail, Cases0),
get_cache_maps_snapshot("switch", InitialSnapshot, !Info),
polymorphism_process_cases(Cases0, Cases, InitialSnapshot, !Info),
set_cache_maps_snapshot("after switch", InitialSnapshot, !Info),
GoalExpr = switch(Var, CanFail, Cases)
;
GoalExpr0 = scope(Reason0, SubGoal0),
(
Reason0 = from_ground_term(TermVar, Kind),
(
Kind = from_ground_term_initial,
polymorphism_process_from_ground_term_initial(TermVar,
GoalInfo0, SubGoal0, GoalExpr, !Info)
;
( Kind = from_ground_term_construct
; Kind = from_ground_term_deconstruct
; Kind = from_ground_term_other
),
polymorphism_process_goal(SubGoal0, SubGoal, !Info),
GoalExpr = scope(Reason0, SubGoal)
)
;
Reason0 = promise_solutions(_, _),
% polymorphism_process_goal may cause SubGoal to bind
% variables (such as PolyConst variables) that SubGoal0 does
% not bind. If we allowed such variables to be reused outside
% the scope, that would change the set of variables that the
% promise would have to cover. We cannot expect and do not want
% user level programmers making promises about variables added
% by the compiler.
get_cache_maps_snapshot("promise_solns", InitialSnapshot,
!Info),
polymorphism_process_goal(SubGoal0, SubGoal, !Info),
set_cache_maps_snapshot("after promise_solns", InitialSnapshot,
!Info),
GoalExpr = scope(Reason0, SubGoal)
;
( Reason0 = promise_purity(_)
; Reason0 = require_detism(_)
; Reason0 = require_complete_switch(_)
; Reason0 = commit(_)
; Reason0 = barrier(_)
; Reason0 = loop_control(_, _, _)
),
polymorphism_process_goal(SubGoal0, SubGoal, !Info),
GoalExpr = scope(Reason0, SubGoal)
;
Reason0 = exist_quant(_),
% If we allowed a type_info created inside SubGoal to be reused
% outside GoalExpr, then we are adding an output variable to
% the scope. If the scope had no outputs to begin with, this
% would change the determinism of the scope.
%
% However, using a type_info from before the scope in SubGoal
% is perfectly ok.
get_cache_maps_snapshot("exists", InitialSnapshot, !Info),
polymorphism_process_goal(SubGoal0, SubGoal, !Info),
set_cache_maps_snapshot("after exists", InitialSnapshot,
!Info),
GoalExpr = scope(Reason0, SubGoal)
;
Reason0 = trace_goal(_, _, _, _, _),
% Trace goal scopes will be deleted after semantic analysis
% if their compile-time condition turns out to be false.
% If we let later code use type_infos introduced inside the
% scope, the deletion of the scope would leave those variables
% undefined.
%
% We *could* evaluate the compile-time condition here to know
% whether the deletion will happen or not, but doing so would
% require breaching the separation between compiler passes.
get_cache_maps_snapshot("trace", InitialSnapshot, !Info),
polymorphism_process_goal(SubGoal0, SubGoal, !Info),
set_cache_maps_snapshot("after trace", InitialSnapshot, !Info),
GoalExpr = scope(Reason0, SubGoal)
)
),
Goal = hlds_goal(GoalExpr, GoalInfo0)
;
GoalExpr0 = shorthand(ShortHand0),
(
ShortHand0 = atomic_goal(GoalType, Outer, Inner, Vars,
MainGoal0, OrElseGoals0, OrElseInners),
get_cache_maps_snapshot("atomic", InitialSnapshot, !Info),
polymorphism_process_goal(MainGoal0, MainGoal, !Info),
polymorphism_process_disj(OrElseGoals0, OrElseGoals,
InitialSnapshot, !Info),
set_cache_maps_snapshot("after atomic", InitialSnapshot, !Info),
ShortHand = atomic_goal(GoalType, Outer, Inner, Vars,
MainGoal, OrElseGoals, OrElseInners)
;
ShortHand0 = try_goal(MaybeIO, ResultVar, SubGoal0),
% We don't let the code inside and outside the try goal share
% type_info variables for the same reason as with lambda
% expressions; because those pieces of code will end up
% in different procedures. However, for try goals, this is true
% even for the first and second conjuncts.
get_cache_maps_snapshot("try", InitialSnapshot, !Info),
(
SubGoal0 = hlds_goal(SubGoalExpr0, SubGoalInfo),
SubGoalExpr0 = conj(plain_conj, Conjuncts0),
Conjuncts0 = [ConjunctA0, ConjunctB0]
->
empty_cache_maps(!Info),
polymorphism_process_goal(ConjunctA0, ConjunctA, !Info),
empty_cache_maps(!Info),
polymorphism_process_goal(ConjunctB0, ConjunctB, !Info),
Conjuncts = [ConjunctA, ConjunctB],
SubGoalExpr = conj(plain_conj, Conjuncts),
SubGoal = hlds_goal(SubGoalExpr, SubGoalInfo)
;
unexpected($module, $pred, "malformed try goal")
),
set_cache_maps_snapshot("after try", InitialSnapshot, !Info),
ShortHand = try_goal(MaybeIO, ResultVar, SubGoal)
;
ShortHand0 = bi_implication(_, _),
unexpected($module, $pred, "bi_implication")
),
GoalExpr = shorthand(ShortHand),
Goal = hlds_goal(GoalExpr, GoalInfo0)
).
%-----------------------------------------------------------------------------%
:- pred polymorphism_process_from_ground_term_initial(prog_var::in,
hlds_goal_info::in, hlds_goal::in, hlds_goal_expr::out,
poly_info::in, poly_info::out) is det.
polymorphism_process_from_ground_term_initial(TermVar, GoalInfo0, SubGoal0,
GoalExpr, !Info) :-
SubGoal0 = hlds_goal(SubGoalExpr0, SubGoalInfo0),
( SubGoalExpr0 = conj(plain_conj, SubGoals0Prime) ->
SubGoals0 = SubGoals0Prime
;
unexpected($module, $pred,
"from_ground_term_initial goal is not plain conj")
),
polymorphism_process_fgti_goals(SubGoals0, [], RevMarkedSubGoals,
fgt_invariants_kept, InvariantsStatus, !Info),
(
InvariantsStatus = fgt_invariants_kept,
Reason = from_ground_term(TermVar, from_ground_term_initial),
GoalExpr = scope(Reason, SubGoal0)
;
InvariantsStatus = fgt_invariants_broken,
introduce_partial_fgt_scopes(GoalInfo0, SubGoalInfo0,
RevMarkedSubGoals, deconstruct_top_down, SubGoal),
% Delete the scope wrapper around SubGoal0.
SubGoal = hlds_goal(GoalExpr, _)
).
:- pred polymorphism_process_fgti_goals(list(hlds_goal)::in,
list(fgt_marked_goal)::in, list(fgt_marked_goal)::out,
fgt_invariants_status::in, fgt_invariants_status::out,
poly_info::in, poly_info::out) is det.
polymorphism_process_fgti_goals([], !RevMarkedGoals, !InvariantsStatus, !Info).
polymorphism_process_fgti_goals([Goal0 | Goals0], !RevMarkedGoals,
!InvariantsStatus, !Info) :-
% This is used only if polymorphism_fgt_sanity_tests is enabled.
OldInfo = !.Info,
Goal0 = hlds_goal(GoalExpr0, GoalInfo0),
(
GoalExpr0 = unify(XVarPrime, Y, ModePrime, UnificationPrime,
UnifyContextPrime),
Y = rhs_functor(ConsIdPrime, _, YVarsPrime)
->
XVar = XVarPrime,
Mode = ModePrime,
Unification = UnificationPrime,
UnifyContext = UnifyContextPrime,
ConsId = ConsIdPrime,
YVars = YVarsPrime
;
unexpected($module, $pred,
"from_ground_term_initial conjunct is not functor unify")
),
polymorphism_process_unify_functor(XVar, ConsId, YVars, Mode,
Unification, UnifyContext, GoalInfo0, Goal, Changed, !Info),
(
Changed = no,
trace [compiletime(flag("polymorphism_fgt_sanity_tests"))] (
poly_info_get_varset(OldInfo, VarSetBefore),
MaxVarBefore = varset.max_var(VarSetBefore),
poly_info_get_num_reuses(OldInfo, NumReusesBefore),
poly_info_get_varset(!.Info, VarSetAfter),
MaxVarAfter = varset.max_var(VarSetAfter),
poly_info_get_num_reuses(!.Info, NumReusesAfter),
expect(unify(MaxVarBefore, MaxVarAfter), $module, $pred,
"MaxVarBefore != MaxVarAfter"),
expect(unify(NumReusesBefore, NumReusesAfter), $module, $pred,
"NumReusesBefore != NumReusesAfter"),
expect(unify(Goal0, Goal), $module, $pred,
"Goal0 != Goal")
),
MarkedGoal = fgt_kept_goal(Goal0, XVar, YVars)
;
Changed = yes,
MarkedGoal = fgt_broken_goal(Goal, XVar, YVars),
!:InvariantsStatus = fgt_invariants_broken
),
!:RevMarkedGoals = [MarkedGoal | !.RevMarkedGoals],
polymorphism_process_fgti_goals(Goals0, !RevMarkedGoals,
!InvariantsStatus, !Info).
%-----------------------------------------------------------------------------%
:- pred polymorphism_process_unify(prog_var::in, unify_rhs::in,
unify_mode::in, unification::in, unify_context::in, hlds_goal_info::in,
hlds_goal::out, poly_info::in, poly_info::out) is det.
polymorphism_process_unify(XVar, Y, Mode, Unification0, UnifyContext,
GoalInfo0, Goal, !Info) :-
(
Y = rhs_var(_YVar),
% Var-var unifications (simple_test, assign, or complicated_unify)
% are basically left unchanged. Complicated unifications will
% eventually get converted into calls, but that is done later on,
% by simplify.m, not now. At this point we just need to figure out
% which type_info/typeclass_info variables the unification might need,
% and insert them in the nonlocals. We have to do that for all var-var
% unifications, because at this point we haven't done mode analysis so
% we don't know which ones will become complicated_unifies.
% Note that we also store the type_info/typeclass_info variables
% in a field in the unification, which quantification.m uses when
% requantifying things.
poly_info_get_var_types(!.Info, VarTypes),
lookup_var_type(VarTypes, XVar, Type),
unification_typeinfos(Type, Unification0, Unification,
GoalInfo0, GoalInfo, _Changed, !Info),
Goal = hlds_goal(unify(XVar, Y, Mode, Unification, UnifyContext),
GoalInfo)
;
Y = rhs_functor(ConsId, _, Args),
polymorphism_process_unify_functor(XVar, ConsId, Args, Mode,
Unification0, UnifyContext, GoalInfo0, Goal, _Changed, !Info)
;
Y = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
ArgVars0, LambdaVars, Modes, Det, LambdaGoal0),
% For lambda expressions, we must recursively traverse the lambda goal.
% Any type_info variables needed by the lambda goal are created in the
% lambda goal (not imported from the outside), and any type_info
% variables created by the lambda goal are not available outside.
% This is because, after lambda expansion, the code inside and outside
% the lambda goal will end up in different procedures.
get_cache_maps_snapshot("lambda", InitialSnapshot, !Info),
empty_cache_maps(!Info),
polymorphism_process_goal(LambdaGoal0, LambdaGoal1, !Info),
set_cache_maps_snapshot("after lambda", InitialSnapshot, !Info),
% Currently we don't allow lambda goals to be existentially typed.
ExistQVars = [],
fixup_lambda_quantification(ArgVars0, LambdaVars, ExistQVars,
LambdaGoal1, LambdaGoal, NonLocalTypeInfos, !Info),
set_of_var.to_sorted_list(NonLocalTypeInfos, NonLocalTypeInfosList),
ArgVars = NonLocalTypeInfosList ++ ArgVars0,
Y1 = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
ArgVars, LambdaVars, Modes, Det, LambdaGoal),
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
set_of_var.union(NonLocals0, NonLocalTypeInfos, NonLocals),
goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo),
% Complicated (in-in) argument unifications are impossible for lambda
% expressions, so we don't need to worry about adding the type_infos
% that would be required for such unifications.
Goal = hlds_goal(unify(XVar, Y1, Mode, Unification0, UnifyContext),
GoalInfo)
).
:- pred unification_typeinfos(mer_type::in,
unification::in, unification::out, hlds_goal_info::in, hlds_goal_info::out,
bool::out, poly_info::in, poly_info::out) is det.
unification_typeinfos(Type, !Unification, !GoalInfo, Changed, !Info) :-
% Compute the type_info/type_class_info variables that would be used
% if this unification ends up being a complicated_unify.
type_vars(Type, TypeVars),
(
TypeVars = [],
Changed = no
;
TypeVars = [_ | _],
list.map_foldl(get_type_info_locn, TypeVars, TypeInfoLocns, !Info),
add_unification_typeinfos(TypeInfoLocns, !Unification, !GoalInfo),
Changed = yes
).
unification_typeinfos_rtti_varmaps(Type, RttiVarMaps, !Unification,
!GoalInfo) :-
% This variant is for use by modecheck_unify.m. During mode checking,
% all the type_infos should appear in the type_info_varmap.
% Compute the type_info/type_class_info variables that would be used
% if this unification ends up being a complicated_unify.
type_vars(Type, TypeVars),
list.map(rtti_lookup_type_info_locn(RttiVarMaps), TypeVars,
TypeInfoLocns),
add_unification_typeinfos(TypeInfoLocns, !Unification, !GoalInfo).
:- pred add_unification_typeinfos(list(type_info_locn)::in,
unification::in, unification::out,
hlds_goal_info::in, hlds_goal_info::out) is det.
add_unification_typeinfos(TypeInfoLocns, !Unification, !GoalInfo) :-
list.map(type_info_locn_var, TypeInfoLocns, TypeInfoVars0),
list.remove_dups(TypeInfoVars0, TypeInfoVars),
% Insert the TypeInfoVars into the nonlocals field of the goal_info
% for the unification goal.
NonLocals0 = goal_info_get_nonlocals(!.GoalInfo),
set_of_var.insert_list(TypeInfoVars, NonLocals0, NonLocals),
goal_info_set_nonlocals(NonLocals, !GoalInfo),
% Also save those type_info vars into a field in the complicated_unify,
% so that quantification.m can recompute variable scopes properly.
% This field is also used by modecheck_unify.m -- for complicated
% unifications, it checks that all these variables are ground.
(
!.Unification = complicated_unify(Modes, CanFail, _),
!:Unification = complicated_unify(Modes, CanFail, TypeInfoVars)
;
% This can happen if an earlier stage of compilation has already
% determined that this unification is particular kind of unification.
% In that case, the type_info vars won't be needed.
( !.Unification = construct(_, _, _, _, _, _, _)
; !.Unification = deconstruct(_, _, _, _, _, _)
; !.Unification = assign(_, _)
; !.Unification = simple_test(_, _)
)
).
:- pred polymorphism_process_unify_functor(prog_var::in, cons_id::in,
list(prog_var)::in, unify_mode::in, unification::in, unify_context::in,
hlds_goal_info::in, hlds_goal::out, bool::out,
poly_info::in, poly_info::out) is det.
polymorphism_process_unify_functor(X0, ConsId0, ArgVars0, Mode0, Unification0,
UnifyContext, GoalInfo0, Goal, Changed, !Info) :-
poly_info_get_module_info(!.Info, ModuleInfo0),
poly_info_get_var_types(!.Info, VarTypes0),
lookup_var_type(VarTypes0, X0, TypeOfX),
list.length(ArgVars0, Arity),
% We replace any unifications with higher order pred constants
% by lambda expressions. For example, we replace
%
% X = list.append(Y) % Y::in, X::out
%
% with
%
% X = (pred(A1::in, A2::out) is ... :- list.append(Y, A1, A2))
%
% We do this because it makes two things easier. First, mode analysis
% needs to check that the lambda goal doesn't bind any nonlocal variables
% (e.g. `Y' in above example). This would require a bit of moderately
% tricky special case code if we didn't expand them here. Second, this pass
% (polymorphism.m) is a lot easier if we don't have to handle higher order
% constants. If it turns out that the predicate was nonpolymorphic,
% lambda.m will turn the lambda expression back into a higher order
% constant again.
%
% Note that this transformation is also done by modecheck_unify.m, in case
% we are rerunning mode analysis after lambda.m has already been run;
% any changes to the code here will also need to be duplicated there.
(
% Check if variable has a higher order type.
ConsId0 = closure_cons(ShroudedPredProcId, _),
proc(PredId, ProcId0) = unshroud_pred_proc_id(ShroudedPredProcId),
type_is_higher_order_details(TypeOfX, Purity, _PredOrFunc, EvalMethod,
CalleeArgTypes)
->
% An `invalid_proc_id' means the predicate is multi-moded. We can't
% pick the right mode yet. Perform the rest of the transformation with
% any mode (the first) but mark the goal with a feature so that mode
% checking knows to fix it up later.
( ProcId0 = invalid_proc_id ->
module_info_pred_info(ModuleInfo0, PredId, PredInfo),
ProcIds = pred_info_procids(PredInfo),
(
ProcIds = [ProcId | _],
goal_info_add_feature(feature_lambda_undetermined_mode,
GoalInfo0, GoalInfo1)
;
ProcIds = [],
unexpected($module, $pred, "no modes")
)
;
ProcId = ProcId0,
GoalInfo1 = GoalInfo0
),
% Convert the higher order pred term to a lambda goal.
poly_info_get_varset(!.Info, VarSet0),
Context = goal_info_get_context(GoalInfo0),
convert_pred_to_lambda_goal(Purity, EvalMethod, X0, PredId, ProcId,
ArgVars0, CalleeArgTypes, UnifyContext, GoalInfo1, Context,
ModuleInfo0, Functor0, VarSet0, VarSet, VarTypes0, VarTypes),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
% Process the unification in its new form.
polymorphism_process_unify(X0, Functor0, Mode0, Unification0,
UnifyContext, GoalInfo1, Goal, !Info),
Changed = yes
;
% Is this a construction or deconstruction of an existentially
% typed data type?
% Check whether the functor had a "new " prefix.
% If so, assume it is a construction, and strip off the prefix.
% Otherwise, assume it is a deconstruction.
ConsId0 = cons(Functor0, Arity, ConsTypeCtor),
( remove_new_prefix(Functor0, OrigFunctor) ->
ConsId = cons(OrigFunctor, Arity, ConsTypeCtor),
IsConstruction = yes
;
ConsId = ConsId0,
IsConstruction = no
),
% Check whether the functor (with the "new " prefix removed)
% is an existentially typed functor.
type_util.get_existq_cons_defn(ModuleInfo0, TypeOfX, ConsId, ConsDefn)
->
% Add extra arguments to the unification for the
% type_info and/or type_class_info variables.
lookup_var_types(VarTypes0, ArgVars0, ActualArgTypes),
polymorphism_process_existq_unify_functor(ConsDefn,
IsConstruction, ActualArgTypes, TypeOfX, GoalInfo0,
ExtraVars, ExtraGoals, !Info),
ArgVars = ExtraVars ++ ArgVars0,
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
set_of_var.insert_list(ExtraVars, NonLocals0, NonLocals),
goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo1),
% Some of the argument unifications may be complicated unifications,
% which may need type_infos.
unification_typeinfos(TypeOfX, Unification0, Unification,
GoalInfo1, GoalInfo, _Changed, !Info),
UnifyExpr = unify(X0, rhs_functor(ConsId, IsConstruction, ArgVars),
Mode0, Unification, UnifyContext),
Unify = hlds_goal(UnifyExpr, GoalInfo),
GoalList = ExtraGoals ++ [Unify],
conj_list_to_goal(GoalList, GoalInfo0, Goal),
Changed = yes
;
% We leave construction/deconstruction unifications alone.
% Some of the argument unifications may be complicated unifications,
% which may need type_infos.
% XXX Return original Goal0 if Changed = no.
unification_typeinfos(TypeOfX, Unification0, Unification,
GoalInfo0, GoalInfo, Changed, !Info),
GoalExpr = unify(X0, rhs_functor(ConsId0, no, ArgVars0), Mode0,
Unification, UnifyContext),
Goal = hlds_goal(GoalExpr, GoalInfo)
).
convert_pred_to_lambda_goal(Purity, EvalMethod, X0, PredId, ProcId,
ArgVars0, PredArgTypes, UnifyContext, GoalInfo0, Context,
ModuleInfo0, Functor, !VarSet, !VarTypes) :-
% Create the new lambda-quantified variables.
create_fresh_vars(PredArgTypes, LambdaVars, !VarSet, !VarTypes),
Args = ArgVars0 ++ LambdaVars,
% Build up the hlds_goal_expr for the call that will form the lambda goal.
module_info_pred_proc_info(ModuleInfo0, PredId, ProcId,
PredInfo, ProcInfo),
PredModule = pred_info_module(PredInfo),
PredName = pred_info_name(PredInfo),
QualifiedPName = qualified(PredModule, PredName),
% The ConsId's type_ctor shouldn't matter in a call_unify_context.
ConsId = cons(QualifiedPName, list.length(ArgVars0),
cons_id_dummy_type_ctor),
RHS = rhs_functor(ConsId, no, ArgVars0),
CallUnifyContext = call_unify_context(X0, RHS, UnifyContext),
LambdaGoalExpr = plain_call(PredId, ProcId, Args, not_builtin,
yes(CallUnifyContext), QualifiedPName),
% Construct a goal_info for the lambda goal, making sure to set up
% the nonlocals field in the goal_info correctly. The goal_id is needed
% to compute constraint_ids correctly.
NonLocals = goal_info_get_nonlocals(GoalInfo0),
set_of_var.insert_list(LambdaVars, NonLocals, OutsideVars),
set_of_var.list_to_set(Args, InsideVars),
set_of_var.intersect(OutsideVars, InsideVars, LambdaNonLocals),
GoalId = goal_info_get_goal_id(GoalInfo0),
goal_info_init(LambdaGoalInfo0),
goal_info_set_context(Context, LambdaGoalInfo0, LambdaGoalInfo1),
goal_info_set_nonlocals(LambdaNonLocals, LambdaGoalInfo1, LambdaGoalInfo2),
goal_info_set_purity(Purity, LambdaGoalInfo2, LambdaGoalInfo3),
goal_info_set_goal_id(GoalId, LambdaGoalInfo3, LambdaGoalInfo),
LambdaGoal = hlds_goal(LambdaGoalExpr, LambdaGoalInfo),
% Work out the modes of the introduced lambda variables and the determinism
% of the lambda goal.
lambda_modes_and_det(ProcInfo, LambdaVars, LambdaModes, LambdaDet),
% Construct the lambda expression.
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
% Higher-order values created in this fashion are always ground.
Groundness = ho_ground,
Functor = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
ArgVars0, LambdaVars, LambdaModes, LambdaDet, LambdaGoal).
fix_undetermined_mode_lambda_goal(ProcId, Functor0, Functor, ModuleInfo) :-
Functor0 = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
ArgVars0, LambdaVars, _LambdaModes0, _LambdaDet0, LambdaGoal0),
LambdaGoal0 = hlds_goal(_, LambdaGoalInfo),
goal_to_conj_list(LambdaGoal0, LambdaGoalList0),
(
list.split_last(LambdaGoalList0, LambdaGoalButLast0, LastGoal0),
LastGoal0 = hlds_goal(LastGoalExpr0, LastGoalInfo0),
LastGoalExpr0 = plain_call(PredId0, _DummyProcId, Args0, not_builtin,
MaybeCallUnifyContext0, QualifiedPName0)
->
LambdaGoalButLast = LambdaGoalButLast0,
LastGoalInfo = LastGoalInfo0,
PredId = PredId0,
Args = Args0,
MaybeCallUnifyContext = MaybeCallUnifyContext0,
QualifiedPName = QualifiedPName0
;
unexpected($module, $pred, "unmatched lambda goal")
),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
% Build up the lambda goal.
LastGoalExpr = plain_call(PredId, ProcId, Args, not_builtin,
MaybeCallUnifyContext, QualifiedPName),
LastGoal = hlds_goal(LastGoalExpr, LastGoalInfo),
conj_list_to_goal(LambdaGoalButLast ++ [LastGoal], LambdaGoalInfo,
LambdaGoal),
% Work out the modes of the introduced lambda variables and the determinism
% of the lambda goal.
lambda_modes_and_det(ProcInfo, LambdaVars, LambdaModes, LambdaDet),
% Construct the lambda expression.
Functor = rhs_lambda_goal(Purity, Groundness, PredOrFunc, EvalMethod,
ArgVars0, LambdaVars, LambdaModes, LambdaDet, LambdaGoal).
:- pred lambda_modes_and_det(proc_info::in, prog_vars::in, list(mer_mode)::out,
determinism::out) is det.
lambda_modes_and_det(ProcInfo, LambdaVars, LambdaModes, LambdaDet) :-
proc_info_get_argmodes(ProcInfo, ArgModes),
list.length(ArgModes, NumArgModes),
list.length(LambdaVars, NumLambdaVars),
( list.drop(NumArgModes - NumLambdaVars, ArgModes, LambdaModesPrime) ->
LambdaModes = LambdaModesPrime
;
unexpected($module, $pred, "list.drop failed")
),
proc_info_get_declared_determinism(ProcInfo, MaybeDet),
(
MaybeDet = yes(Det),
LambdaDet = Det
;
MaybeDet = no,
sorry($module, $pred,
"determinism inference for higher order predicate terms.")
).
:- pred create_fresh_vars(list(mer_type)::in, list(prog_var)::out,
prog_varset::in, prog_varset::out, vartypes::in, vartypes::out) is det.
create_fresh_vars([], [], !VarSet, !VarTypes).
create_fresh_vars([Type | Types], [Var | Vars], !VarSet, !VarTypes) :-
varset.new_var(Var, !VarSet),
add_var_type(Var, Type, !VarTypes),
create_fresh_vars(Types, Vars, !VarSet, !VarTypes).
%-----------------------------------------------------------------------------%
% Compute the extra arguments that we need to add to a unification with
% an existentially quantified data constructor.
%
:- pred polymorphism_process_existq_unify_functor(ctor_defn::in, bool::in,
list(mer_type)::in, mer_type::in, hlds_goal_info::in, list(prog_var)::out,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
polymorphism_process_existq_unify_functor(CtorDefn, IsConstruction,
ActualArgTypes, ActualRetType, GoalInfo,
ExtraVars, ExtraGoals, !Info) :-
CtorDefn = ctor_defn(CtorTypeVarSet, CtorExistQVars, CtorKindMap,
CtorExistentialConstraints, CtorArgTypes, CtorRetType),
% Rename apart the type variables in the constructor definition.
poly_info_get_typevarset(!.Info, TypeVarSet0),
tvarset_merge_renaming(TypeVarSet0, CtorTypeVarSet, TypeVarSet,
CtorToParentRenaming),
apply_variable_renaming_to_tvar_list(CtorToParentRenaming,
CtorExistQVars, ParentExistQVars),
apply_variable_renaming_to_tvar_kind_map(CtorToParentRenaming,
CtorKindMap, ParentKindMap),
apply_variable_renaming_to_prog_constraint_list(CtorToParentRenaming,
CtorExistentialConstraints, ParentExistentialConstraints),
apply_variable_renaming_to_type_list(CtorToParentRenaming,
CtorArgTypes, ParentArgTypes),
apply_variable_renaming_to_type(CtorToParentRenaming, CtorRetType,
ParentRetType),
poly_info_set_typevarset(TypeVarSet, !Info),
% Compute the type bindings resulting from the functor's actual argument
% and return types. These are the ones that might bind the ExistQVars.
type_list_subsumes_det([ParentRetType | ParentArgTypes],
[ActualRetType | ActualArgTypes], ParentToActualTypeSubst),
% Create type_class_info variables for the type class constraints.
poly_info_get_constraint_map(!.Info, ConstraintMap),
GoalId = goal_info_get_goal_id(GoalInfo),
list.length(ParentExistentialConstraints, NumExistentialConstraints),
Context = goal_info_get_context(GoalInfo),
(
IsConstruction = yes,
% Assume it is a construction.
lookup_hlds_constraint_list(ConstraintMap, unproven, GoalId,
NumExistentialConstraints, ActualExistentialConstraints),
make_typeclass_info_vars(ActualExistentialConstraints, [], Context,
ExtraTypeClassVarsMCAs, ExtraTypeClassGoals, !Info),
assoc_list.keys(ExtraTypeClassVarsMCAs, ExtraTypeClassVars)
;
IsConstruction = no,
% Assume it is a deconstruction.
lookup_hlds_constraint_list(ConstraintMap, assumed, GoalId,
NumExistentialConstraints, ActualExistentialConstraints),
make_existq_typeclass_info_vars(ActualExistentialConstraints,
ExtraTypeClassVars, ExtraTypeClassGoals, !Info)
),
% Compute the set of _unconstrained_ existentially quantified type
% variables, and then apply the type bindings to those type variables
% to figure out what types they are bound to.
constraint_list_get_tvars(ParentExistentialConstraints,
ParentExistConstrainedTVars),
list.delete_elems(ParentExistQVars, ParentExistConstrainedTVars,
ParentUnconstrainedExistQVars),
apply_rec_subst_to_tvar_list(ParentKindMap, ParentToActualTypeSubst,
ParentUnconstrainedExistQVars, ActualExistentialTypes),
% Create type_info variables for the _unconstrained_ existentially
% quantified type variables.
polymorphism_do_make_type_info_vars(ActualExistentialTypes, Context,
ExtraTypeInfoVarsMCAs, ExtraTypeInfoGoals, !Info),
assoc_list.keys(ExtraTypeInfoVarsMCAs, ExtraTypeInfoVars),
% The type_class_info variables go AFTER the type_info variables
% (for consistency with the order for argument passing,
% and because the RTTI support in the runtime system relies on it)
ExtraGoals = ExtraTypeInfoGoals ++ ExtraTypeClassGoals,
ExtraVars = ExtraTypeInfoVars ++ ExtraTypeClassVars.
%-----------------------------------------------------------------------------%
:- pred polymorphism_process_foreign_proc(pred_info::in,
hlds_goal_expr::in(bound(call_foreign_proc(ground,ground,ground,ground,
ground,ground,ground))), hlds_goal_info::in, hlds_goal::out,
poly_info::in, poly_info::out) is det.
polymorphism_process_foreign_proc(PredInfo, GoalExpr0, GoalInfo0,
Goal, !Info) :-
% Insert the type_info vars into the argname map, so that the foreign_proc
% can refer to the type_info variable for type T as `TypeInfo_for_T'.
GoalExpr0 = call_foreign_proc(Attributes, PredId, ProcId,
Args0, ProcExtraArgs, MaybeTraceRuntimeCond, Impl),
ArgVars0 = list.map(foreign_arg_var, Args0),
polymorphism_process_call(PredId, ArgVars0, GoalInfo0, GoalInfo,
ExtraVars, ExtraGoals, !Info),
CanOptAwayUnnamed = yes,
polymorphism_process_foreign_proc_args(PredInfo, CanOptAwayUnnamed, Impl,
ExtraVars, ExtraArgs),
Args = ExtraArgs ++ Args0,
% Plug it all back together.
CallExpr = call_foreign_proc(Attributes, PredId, ProcId,
Args, ProcExtraArgs, MaybeTraceRuntimeCond, Impl),
Call = hlds_goal(CallExpr, GoalInfo),
GoalList = ExtraGoals ++ [Call],
conj_list_to_goal(GoalList, GoalInfo0, Goal).
:- pred polymorphism_process_foreign_proc_args(pred_info::in, bool::in,
pragma_foreign_code_impl::in, list(prog_var)::in, list(foreign_arg)::out)
is det.
polymorphism_process_foreign_proc_args(PredInfo, CanOptAwayUnnamed, Impl, Vars,
Args) :-
pred_info_get_arg_types(PredInfo, PredTypeVarSet, ExistQVars,
PredArgTypes),
% Find out which variables are constrained (so that we don't add
% type_infos for them).
pred_info_get_class_context(PredInfo, constraints(UnivCs, ExistCs)),
UnivVars0 = list.map(get_constrained_vars, UnivCs),
list.condense(UnivVars0, UnivConstrainedVars),
ExistVars0 = list.map(get_constrained_vars, ExistCs),
list.condense(ExistVars0, ExistConstrainedVars),
type_vars_list(PredArgTypes, PredTypeVars0),
list.remove_dups(PredTypeVars0, PredTypeVars1),
list.delete_elems(PredTypeVars1, UnivConstrainedVars, PredTypeVars2),
list.delete_elems(PredTypeVars2, ExistConstrainedVars, PredTypeVars),
% The argument order is described at the top of this file.
in_mode(In),
out_mode(Out),
list.map(foreign_proc_add_typeclass_info(CanOptAwayUnnamed, Out, Impl,
PredTypeVarSet), ExistCs, ExistTypeClassArgInfos),
list.map(foreign_proc_add_typeclass_info(CanOptAwayUnnamed, In, Impl,
PredTypeVarSet), UnivCs, UnivTypeClassArgInfos),
TypeClassArgInfos = UnivTypeClassArgInfos ++ ExistTypeClassArgInfos,
list.filter((pred(X::in) is semidet :- list.member(X, ExistQVars)),
PredTypeVars, ExistUnconstrainedVars, UnivUnconstrainedVars),
list.map(foreign_proc_add_typeinfo(CanOptAwayUnnamed, Out, Impl,
PredTypeVarSet), ExistUnconstrainedVars, ExistTypeArgInfos),
list.map(foreign_proc_add_typeinfo(CanOptAwayUnnamed, In, Impl,
PredTypeVarSet), UnivUnconstrainedVars, UnivTypeArgInfos),
TypeInfoArgInfos = UnivTypeArgInfos ++ ExistTypeArgInfos,
ArgInfos = TypeInfoArgInfos ++ TypeClassArgInfos,
% Insert type_info/typeclass_info types for all the inserted
% type_info/typeclass_info vars into the argument type list.
TypeInfoTypes = list.map((func(_) = type_info_type), PredTypeVars),
list.map(build_typeclass_info_type, UnivCs, UnivTypes),
list.map(build_typeclass_info_type, ExistCs, ExistTypes),
OrigArgTypes = TypeInfoTypes ++ UnivTypes ++ ExistTypes,
make_foreign_args(Vars, ArgInfos, OrigArgTypes, Args).
:- pred foreign_proc_add_typeclass_info(bool::in, mer_mode::in,
pragma_foreign_code_impl::in, tvarset::in, prog_constraint::in,
pair(maybe(pair(string, mer_mode)), box_policy)::out) is det.
foreign_proc_add_typeclass_info(CanOptAwayUnnamed, Mode, Impl, TypeVarSet,
Constraint, MaybeArgName - native_if_possible) :-
Constraint = constraint(SymName, Types),
Name = sym_name_to_string_sep(SymName, "__"),
type_vars_list(Types, TypeVars),
TypeVarNames = list.map(underscore_and_tvar_name(TypeVarSet), TypeVars),
string.append_list(["TypeClassInfo_for_", Name | TypeVarNames],
ConstraintVarName),
% If the variable name corresponding to the typeclass_info isn't mentioned
% in the C code fragment, don't pass the variable to the C code at all.
(
CanOptAwayUnnamed = yes,
foreign_code_does_not_use_variable(Impl, ConstraintVarName)
->
MaybeArgName = no
;
MaybeArgName = yes(ConstraintVarName - Mode)
).
:- pred foreign_proc_add_typeinfo(bool::in, mer_mode::in,
pragma_foreign_code_impl::in, tvarset::in, tvar::in,
pair(maybe(pair(string, mer_mode)), box_policy)::out) is det.
foreign_proc_add_typeinfo(CanOptAwayUnnamed, Mode, Impl, TypeVarSet, TVar,
MaybeArgName - native_if_possible) :-
( varset.search_name(TypeVarSet, TVar, TypeVarName) ->
C_VarName = "TypeInfo_for_" ++ TypeVarName,
% If the variable name corresponding to the type_info isn't mentioned
% in the C code fragment, don't pass the variable to the C code at all.
(
CanOptAwayUnnamed = yes,
foreign_code_does_not_use_variable(Impl, C_VarName)
->
MaybeArgName = no
;
MaybeArgName = yes(C_VarName - Mode)
)
;
MaybeArgName = no
).
:- pred foreign_code_does_not_use_variable(pragma_foreign_code_impl::in,
string::in) is semidet.
foreign_code_does_not_use_variable(Impl, VarName) :-
% XXX This test used to be turned off with the semidet_fail, as it caused
% the compiler to abort when compiling declarative_execution.m in stage2,
% but this is no longer the case.
% semidet_fail,
\+ foreign_code_uses_variable(Impl, VarName).
:- func underscore_and_tvar_name(tvarset, tvar) = string.
underscore_and_tvar_name(TypeVarSet, TVar) = TVarName :-
varset.lookup_name(TypeVarSet, TVar, TVarName0),
TVarName = "_" ++ TVarName0.
:- pred polymorphism_process_plain_conj(list(hlds_goal)::in,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
polymorphism_process_plain_conj([], [], !Info).
polymorphism_process_plain_conj([Goal0 | Goals0], [Goal | Goals], !Info) :-
polymorphism_process_goal(Goal0, Goal, !Info),
polymorphism_process_plain_conj(Goals0, Goals, !Info).
:- pred polymorphism_process_par_conj(list(hlds_goal)::in,
list(hlds_goal)::out, cache_maps::in, poly_info::in, poly_info::out)
is det.
polymorphism_process_par_conj([], [], _, !Info).
polymorphism_process_par_conj([Goal0 | Goals0], [Goal | Goals],
InitialSnapshot, !Info) :-
% Any variable that a later parallel conjunct reuses from an earlier
% parallel conjunct (a) will definitely require synchronization, whose
% cost will be greater than the cost of building a typeinfo from scratch,
% and (b) may drastically reduce the available parallelism, if the earlier
% conjunct produces the variable late but the later conjunct requires it
% early.
set_cache_maps_snapshot("par conjunct", InitialSnapshot, !Info),
polymorphism_process_goal(Goal0, Goal, !Info),
polymorphism_process_par_conj(Goals0, Goals, InitialSnapshot, !Info).
:- pred polymorphism_process_disj(list(hlds_goal)::in, list(hlds_goal)::out,
cache_maps::in, poly_info::in, poly_info::out) is det.
polymorphism_process_disj([], [], _, !Info).
polymorphism_process_disj([Goal0 | Goals0], [Goal | Goals], InitialSnapshot,
!Info) :-
set_cache_maps_snapshot("disjunct", InitialSnapshot, !Info),
polymorphism_process_goal(Goal0, Goal, !Info),
polymorphism_process_disj(Goals0, Goals, InitialSnapshot, !Info).
:- pred polymorphism_process_cases(list(case)::in, list(case)::out,
cache_maps::in, poly_info::in, poly_info::out) is det.
polymorphism_process_cases([], [], _, !Info).
polymorphism_process_cases([Case0 | Cases0], [Case | Cases], InitialSnapshot,
!Info) :-
Case0 = case(MainConsId, OtherConsIds, Goal0),
set_cache_maps_snapshot("case", InitialSnapshot, !Info),
polymorphism_process_goal(Goal0, Goal, !Info),
Case = case(MainConsId, OtherConsIds, Goal),
polymorphism_process_cases(Cases0, Cases, InitialSnapshot, !Info).
%-----------------------------------------------------------------------------%
% XXX document me
%
% XXX the following code ought to be rewritten to handle
% existential/universal type_infos and type_class_infos
% in a more consistent manner.
%
:- pred polymorphism_process_call(pred_id::in, list(prog_var)::in,
hlds_goal_info::in, hlds_goal_info::out,
list(prog_var)::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
polymorphism_process_call(PredId, ArgVars0, GoalInfo0, GoalInfo,
ExtraVars, ExtraGoals, !Info) :-
poly_info_get_var_types(!.Info, VarTypes),
poly_info_get_typevarset(!.Info, TypeVarSet0),
poly_info_get_module_info(!.Info, ModuleInfo),
% The order of the added variables is important, and must match the
% order specified at the top of this file.
module_info_pred_info(ModuleInfo, PredId, PredInfo),
pred_info_get_arg_types(PredInfo, PredTypeVarSet, PredExistQVars,
PredArgTypes),
pred_info_get_tvar_kinds(PredInfo, PredKindMap),
pred_info_get_class_context(PredInfo, PredClassContext),
% VarTypes, TypeVarSet* etc come from the caller.
% PredTypeVarSet, PredArgTypes, PredExistQVars, etc come
% directly from the callee.
% ParentArgTypes, ParentExistQVars etc come from a version
% of the callee that has been renamed apart from the caller.
%
% The difference between e.g. PredArgTypes and ParentArgTypes is the
% application of PredToParentTypeRenaming, which maps the type variables
% in the callee to new type variables in the caller. Adding the new type
% variables to TypeVarSet0 yields TypeVarSet.
( varset.is_empty(PredTypeVarSet) ->
% Optimize a common case.
map.init(PredToParentTypeRenaming),
TypeVarSet = TypeVarSet0,
ParentArgTypes = PredArgTypes,
ParentKindMap = PredKindMap,
ParentTVars = [],
ParentExistQVars = []
;
% This merge might be a performance bottleneck?
tvarset_merge_renaming(TypeVarSet0, PredTypeVarSet, TypeVarSet,
PredToParentTypeRenaming),
apply_variable_renaming_to_type_list(PredToParentTypeRenaming,
PredArgTypes, ParentArgTypes),
type_vars_list(ParentArgTypes, ParentTVars),
apply_variable_renaming_to_tvar_kind_map(PredToParentTypeRenaming,
PredKindMap, ParentKindMap),
apply_variable_renaming_to_tvar_list(PredToParentTypeRenaming,
PredExistQVars, ParentExistQVars)
),
PredModule = pred_info_module(PredInfo),
PredName = pred_info_name(PredInfo),
PredArity = pred_info_orig_arity(PredInfo),
(
(
% Optimize for the common case of nonpolymorphic call
% with no constraints.
ParentTVars = [],
PredClassContext = constraints([], [])
;
% Some builtins don't need or want the type_info.
no_type_info_builtin(PredModule, PredName, PredArity)
)
->
GoalInfo = GoalInfo0,
ExtraGoals = [],
ExtraVars = []
;
poly_info_set_typevarset(TypeVarSet, !Info),
% Compute which "parent" type variables are constrained
% by the type class constraints.
apply_variable_renaming_to_prog_constraints(PredToParentTypeRenaming,
PredClassContext, ParentClassContext),
ParentClassContext = constraints(ParentUnivConstraints,
ParentExistConstraints),
constraint_list_get_tvars(ParentUnivConstraints,
ParentUnivConstrainedTVars),
constraint_list_get_tvars(ParentExistConstraints,
ParentExistConstrainedTVars),
% Calculate the set of unconstrained type vars. Split these into
% existential and universal type vars.
list.remove_dups(ParentTVars, ParentUnconstrainedTVars0),
list.delete_elems(ParentUnconstrainedTVars0,
ParentUnivConstrainedTVars, ParentUnconstrainedTVars1),
list.delete_elems(ParentUnconstrainedTVars1,
ParentExistConstrainedTVars, ParentUnconstrainedTVars),
list.delete_elems(ParentUnconstrainedTVars, ParentExistQVars,
ParentUnconstrainedUnivTVars),
list.delete_elems(ParentUnconstrainedTVars,
ParentUnconstrainedUnivTVars, ParentUnconstrainedExistTVars),
% Calculate the "parent to actual" binding.
lookup_var_types(VarTypes, ArgVars0, ActualArgTypes),
type_list_subsumes_det(ParentArgTypes, ActualArgTypes,
ParentToActualTypeSubst),
% Make the universally quantified typeclass_infos for the call.
poly_info_get_constraint_map(!.Info, ConstraintMap),
GoalId = goal_info_get_goal_id(GoalInfo0),
list.length(ParentUnivConstraints, NumUnivConstraints),
lookup_hlds_constraint_list(ConstraintMap, unproven, GoalId,
NumUnivConstraints, ActualUnivConstraints),
apply_rec_subst_to_tvar_list(ParentKindMap, ParentToActualTypeSubst,
ParentExistQVars, ActualExistQVarTypes),
(
prog_type.type_list_to_var_list(ActualExistQVarTypes,
ActualExistQVars0)
->
ActualExistQVars = ActualExistQVars0
;
unexpected($module, $pred, "existq_tvar bound")
),
Context = goal_info_get_context(GoalInfo0),
make_typeclass_info_vars(ActualUnivConstraints, ActualExistQVars,
Context, ExtraUnivClassVarsMCAs, ExtraUnivClassGoals,
!Info),
assoc_list.keys(ExtraUnivClassVarsMCAs, ExtraUnivClassVars),
% Make variables to hold any existentially quantified typeclass_infos
% in the call, insert them into the typeclass_info map.
list.length(ParentExistConstraints, NumExistConstraints),
lookup_hlds_constraint_list(ConstraintMap, assumed, GoalId,
NumExistConstraints, ActualExistConstraints),
make_existq_typeclass_info_vars(ActualExistConstraints,
ExtraExistClassVars, ExtraExistClassGoals, !Info),
% Make variables to hold typeinfos for unconstrained universal type
% vars.
apply_rec_subst_to_tvar_list(ParentKindMap, ParentToActualTypeSubst,
ParentUnconstrainedUnivTVars, ActualUnconstrainedUnivTypes),
polymorphism_do_make_type_info_vars(ActualUnconstrainedUnivTypes,
Context, ExtraUnivTypeInfoVarsMCAs,
ExtraUnivTypeInfoGoals, !Info),
assoc_list.keys(ExtraUnivTypeInfoVarsMCAs,
ExtraUnivTypeInfoVars),
% Make variables to hold typeinfos for unconstrained existential type
% vars.
apply_rec_subst_to_tvar_list(ParentKindMap, ParentToActualTypeSubst,
ParentUnconstrainedExistTVars, ActualUnconstrainedExistTypes),
polymorphism_do_make_type_info_vars(ActualUnconstrainedExistTypes,
Context, ExtraExistTypeInfoVarsMCAs,
ExtraExistTypeInfoGoals, !Info),
assoc_list.keys(ExtraExistTypeInfoVarsMCAs,
ExtraExistTypeInfoVars),
% Add up the extra vars and goals.
ExtraGoals = ExtraUnivClassGoals ++ ExtraExistClassGoals
++ ExtraUnivTypeInfoGoals ++ ExtraExistTypeInfoGoals,
ExtraVars = ExtraUnivTypeInfoVars ++ ExtraExistTypeInfoVars
++ ExtraUnivClassVars ++ ExtraExistClassVars,
% Update the nonlocals.
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
set_of_var.insert_list(ExtraVars, NonLocals0, NonLocals),
goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo)
).
%-----------------------------------------------------------------------------%
polymorphism_process_new_call(CalleePredInfo, CalleeProcInfo, PredId, ProcId,
CallArgs0, BuiltinState, MaybeCallUnifyContext, SymName,
GoalInfo0, Goal, !Info) :-
% document me better
%
poly_info_get_typevarset(!.Info, TVarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
lookup_var_types(VarTypes0, CallArgs0, ActualArgTypes0),
pred_info_get_arg_types(CalleePredInfo, PredTVarSet, _PredExistQVars,
PredArgTypes),
proc_info_get_headvars(CalleeProcInfo, CalleeHeadVars),
proc_info_get_rtti_varmaps(CalleeProcInfo, CalleeRttiVarMaps),
% Work out how many type_info args we need to prepend.
NCallArgs0 = list.length(ActualArgTypes0),
NPredArgs = list.length(PredArgTypes),
NExtraArgs = NPredArgs - NCallArgs0,
(
list.drop(NExtraArgs, PredArgTypes, OrigPredArgTypes0),
list.take(NExtraArgs, CalleeHeadVars, CalleeExtraHeadVars0)
->
OrigPredArgTypes = OrigPredArgTypes0,
CalleeExtraHeadVars = CalleeExtraHeadVars0
;
unexpected($module, $pred, "extra args not found")
),
% Work out the bindings of type variables in the call.
tvarset_merge_renaming(TVarSet0, PredTVarSet, TVarSet,
PredToParentRenaming),
apply_variable_renaming_to_type_list(PredToParentRenaming,
OrigPredArgTypes, OrigParentArgTypes),
type_list_subsumes_det(OrigParentArgTypes, ActualArgTypes0,
ParentToActualTSubst),
poly_info_set_typevarset(TVarSet, !Info),
% Look up the type variables that the type_infos in the caller are for,
% and apply the type bindings to calculate the types that the caller
% should pass type_infos for.
GetTypeInfoTypes = (pred(ProgVar::in, TypeInfoType::out) is det :-
rtti_varmaps_var_info(CalleeRttiVarMaps, ProgVar, VarInfo),
(
VarInfo = type_info_var(TypeInfoType)
;
VarInfo = typeclass_info_var(_),
unexpected($module, $pred,
"unsupported: constraints on initialisation preds")
;
VarInfo = non_rtti_var,
unexpected($module, $pred,
"missing rtti_var_info for initialisation pred")
)
),
list.map(GetTypeInfoTypes, CalleeExtraHeadVars, PredTypeInfoTypes),
apply_variable_renaming_to_type_list(PredToParentRenaming,
PredTypeInfoTypes, ParentTypeInfoTypes),
apply_rec_subst_to_type_list(ParentToActualTSubst, ParentTypeInfoTypes,
ActualTypeInfoTypes),
% Construct goals to make the required type_infos.
Ctxt = term.context_init,
polymorphism_do_make_type_info_vars(ActualTypeInfoTypes, Ctxt,
ExtraArgsConstArgs, ExtraGoals, !Info),
assoc_list.keys(ExtraArgsConstArgs, ExtraArgs),
CallArgs = ExtraArgs ++ CallArgs0,
NonLocals0 = goal_info_get_nonlocals(GoalInfo0),
NonLocals1 = set_of_var.list_to_set(ExtraArgs),
set_of_var.union(NonLocals0, NonLocals1, NonLocals),
goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo),
CallGoalExpr = plain_call(PredId, ProcId, CallArgs, BuiltinState,
MaybeCallUnifyContext, SymName),
CallGoal = hlds_goal(CallGoalExpr, GoalInfo),
conj_list_to_goal(ExtraGoals ++ [CallGoal], GoalInfo, Goal).
%-----------------------------------------------------------------------------%
% If the pred we are processing is a polymorphic predicate, or contains
% polymorphically-typed goals, we may need to fix up the quantification
% (nonlocal variables) of the goal so that it includes the extra type_info
% variables and typeclass_info variables that we added to the headvars
% or the arguments of existentially typed predicate calls, function calls
% and deconstruction unifications.
%
% Type(class)-infos added for ground types passed to predicate calls,
% function calls and existentially typed construction unifications
% do not require requantification because they are local to the conjunction
% containing the type(class)-info construction and the goal which uses the
% type(class)-info. The nonlocals for those goals are adjusted by
% the code which creates/alters them. However, reusing a type_info changes
% it from being local to nonlocal.
%
:- pred fixup_quantification(proc_arg_vector(prog_var)::in,
existq_tvars::in, hlds_goal::in, hlds_goal::out,
poly_info::in, poly_info::out) is det.
fixup_quantification(HeadVars, ExistQVars, Goal0, Goal, !Info) :-
(
% Optimize common case.
ExistQVars = [],
rtti_varmaps_no_tvars(!.Info ^ poly_rtti_varmaps),
poly_info_get_num_reuses(!.Info, NumReuses),
NumReuses = 0
->
Goal = Goal0
;
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
OutsideVars = proc_arg_vector_to_set(HeadVars),
implicitly_quantify_goal_general(ordinary_nonlocals_maybe_lambda,
set_to_bitset(OutsideVars), _Warnings, Goal0, Goal,
VarSet0, VarSet, VarTypes0, VarTypes, RttiVarMaps0, RttiVarMaps),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info)
).
% If the lambda goal we are processing is polymorphically typed, we may
% need to fix up the quantification (nonlocal variables) so that it
% includes the type_info variables and typeclass_info variables for
% any polymorphically typed variables in the nonlocals set or in the
% arguments (either the lambda vars or the implicit curried argument
% variables). Including typeinfos for arguments which are not in the
% nonlocals set of the goal, i.e. unused arguments, is necessary only
% if typeinfo_liveness is set, but we do it always, since we don't have
% the options available here, and the since cost is pretty minimal.
%
:- pred fixup_lambda_quantification(list(prog_var)::in,
list(prog_var)::in, existq_tvars::in, hlds_goal::in, hlds_goal::out,
set_of_progvar::out, poly_info::in, poly_info::out) is det.
fixup_lambda_quantification(ArgVars, LambdaVars, ExistQVars, !Goal,
NewOutsideVars, !Info) :-
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
( rtti_varmaps_no_tvars(RttiVarMaps0) ->
set_of_var.init(NewOutsideVars)
;
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
!.Goal = hlds_goal(_, GoalInfo0),
NonLocals = goal_info_get_nonlocals(GoalInfo0),
set_of_var.insert_list(ArgVars, NonLocals, NonLocalsPlusArgs0),
set_of_var.insert_list(LambdaVars,
NonLocalsPlusArgs0, NonLocalsPlusArgs),
goal_util.extra_nonlocal_typeinfos(RttiVarMaps0, VarTypes0,
ExistQVars, NonLocalsPlusArgs, NewOutsideVars),
set_of_var.union(NonLocals, NewOutsideVars, OutsideVars),
implicitly_quantify_goal_general(ordinary_nonlocals_maybe_lambda,
OutsideVars, _Warnings, !Goal,
VarSet0, VarSet, VarTypes0, VarTypes, RttiVarMaps0, RttiVarMaps),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info)
).
%-----------------------------------------------------------------------------%
% Given the list of constraints for a called predicate, create a list of
% variables to hold the typeclass_info for those constraints, and create
% a list of goals to initialize those typeclass_info variables to the
% appropriate typeclass_info structures for the constraints.
%
% Constraints should be renamed-apart and actual-to-formal substituted
% constraints. Constraints which are already in the rtti_varmaps are
% assumed to have already had their typeclass_infos initialized; for them,
% we just return the variable in the rtti_varmaps.
%
:- pred make_typeclass_info_vars(list(prog_constraint)::in,
existq_tvars::in, prog_context::in,
assoc_list(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
make_typeclass_info_vars(Constraints, ExistQVars, Context,
TypeClassInfoVarsMCAs, ExtraGoals, !Info) :-
SeenInstances = [],
make_typeclass_info_vars_2(Constraints, SeenInstances, ExistQVars, Context,
TypeClassInfoVarsMCAs, ExtraGoals, !Info).
% Accumulator version of the above.
%
:- pred make_typeclass_info_vars_2(list(prog_constraint)::in,
list(prog_constraint)::in, existq_tvars::in, prog_context::in,
assoc_list(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
make_typeclass_info_vars_2([], _Seen, _ExistQVars, _Context,
[], [], !Info).
make_typeclass_info_vars_2([Constraint | Constraints], Seen, ExistQVars,
Context, [TypeClassInfoVarMCA | TypeClassInfoVarsMCAs],
ExtraGoals, !Info) :-
make_typeclass_info_var(Constraint, [Constraint | Seen],
ExistQVars, Context, TypeClassInfoVarMCA, HeadExtraGoals, !Info),
make_typeclass_info_vars_2(Constraints, Seen, ExistQVars,
Context, TypeClassInfoVarsMCAs, TailExtraGoals, !Info),
ExtraGoals = HeadExtraGoals ++ TailExtraGoals.
:- pred make_typeclass_info_var(prog_constraint::in,
list(prog_constraint)::in, existq_tvars::in, prog_context::in,
pair(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
make_typeclass_info_var(Constraint, Seen, ExistQVars, Context,
TypeClassInfoVarMCA, Goals, !Info) :-
(
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
rtti_search_typeclass_info_var(RttiVarMaps0, Constraint,
OldTypeClassInfoVar)
->
% We already have a typeclass_info for this constraint, either from
% a parameter to the pred or from an existentially quantified goal
% that we have already processed.
TypeClassInfoVar = OldTypeClassInfoVar,
TypeClassInfoVarMCA = TypeClassInfoVar - no,
Goals = []
;
% We don't have the typeclass_info, so we must either have a proof
% that tells us how to make it, or ...
map.search(!.Info ^ poly_proof_map, Constraint, Proof)
->
make_typeclass_info_from_proof(Constraint, Seen, Proof, ExistQVars,
Context, TypeClassInfoVarMCA, Goals, !Info)
;
% ... it will be produced by an existentially typed goal that
% we will process later on.
make_typeclass_info_head_var(do_record_type_info_locns, Constraint,
TypeClassInfoVar, !Info),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
rtti_reuse_typeclass_info_var(TypeClassInfoVar,
RttiVarMaps0, RttiVarMaps),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info),
TypeClassInfoVarMCA = TypeClassInfoVar - no,
Goals = []
).
:- pred make_typeclass_info_from_proof(prog_constraint::in,
list(prog_constraint)::in, constraint_proof::in, existq_tvars::in,
prog_context::in, pair(prog_var, maybe(const_struct_arg))::out,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
make_typeclass_info_from_proof(Constraint, Seen, Proof,
ExistQVars, Context, TypeClassInfoVarMCA, Goals, !Info) :-
(
% XXX MR_Dictionary should have MR_Dictionaries for superclass
% We have to extract the typeclass_info from another one.
Proof = superclass(SubClassConstraint),
make_typeclass_info_from_subclass(Constraint, Seen, SubClassConstraint,
ExistQVars, Context, TypeClassInfoVarMCA, Goals, !Info)
;
% We have to construct the typeclass_info using an instance
% declaration.
Proof = apply_instance(InstanceNum),
make_typeclass_info_from_instance(Constraint, Seen, InstanceNum,
ExistQVars, Context, TypeClassInfoVarMCA, Goals, !Info)
).
:- pred make_typeclass_info_from_subclass(prog_constraint::in,
list(prog_constraint)::in, prog_constraint::in, existq_tvars::in,
prog_context::in, pair(prog_var, maybe(const_struct_arg))::out,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
make_typeclass_info_from_subclass(Constraint, Seen, SubClassConstraint,
ExistQVars, Context, TypeClassInfoVar - MaybeTCIConstArg, Goals,
!Info) :-
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', Level * 4),
impure set_level(Level + 1),
io.write_string(IndentStr, !IO),
io.write_string("make_typeclass_info_from_subclass", !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("Constraint: ", !IO),
io.write(Constraint, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("Seen: ", !IO),
( Seen = [Constraint] ->
io.write_string("[Constraint]\n", !IO)
;
io.write(Seen, !IO),
io.nl(!IO)
),
io.write_string(IndentStr, !IO),
io.write_string("SubClassConstraint: ", !IO),
io.write(SubClassConstraint, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("ExistQVars: ", !IO),
io.write(ExistQVars, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
),
% Work out where to extract the typeclass info from.
SubClassConstraint = constraint(SubClassName, SubClassTypes),
list.length(SubClassTypes, SubClassArity),
SubClassId = class_id(SubClassName, SubClassArity),
% Make the typeclass_info for the subclass.
make_typeclass_info_var(SubClassConstraint, Seen, ExistQVars, Context,
SubClassVarMCA, SubClassVarGoals, !Info),
SubClassVarMCA = SubClassVar - SubClassMCA,
% Look up the definition of the subclass.
poly_info_get_module_info(!.Info, ModuleInfo),
module_info_get_class_table(ModuleInfo, ClassTable),
map.lookup(ClassTable, SubClassId, SubClassDefn),
% Work out which superclass typeclass_info to take.
map.from_corresponding_lists(SubClassDefn ^ class_vars, SubClassTypes,
SubTypeSubst),
apply_subst_to_prog_constraint_list(SubTypeSubst,
SubClassDefn ^ class_supers, SuperClasses),
( list.nth_member_search(SuperClasses, Constraint, SuperClassIndex0) ->
SuperClassIndex0 = SuperClassIndex
;
% We shouldn't have got this far if the constraints were not satisfied.
unexpected($module, $pred, "constraint not in constraint list")
),
(
SubClassMCA = yes(SubClassConstArg),
(
SubClassConstArg = csa_constant(_, _),
unexpected($module, $pred, "typeclass infos need a cell")
;
SubClassConstArg = csa_const_struct(SubClassConstNum),
poly_info_get_const_struct_db(!.Info, ConstStructDb),
lookup_const_struct_num(ConstStructDb, SubClassConstNum,
SubClassConstStruct),
SubClassConstStruct = const_struct(SubClassConsId, SubClassArgs,
_, _),
(
SubClassConsId = typeclass_info_cell_constructor,
SubClassArgs = [BTCIArg | OtherArgs],
BTCIArg = csa_constant(BTCIConsId, _),
BTCIConsId = base_typeclass_info_const(_, SubClassId,
SubInstanceNum, _),
module_info_get_instance_table(ModuleInfo, InstanceTable),
map.lookup(InstanceTable, SubClassId, SubInstanceDefns),
list.index1(SubInstanceDefns, SubInstanceNum, SubInstanceDefn),
num_extra_instance_args(SubInstanceDefn, NumExtra),
Index = NumExtra + SuperClassIndex,
list.det_index1(OtherArgs, Index, SelectedArg),
SelectedArg = csa_const_struct(SelectedConstNum)
->
materialize_typeclass_info_var(Constraint, SelectedConstNum,
TypeClassInfoVar, Goals, !Info),
MaybeTCIConstArg = yes(SelectedArg)
;
unexpected($module, $pred,
"unexpected typeclass info structure")
)
),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr, ResultStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
impure set_level(Level - 1),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', (Level-1) * 4),
io.write_string(IndentStr, !IO),
io.write_string("subclass constant result ", !IO),
io.write(TypeClassInfoVar - MaybeTCIConstArg, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
)
;
SubClassMCA = no,
new_typeclass_info_var(Constraint, typeclass_info_kind,
TypeClassInfoVar, _TypeClassInfoVarType, !Info),
get_poly_const(SuperClassIndex, IndexVar, IndexGoals, !Info),
% We extract the superclass typeclass_info by inserting a call
% to superclass_from_typeclass_info in private_builtin.
goal_util.generate_simple_call(mercury_private_builtin_module,
"superclass_from_typeclass_info",
pf_predicate, only_mode, detism_det, purity_pure,
[SubClassVar, IndexVar, TypeClassInfoVar], [],
instmap_delta_bind_no_var, ModuleInfo, term.context_init,
SuperClassGoal),
Goals = SubClassVarGoals ++ IndexGoals ++ [SuperClassGoal],
MaybeTCIConstArg = no,
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr, ResultStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
impure set_level(Level - 1),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', (Level-1) * 4),
io.write_string(IndentStr, !IO),
io.write_string("subclass computed result ", !IO),
io.write(TypeClassInfoVar - MaybeTCIConstArg, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
)
).
:- pred make_typeclass_info_from_instance(prog_constraint::in,
list(prog_constraint)::in, int::in, existq_tvars::in, prog_context::in,
pair(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
make_typeclass_info_from_instance(Constraint, Seen, InstanceNum, ExistQVars,
Context, TypeClassInfoVarMCA, Goals, !Info) :-
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', Level * 4),
impure set_level(Level + 1),
io.write_string(IndentStr, !IO),
io.write_string("make_typeclass_info_from_instance", !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("Constraint: ", !IO),
io.write(Constraint, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("Seen: ", !IO),
( Seen = [Constraint] ->
io.write_string("[Constraint]\n", !IO)
;
io.write(Seen, !IO),
io.nl(!IO)
),
io.write_string(IndentStr, !IO),
io.write_string("InstanceNum: ", !IO),
io.write(InstanceNum, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("ExistQVars: ", !IO),
io.write(ExistQVars, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
),
poly_info_get_const_struct_db(!.Info, ConstStructDb0),
InstanceId = ciid(InstanceNum, Constraint, Seen),
(
ExistQVars = [],
search_for_constant_instance(ConstStructDb0, InstanceId,
InstanceIdConstNum)
->
materialize_typeclass_info_var(Constraint, InstanceIdConstNum,
TypeClassInfoVar, Goals, !Info),
TypeClassInfoVarMCA =
TypeClassInfoVar - yes(csa_const_struct(InstanceIdConstNum)),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr, ResultStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
impure set_level(Level - 1),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', (Level-1) * 4),
(
Goals = [],
ResultStr = "instance doubly cached result "
;
Goals = [_ | _],
ResultStr = "instance cached result "
),
io.write_string(IndentStr, !IO),
io.write_string(ResultStr, !IO),
io.write(TypeClassInfoVarMCA, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
)
;
do_make_typeclass_info_from_instance(InstanceId, ExistQVars,
Context, TypeClassInfoVarMCA, Goals, !Info),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
impure set_level(Level - 1),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', (Level-1) * 4),
io.write_string(IndentStr, !IO),
io.write_string("instance computed result: ", !IO),
io.write(TypeClassInfoVarMCA, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("type_info_var_map ", !IO),
io.write(!.Info ^ poly_type_info_var_map, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("typeclass_info_map ", !IO),
io.write(!.Info ^ poly_typeclass_info_map, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("struct_var_map ", !IO),
io.write(!.Info ^ poly_const_struct_var_map, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
)
).
:- pred do_make_typeclass_info_from_instance(const_instance_id::in,
existq_tvars::in, prog_context::in,
pair(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
do_make_typeclass_info_from_instance(InstanceId, ExistQVars, Context,
TypeClassInfoVarMCA, Goals, !Info) :-
poly_info_get_module_info(!.Info, ModuleInfo),
module_info_get_instance_table(ModuleInfo, InstanceTable),
module_info_get_class_table(ModuleInfo, ClassTable),
poly_info_get_typevarset(!.Info, TypeVarSet),
poly_info_get_proofs(!.Info, Proofs0),
InstanceId = ciid(InstanceNum, Constraint, Seen),
Constraint = constraint(ClassName, ConstrainedTypes),
list.length(ConstrainedTypes, ClassArity),
ClassId = class_id(ClassName, ClassArity),
map.lookup(InstanceTable, ClassId, InstanceList),
list.det_index1(InstanceList, InstanceNum, ProofInstanceDefn),
ProofInstanceDefn = hlds_instance_defn(_, _, _, InstanceConstraints,
InstanceTypes, _, _, _, InstanceTVarset, InstanceProofs),
% XXX kind inference:
% we assume all tvars have kind `star'.
map.init(KindMap),
type_vars_list(InstanceTypes, InstanceTvars),
get_unconstrained_tvars(InstanceTvars, InstanceConstraints,
UnconstrainedTvars),
% We can ignore the new typevarset because all the type variables
% in the instance constraints and superclass proofs must appear
% in the arguments of the instance, and all such variables
% are bound when we call type_list_subsumes then apply
% the resulting bindings.
tvarset_merge_renaming(TypeVarSet, InstanceTVarset, _NewTVarset, Renaming),
apply_variable_renaming_to_type_list(Renaming, InstanceTypes,
RenamedInstanceTypes),
type_list_subsumes_det(RenamedInstanceTypes, ConstrainedTypes,
InstanceSubst),
apply_variable_renaming_to_prog_constraint_list(Renaming,
InstanceConstraints, RenamedInstanceConstraints),
apply_rec_subst_to_prog_constraint_list(InstanceSubst,
RenamedInstanceConstraints, ActualInstanceConstraints0),
% XXX document diamond as guess
% XXX does anyone know what the preceding line means?
list.delete_elems(ActualInstanceConstraints0, Seen,
ActualInstanceConstraints),
apply_variable_renaming_to_constraint_proofs(Renaming,
InstanceProofs, RenamedInstanceProofs),
apply_rec_subst_to_constraint_proofs(InstanceSubst,
RenamedInstanceProofs, ActualInstanceProofs),
apply_variable_renaming_to_tvar_list(Renaming, UnconstrainedTvars,
RenamedUnconstrainedTvars),
apply_variable_renaming_to_tvar_kind_map(Renaming, KindMap,
RenamedKindMap),
apply_rec_subst_to_tvar_list(RenamedKindMap, InstanceSubst,
RenamedUnconstrainedTvars, ActualUnconstrainedTypes),
map.overlay(Proofs0, ActualInstanceProofs, Proofs),
get_var_maps_snapshot("make_typeclass_info_from_instance",
InitialVarMapsSnapshot, !Info),
% Make the type_infos for the types that are constrained by this.
% These are packaged in the typeclass_info.
polymorphism_do_make_type_info_vars(ConstrainedTypes, Context,
ArgTypeInfoVarsMCAs, TypeInfoGoals, !Info),
% Make the typeclass_infos for the constraints from the context of the
% instance decl.
make_typeclass_info_vars_2(ActualInstanceConstraints, Seen, ExistQVars,
Context, ArgTypeClassInfoVarsMCAs, InstanceConstraintGoals, !Info),
% Make the type_infos for the unconstrained type variables
% from the head of the instance declaration.
polymorphism_do_make_type_info_vars(ActualUnconstrainedTypes, Context,
ArgUnconstrainedTypeInfoVarsMCAs, UnconstrainedTypeInfoGoals, !Info),
% --------------------- %
map.lookup(ClassTable, ClassId, ClassDefn),
get_arg_superclass_vars(ClassDefn, ConstrainedTypes, Proofs,
ExistQVars, ArgSuperClassVarsMCAs, SuperClassGoals, !Info),
PrevGoals = UnconstrainedTypeInfoGoals ++ TypeInfoGoals ++
InstanceConstraintGoals ++ SuperClassGoals,
% Lay out the argument variables as expected in the typeclass_info.
ArgVarsMCAs = ArgUnconstrainedTypeInfoVarsMCAs ++
ArgTypeClassInfoVarsMCAs ++
ArgSuperClassVarsMCAs ++ ArgTypeInfoVarsMCAs,
list.map(make_const_or_var_arg, ArgVarsMCAs, ArgCOVAs),
Constraint = constraint(ConstraintClassName, ConstraintArgTypes),
poly_info_get_typeclass_info_map(!.Info, TypeClassInfoMap0),
(
map.search(TypeClassInfoMap0, ConstraintClassName, ClassNameMap0),
map.search(ClassNameMap0, ConstraintArgTypes, OldEntry0),
OldEntry0 = typeclass_info_map_entry(_BaseConsId, ArgsMap0),
map.search(ArgsMap0, ArgCOVAs, OldTypeClassInfoVarMCA0)
->
TypeClassInfoVarMCA = OldTypeClassInfoVarMCA0,
Goals = [],
set_var_maps_snapshot("make_typeclass_info",
InitialVarMapsSnapshot, !Info),
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 2, !Info)
;
BaseConsId = base_typeclass_info_cons_id(InstanceTable,
Constraint, InstanceNum, InstanceTypes),
materialize_base_typeclass_info_var(Constraint, BaseConsId, BaseVar,
BaseGoals, !Info),
construct_typeclass_info(Constraint, BaseVar, BaseConsId, ArgVarsMCAs,
InitialVarMapsSnapshot, TypeClassInfoVar, TypeClassInfoMCA,
BaseGoals ++ PrevGoals, Goals, !Info),
TypeClassInfoVarMCA = TypeClassInfoVar - TypeClassInfoMCA,
% We must start the search from scratch, since construct_typeclass_info
% may have reset all the cache maps.
poly_info_get_typeclass_info_map(!.Info, TypeClassInfoMap1),
( map.search(TypeClassInfoMap1, ConstraintClassName, ClassNameMap1) ->
( map.search(ClassNameMap1, ConstraintArgTypes, OldEntry1) ->
OldEntry1 = typeclass_info_map_entry(BaseConsId1, ArgsMap1),
expect(unify(BaseConsId1, BaseConsId), $module, $pred,
"BaseConsId1 != BaseConsId"),
map.det_insert(ArgCOVAs, TypeClassInfoVarMCA,
ArgsMap1, ArgsMap),
Entry = typeclass_info_map_entry(BaseConsId, ArgsMap),
map.det_update(ConstraintArgTypes, Entry,
ClassNameMap1, ClassNameMap),
map.det_update(ConstraintClassName, ClassNameMap,
TypeClassInfoMap1, TypeClassInfoMap)
;
ArgsMap = map.singleton(ArgCOVAs, TypeClassInfoVarMCA),
Entry = typeclass_info_map_entry(BaseConsId, ArgsMap),
map.det_insert(ConstraintArgTypes, Entry,
ClassNameMap1, ClassNameMap),
map.det_update(ConstraintClassName, ClassNameMap,
TypeClassInfoMap1, TypeClassInfoMap)
)
;
ArgsMap = map.singleton(ArgCOVAs, TypeClassInfoVarMCA),
Entry = typeclass_info_map_entry(BaseConsId, ArgsMap),
ClassNameMap = map.singleton(ConstraintArgTypes, Entry),
map.det_insert(ConstraintClassName, ClassNameMap,
TypeClassInfoMap1, TypeClassInfoMap)
),
poly_info_set_typeclass_info_map(TypeClassInfoMap, !Info)
),
(
TypeClassInfoVarMCA = _ - yes(TypeClassInfoConstArg),
TypeClassInfoConstArg = csa_const_struct(TypeClassInfoConstArgNum)
->
poly_info_get_const_struct_db(!.Info, ConstStructDb1),
insert_constant_instance(InstanceId, TypeClassInfoConstArgNum,
ConstStructDb1, ConstStructDb),
poly_info_set_const_struct_db(ConstStructDb, !Info)
;
true
).
:- pred construct_typeclass_info(prog_constraint::in,
prog_var::in, cons_id::in,
assoc_list(prog_var, maybe(const_struct_arg))::in, var_maps::in,
prog_var::out, maybe(const_struct_arg)::out,
list(hlds_goal)::in, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
construct_typeclass_info(Constraint, BaseVar, BaseConsId, ArgVarsMCAs,
InitialVarMapsSnapshot, TypeClassInfoVar, TypeClassInfoMCA,
PrevGoals, AllGoals, !Info) :-
% Build a unification to add the argvars to the base_typeclass_info.
ConsId = typeclass_info_cell_constructor,
poly_info_get_const_struct_db(!.Info, ConstStructDb0),
const_struct_db_get_poly_enabled(ConstStructDb0, ConstStructEnabled),
(
ConstStructEnabled = yes,
all_are_const_struct_args(ArgVarsMCAs, VarConstArgs)
->
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
set_var_maps_snapshot("construct_typeclass_info",
InitialVarMapsSnapshot, !Info),
new_typeclass_info_var(Constraint, typeclass_info_kind,
TypeClassInfoVar, TypeClassInfoVarType, !Info),
build_typeclass_info_type(Constraint, BaseConstArgType),
BaseConstArg = csa_constant(BaseConsId, BaseConstArgType),
StructArgs = [BaseConstArg | VarConstArgs],
list.map(get_inst_of_const_struct_arg(ConstStructDb0),
VarConstArgs, VarInsts),
list.length(ArgVarsMCAs, NumArgs),
InstConsId = cell_inst_cons_id(typeclass_info_cell, NumArgs),
StructInst = bound(shared, inst_test_results_fgtc,
[bound_functor(InstConsId, VarInsts)]),
ConstStruct = const_struct(ConsId, StructArgs,
TypeClassInfoVarType, StructInst),
lookup_insert_const_struct(ConstStruct, ConstNum,
ConstStructDb0, ConstStructDb),
poly_info_set_const_struct_db(ConstStructDb, !Info),
TypeClassInfoConstArg = csa_const_struct(ConstNum),
TypeClassInfoMCA = yes(TypeClassInfoConstArg),
% Create the construction unification to initialize the variable.
ConstConsId = typeclass_info_const(ConstNum),
Unification = construct(TypeClassInfoVar, ConstConsId, [], [],
construct_statically, cell_is_shared, no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
% XXX The UnifyContext is wrong.
UnifyContext = unify_context(umc_explicit, []),
TypeClassInfoRHS = rhs_functor(ConstConsId, no, []),
GoalExpr = unify(TypeClassInfoVar, TypeClassInfoRHS, UnifyMode,
Unification, UnifyContext),
% Create a goal_info for the unification.
goal_info_init(GoalInfo0),
NonLocals = set_of_var.make_singleton(TypeClassInfoVar),
goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo1),
% Note that we could perhaps be more accurate than `ground(shared)',
% but it shouldn't make any difference.
InstResults = inst_test_results(inst_result_is_ground,
inst_result_does_not_contain_any,
inst_result_contains_instnames_known(set.init),
inst_result_contains_types_known(set.init)),
TypeClassInfoInst = bound(shared, InstResults,
[bound_functor(ConsId, [])]),
TypeClassInfoVarInst = TypeClassInfoVar - TypeClassInfoInst,
InstMapDelta = instmap_delta_from_assoc_list([TypeClassInfoVarInst]),
goal_info_set_instmap_delta(InstMapDelta, GoalInfo1, GoalInfo2),
goal_info_set_determinism(detism_det, GoalInfo2, GoalInfo),
Goal = hlds_goal(GoalExpr, GoalInfo),
% XXX reset varset and vartypes
AllGoals = [Goal]
;
TypeClassInfoMCA = no,
new_typeclass_info_var(Constraint, typeclass_info_kind,
TypeClassInfoVar, _TypeClassInfoVarType, !Info),
assoc_list.keys(ArgVarsMCAs, ArgVars),
AllArgVars = [BaseVar | ArgVars],
% Create the construction unification to initialize the variable.
TypeClassInfoRHS = rhs_functor(ConsId, no, AllArgVars),
UniMode = (free - ground(shared, none) ->
ground(shared, none) - ground(shared, none)),
list.length(AllArgVars, NumArgs),
list.duplicate(NumArgs, UniMode, UniModes),
Unification = construct(TypeClassInfoVar, ConsId, AllArgVars, UniModes,
construct_dynamically, cell_is_unique, no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
UnifyContext = unify_context(umc_explicit, []),
% XXX The UnifyContext is wrong.
GoalExpr = unify(TypeClassInfoVar, TypeClassInfoRHS, UnifyMode,
Unification, UnifyContext),
% Create a goal_info for the unification.
goal_info_init(GoalInfo0),
set_of_var.list_to_set([TypeClassInfoVar | AllArgVars], NonLocals),
goal_info_set_nonlocals(NonLocals, GoalInfo0, GoalInfo1),
list.duplicate(NumArgs, ground(shared, none), ArgInsts),
% Note that we could perhaps be more accurate than `ground(shared)',
% but it shouldn't make any difference.
InstConsId = cell_inst_cons_id(typeclass_info_cell, NumArgs),
InstResults = inst_test_results(inst_result_is_ground,
inst_result_does_not_contain_any,
inst_result_contains_instnames_known(set.init),
inst_result_contains_types_unknown),
% XXX that should be inst_result_contains_types_known(set.init),
TypeClassInfoInst = bound(unique, InstResults,
[bound_functor(InstConsId, ArgInsts)]),
TypeClassInfoVarInst = TypeClassInfoVar - TypeClassInfoInst,
InstMapDelta = instmap_delta_from_assoc_list([TypeClassInfoVarInst]),
goal_info_set_instmap_delta(InstMapDelta, GoalInfo1, GoalInfo2),
goal_info_set_determinism(detism_det, GoalInfo2, GoalInfo),
Goal = hlds_goal(GoalExpr, GoalInfo),
AllGoals = PrevGoals ++ [Goal]
).
%---------------------------------------------------------------------------%
:- pred get_arg_superclass_vars(hlds_class_defn::in, list(mer_type)::in,
constraint_proof_map::in, existq_tvars::in,
assoc_list(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
get_arg_superclass_vars(ClassDefn, InstanceTypes, SuperClassProofs, ExistQVars,
SuperClassTypeClassInfoVarsMCAs, SuperClassGoals, !Info) :-
poly_info_get_proofs(!.Info, Proofs),
poly_info_get_typevarset(!.Info, TVarSet0),
SuperClasses0 = ClassDefn ^ class_supers,
ClassVars0 = ClassDefn ^ class_vars,
ClassTVarSet = ClassDefn ^ class_tvarset,
tvarset_merge_renaming(TVarSet0, ClassTVarSet, TVarSet1, Renaming),
poly_info_set_typevarset(TVarSet1, !Info),
apply_variable_renaming_to_tvar_list(Renaming, ClassVars0, ClassVars),
map.from_corresponding_lists(ClassVars, InstanceTypes, TypeSubst),
apply_variable_renaming_to_prog_constraint_list(Renaming,
SuperClasses0, SuperClasses1),
apply_rec_subst_to_prog_constraint_list(TypeSubst,
SuperClasses1, SuperClasses),
poly_info_set_proofs(SuperClassProofs, !Info),
make_superclasses_from_proofs(SuperClasses, ExistQVars,
SuperClassTypeClassInfoVarsMCAs, SuperClassGoals, !Info),
poly_info_set_proofs(Proofs, !Info).
:- pred make_superclasses_from_proofs(list(prog_constraint)::in,
existq_tvars::in, assoc_list(prog_var, maybe(const_struct_arg))::out,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
make_superclasses_from_proofs([], _, [], [], !Info).
make_superclasses_from_proofs([Constraint | Constraints], ExistQVars,
[TypeClassInfoVarMCA | TypeClassInfoVarsMCAs], Goals, !Info) :-
term.context_init(Context),
make_typeclass_info_var(Constraint, [], ExistQVars, Context,
TypeClassInfoVarMCA, HeadGoals, !Info),
make_superclasses_from_proofs(Constraints, ExistQVars,
TypeClassInfoVarsMCAs, TailGoals, !Info),
Goals = HeadGoals ++ TailGoals.
%-----------------------------------------------------------------------------%
% Produce the typeclass_infos for the existential class constraints
% for a call or deconstruction unification.
%
:- pred make_existq_typeclass_info_vars(list(prog_constraint)::in,
list(prog_var)::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
make_existq_typeclass_info_vars(ExistentialConstraints, ExtraTypeClassVars,
ExtraGoals, !Info) :-
poly_info_get_rtti_varmaps(!.Info, OldRttiVarMaps),
make_typeclass_info_head_vars(do_record_type_info_locns,
ExistentialConstraints, ExtraTypeClassVars, !Info),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
list.foldl(rtti_reuse_typeclass_info_var, ExtraTypeClassVars,
RttiVarMaps0, RttiVarMaps),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info),
constraint_list_get_tvars(ExistentialConstraints, TVars0),
list.sort_and_remove_dups(TVars0, TVars),
list.foldl2(polymorphism_maybe_extract_type_info(OldRttiVarMaps), TVars,
[], ExtraGoals, !Info).
% For code which requires mode reordering, we may have already seen uses
% of some of the type variables produced by this call. At the point of the
% use of a type variable that we haven't seen before, we assume that it is
% unconstrained. If it turns out that the type variable is constrained,
% and the type_info is contained in a typeclass_info, we need to generate
% code to extract it here.
%
:- pred polymorphism_maybe_extract_type_info(rtti_varmaps::in, tvar::in,
list(hlds_goal)::in, list(hlds_goal)::out, poly_info::in, poly_info::out)
is det.
polymorphism_maybe_extract_type_info(OldRttiVarMaps, TVar, !ExtraGoals,
!Info) :-
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps),
(
rtti_search_type_info_locn(OldRttiVarMaps, TVar,
type_info(TypeInfoVar0)),
rtti_search_type_info_locn(RttiVarMaps, TVar,
typeclass_info(TypeClassInfoVar, Index))
->
polymorphism_extract_type_info(TVar, TypeClassInfoVar, Index, NewGoals,
TypeInfoVar1, !Info),
assign_var(TypeInfoVar0, TypeInfoVar1, AssignGoal),
!:ExtraGoals = NewGoals ++ [AssignGoal | !.ExtraGoals]
;
true
).
%---------------------------------------------------------------------------%
polymorphism_make_type_info_vars(Types, Context, ExtraVars,
ExtraGoals, !Info) :-
polymorphism_do_make_type_info_vars(Types, Context, ExtraVarsMCAs,
ExtraGoals, !Info),
assoc_list.keys(ExtraVarsMCAs, ExtraVars).
polymorphism_make_type_info_var(Type, Context, ExtraVar, ExtraGoals, !Info) :-
polymorphism_do_make_type_info_var(Type, Context, ExtraVarMCA,
ExtraGoals, !Info),
ExtraVarMCA = ExtraVar - _.
:- pred polymorphism_do_make_type_info_vars(list(mer_type)::in,
term.context::in,
assoc_list(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
polymorphism_do_make_type_info_vars([], _, [], [], !Info).
polymorphism_do_make_type_info_vars([Type | Types], Context,
VarsMCAs, Goals, !Info) :-
polymorphism_do_make_type_info_var(Type, Context, HeadVarMCA,
HeadGoals, !Info),
polymorphism_do_make_type_info_vars(Types, Context, TailVarsMCAs,
TailGoals, !Info),
VarsMCAs = [HeadVarMCA | TailVarsMCAs],
Goals = HeadGoals ++ TailGoals.
:- pred polymorphism_do_make_type_info_var(mer_type::in, term.context::in,
pair(prog_var, maybe(const_struct_arg))::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
polymorphism_do_make_type_info_var(Type, Context, VarMCA, ExtraGoals, !Info) :-
% First handle statically known types (i.e. types which are not
% type variables).
( type_has_variable_arity_ctor(Type, TypeCtor, TypeArgs) ->
% This occurs for code where a predicate calls a polymorphic predicate
% with a type whose type constructor is of variable arity. The
% transformation we perform is basically the same as in the usual case
% below, except that we map pred types to pred/0, func types to func/0
% and tuple types to tuple/0 for the purposes of creating type_infos.
% To allow univ_to_type to check the type_infos correctly, the actual
% arity is added to the type_info we create.
%
% XXX FIXME (RTTI for higher order impure code)
% we should not ignore the purity of higher order procs;
% it should get included in the RTTI.
polymorphism_make_type_info(Type, TypeCtor, TypeArgs, yes,
Context, VarMCA, ExtraGoals, !Info)
;
(
( Type = defined_type(_, _, _)
; Type = builtin_type(_)
; Type = tuple_type(_, _)
; Type = higher_order_type(_,_, _, _)
; Type = apply_n_type(_, _, _)
; Type = kinded_type(_, _)
),
type_to_ctor_and_args_det(Type, TypeCtor, TypeArgs),
% This occurs for code where a predicate calls a polymorphic
% predicate with a known value of the type variable. The
% transformation we perform is shown in the comment at the top
% of the module.
polymorphism_make_type_info(Type, TypeCtor, TypeArgs, no,
Context, VarMCA, ExtraGoals, !Info)
;
% Now handle the cases of types which are not known statically,
% i.e. type variables.
Type = type_variable(TypeVar, _),
get_type_info_locn(TypeVar, TypeInfoLocn, !Info),
get_type_info_from_locn(TypeVar, TypeInfoLocn, Var, ExtraGoals,
!Info),
VarMCA = Var - no
)
).
:- pred polymorphism_make_type_info(mer_type::in, type_ctor::in,
list(mer_type)::in, bool::in, prog_context::in,
pair(prog_var, maybe(const_struct_arg))::out,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
polymorphism_make_type_info(Type, TypeCtor, TypeArgs, TypeCtorIsVarArity,
Context, TypeInfoVarMCA, ExtraGoals, !Info) :-
poly_info_get_type_info_var_map(!.Info, TypeInfoVarMap0),
(
map.search(TypeInfoVarMap0, TypeCtor, TypeCtorVarMap0),
map.search(TypeCtorVarMap0, TypeArgs, OldTypeInfoVarMCA)
->
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
TypeInfoVarMCA = OldTypeInfoVarMCA,
ExtraGoals = []
;
polymorphism_construct_type_info(Type, TypeCtor, TypeArgs,
TypeCtorIsVarArity, Context, TypeInfoVar, TypeInfoConstArg,
ExtraGoals, !Info),
TypeInfoVarMCA = TypeInfoVar - TypeInfoConstArg,
% We have to get the type_info_var_map again since the call just above
% could have added relevant new entries to it.
poly_info_get_type_info_var_map(!.Info, TypeInfoVarMap1),
( map.search(TypeInfoVarMap1, TypeCtor, TypeCtorVarMap1) ->
map.det_insert(TypeArgs, TypeInfoVarMCA,
TypeCtorVarMap1, TypeCtorVarMap),
map.det_update(TypeCtor, TypeCtorVarMap,
TypeInfoVarMap1, TypeInfoVarMap)
;
TypeCtorVarMap = map.singleton(TypeArgs, TypeInfoVarMCA),
map.det_insert(TypeCtor, TypeCtorVarMap,
TypeInfoVarMap1, TypeInfoVarMap)
),
poly_info_set_type_info_var_map(TypeInfoVarMap, !Info)
).
:- pred polymorphism_construct_type_info(mer_type::in, type_ctor::in,
list(mer_type)::in, bool::in, prog_context::in,
prog_var::out, maybe(const_struct_arg)::out,
list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
polymorphism_construct_type_info(Type, TypeCtor, TypeArgs, TypeCtorIsVarArity,
Context, Var, MCA, ExtraGoals, !Info) :-
get_var_maps_snapshot("polymorphism_construct_type_info",
InitialVarMapsSnapshot, !Info),
% Create the typeinfo vars for the arguments.
polymorphism_do_make_type_info_vars(TypeArgs, Context,
ArgTypeInfoVarsMCAs, ArgTypeInfoGoals, !Info),
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
TypeCtorConsId = type_ctor_info_cons_id(TypeCtor),
TypeCtorConsIdConstArg = csa_constant(TypeCtorConsId, type_info_type),
poly_info_get_const_struct_var_map(!.Info, ConstStructVarMap0),
( map.search(ConstStructVarMap0, TypeCtorConsIdConstArg, OldTypeCtorVar) ->
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
TypeCtorVar = OldTypeCtorVar,
TypeCtorGoals = [],
VarSet1 = VarSet0,
VarTypes1 = VarTypes0,
RttiVarMaps1 = RttiVarMaps0
;
init_const_type_ctor_info_var_from_cons_id(Type, TypeCtorConsId,
TypeCtorVar, TypeCtorGoal, VarSet0, VarSet1, VarTypes0, VarTypes1,
RttiVarMaps0, RttiVarMaps1),
TypeCtorGoals = [TypeCtorGoal],
map.det_insert(TypeCtorConsIdConstArg, TypeCtorVar,
ConstStructVarMap0, ConstStructVarMap1),
poly_info_set_const_struct_var_map(ConstStructVarMap1, !Info)
),
poly_info_set_varset_and_types(VarSet1, VarTypes1, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps1, !Info),
% The rest of this predicate create code that constructs the second cell
% of a type_info for Type if we need a second cell for Type. This cell
% will usually be of the form:
%
% TypeInfoVar = type_info(TypeCtorVar, ArgTypeInfoVars...)
%
% However, if TypeCtorIsVarArity is true, then it will be of the form
%
% TypeInfoVar = type_info(TypeCtorVar, Arity, ArgTypeInfoVars...)
%
% TypeCtorVar should be the variable holding the type_ctor_info for the
% principal type constructor of Type, and TypeCtorIsVarArity should be
% true iff the type constructor it represents has a variable arity.
%
% ArgTypeInfoVars should be variables holding the type_infos (or
% type_ctor_infos for zero-arity types) of the argument types of Type.
%
% The returned Var will be bound to the type_info cell of Type if such
% a cell had to be allocated, and to the type_ctor_info of Type's only
% type constructor if it didn't.
(
% Unfortunately, if the type's type constructor has variable arity,
% we cannot use a one-cell representation for that type.
TypeCtorIsVarArity = no,
ArgTypeInfoVarsMCAs = []
->
% We do not need a second cell for a separate typeinfo; we will use
% the type_ctor_info as the type_info.
% Since this type_ctor_info is pretending to be a type_info,
% we need to adjust its type. We handle type_ctor_info_const cons_ids
% specially to make sure that this causes no problems.
TypeInfoType = type_info_type,
Var = TypeCtorVar,
TypeCtorConstArg = csa_constant(TypeCtorConsId, type_info_type),
MCA = yes(TypeCtorConstArg),
ExtraGoals = ArgTypeInfoGoals ++ TypeCtorGoals,
update_var_type(TypeCtorVar, TypeInfoType, VarTypes1, VarTypes),
poly_info_set_varset_and_types(VarSet1, VarTypes, !Info)
;
% We do need a second cell for a separate typeinfo.
Cell = type_info_cell(TypeCtor),
ConsId = cell_cons_id(Cell),
poly_info_get_const_struct_db(!.Info, ConstStructDb0),
const_struct_db_get_poly_enabled(ConstStructDb0, Enabled),
(
Enabled = yes,
all_are_const_struct_args(ArgTypeInfoVarsMCAs,
ArgTypeInfoConstArgs)
->
TypeCtorConstArg = csa_constant(TypeCtorConsId, type_info_type),
TypeCtorInst = bound(shared, inst_test_results_fgtc,
[bound_functor(TypeCtorConsId, [])]),
list.map(get_inst_of_const_struct_arg(ConstStructDb0),
ArgTypeInfoConstArgs, ArgTypeInfoInsts),
(
TypeCtorIsVarArity = yes,
list.length(ArgTypeInfoVarsMCAs, ActualArity),
ArityConstArg = csa_constant(int_const(ActualArity), int_type),
ArityInst = bound(shared, inst_test_results_fgtc,
[bound_functor(int_const(ActualArity), [])]),
StructConstArgs =
[TypeCtorConstArg, ArityConstArg | ArgTypeInfoConstArgs],
StructArgInsts = [TypeCtorInst, ArityInst | ArgTypeInfoInsts]
;
TypeCtorIsVarArity = no,
StructConstArgs = [TypeCtorConstArg | ArgTypeInfoConstArgs],
StructArgInsts = [TypeCtorInst | ArgTypeInfoInsts]
),
StructType = type_info_type,
list.length(ArgTypeInfoConstArgs, NumArgs),
InstConsId = cell_inst_cons_id(Cell, NumArgs),
StructInst = bound(shared, inst_test_results_fgtc,
[bound_functor(InstConsId, StructArgInsts)]),
ConstStruct = const_struct(ConsId, StructConstArgs,
StructType, StructInst),
lookup_insert_const_struct(ConstStruct, ConstNum,
ConstStructDb0, ConstStructDb),
MCA = yes(csa_const_struct(ConstNum)),
poly_info_set_const_struct_db(ConstStructDb, !Info),
set_var_maps_snapshot("maybe_init_second_cell",
InitialVarMapsSnapshot, !Info),
new_type_info_var(Type, type_info, Var, !Info),
Unification = construct(Var, type_info_const(ConstNum),
[], [], construct_statically, cell_is_shared,
no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
UnifyContext = unify_context(umc_explicit, []),
% XXX The UnifyContext is wrong.
TypeInfoRHS = rhs_functor(type_info_const(ConstNum), no, []),
Unify = unify(Var, TypeInfoRHS, UnifyMode, Unification,
UnifyContext),
% Create a goal_info for the unification.
NonLocals = set_of_var.make_singleton(Var),
% Note that we could be more accurate than `ground(shared)',
% but it shouldn't make any difference.
InstResults = inst_test_results(inst_result_is_ground,
inst_result_does_not_contain_any,
inst_result_contains_instnames_known(set.init),
inst_result_contains_types_known(set.init)),
VarInst = bound(shared, InstResults,
[bound_functor(InstConsId, [])]),
InstMapDelta = instmap_delta_from_assoc_list([Var - VarInst]),
goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure,
GoalInfo),
TypeInfoGoal = hlds_goal(Unify, GoalInfo),
ExtraGoals = [TypeInfoGoal]
;
assoc_list.keys(ArgTypeInfoVarsMCAs, ArgTypeInfoVars),
(
TypeCtorIsVarArity = yes,
list.length(ArgTypeInfoVars, ActualArity),
get_poly_const(ActualArity, ArityVar, ArityGoals, !Info),
% The call get_poly_const may (and probably will) allocate
% a variable, so VarSet1, VarTypes1 and RttiVarMaps1 are
% all out of date.
poly_info_get_varset(!.Info, VarSet2),
poly_info_get_var_types(!.Info, VarTypes2),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps2),
init_type_info_var(Type,
[TypeCtorVar, ArityVar | ArgTypeInfoVars],
no, Var, TypeInfoGoal,
VarSet2, VarSet, VarTypes2, VarTypes,
RttiVarMaps2, RttiVarMaps),
ExtraGoals = TypeCtorGoals ++ ArityGoals ++ ArgTypeInfoGoals
++ [TypeInfoGoal]
;
TypeCtorIsVarArity = no,
init_type_info_var(Type, [TypeCtorVar | ArgTypeInfoVars],
no, Var, TypeInfoGoal,
VarSet1, VarSet, VarTypes1, VarTypes,
RttiVarMaps1, RttiVarMaps),
ExtraGoals = TypeCtorGoals ++ ArgTypeInfoGoals ++
[TypeInfoGoal]
),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info),
MCA = no
)
).
get_special_proc(Type, SpecialPredId, ModuleInfo, PredName, PredId, ProcId) :-
TypeCategory = classify_type(ModuleInfo, Type),
get_category_name(TypeCategory) = MaybeCategoryName,
(
MaybeCategoryName = no,
module_info_get_special_pred_map(ModuleInfo, SpecialPredMap),
type_to_ctor_det(Type, TypeCtor),
map.search(SpecialPredMap, SpecialPredId - TypeCtor, PredId),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
Module = pred_info_module(PredInfo),
Name = pred_info_name(PredInfo),
PredName = qualified(Module, Name),
special_pred_mode_num(SpecialPredId, ProcInt),
proc_id_to_int(ProcId, ProcInt)
;
MaybeCategoryName = yes(CategoryName),
special_pred_name_arity(SpecialPredId, SpecialName, _, Arity),
Name = "builtin_" ++ SpecialName ++ "_" ++ CategoryName,
lookup_builtin_pred_proc_id(ModuleInfo, mercury_private_builtin_module,
Name, pf_predicate, Arity, only_mode, PredId, ProcId),
PredName = qualified(mercury_private_builtin_module, Name)
).
get_special_proc_det(Type, SpecialPredId, ModuleInfo, PredName,
PredId, ProcId) :-
(
get_special_proc(Type, SpecialPredId, ModuleInfo,
PredNamePrime, PredIdPrime, ProcIdPrime)
->
PredName = PredNamePrime,
PredId = PredIdPrime,
ProcId = ProcIdPrime
;
unexpected($module, $pred, "get_special_proc failed")
).
:- func get_category_name(type_ctor_category) = maybe(string).
get_category_name(CtorCat) = MaybeName :-
(
CtorCat = ctor_cat_builtin(cat_builtin_int),
MaybeName = yes("int")
;
CtorCat = ctor_cat_builtin(cat_builtin_char),
MaybeName = yes("character")
;
CtorCat = ctor_cat_builtin(cat_builtin_float),
MaybeName = yes("float")
;
CtorCat = ctor_cat_builtin(cat_builtin_string),
MaybeName = yes("string")
;
CtorCat = ctor_cat_higher_order,
MaybeName = yes("pred")
;
CtorCat = ctor_cat_tuple,
MaybeName = yes("tuple")
;
( CtorCat = ctor_cat_enum(_)
; CtorCat = ctor_cat_builtin_dummy
; CtorCat = ctor_cat_user(_)
; CtorCat = ctor_cat_system(_)
),
MaybeName = no
;
CtorCat = ctor_cat_variable,
unexpected($module, $pred, "variable type")
;
CtorCat = ctor_cat_void,
unexpected($module, $pred, "void_type")
).
init_type_info_var(Type, ArgVars, MaybePreferredVar, TypeInfoVar, TypeInfoGoal,
!VarSet, !VarTypes, !RttiVarMaps) :-
type_to_ctor_det(Type, TypeCtor),
Cell = type_info_cell(TypeCtor),
ConsId = cell_cons_id(Cell),
do_init_type_info_var(Type, Cell, ConsId, ArgVars, MaybePreferredVar,
TypeInfoVar, TypeInfoGoal, !VarSet, !VarTypes, !RttiVarMaps).
:- pred do_init_type_info_var(mer_type::in, polymorphism_cell::in, cons_id::in,
list(prog_var)::in, maybe(prog_var)::in, prog_var::out, hlds_goal::out,
prog_varset::in, prog_varset::out, vartypes::in, vartypes::out,
rtti_varmaps::in, rtti_varmaps::out) is det.
do_init_type_info_var(Type, Cell, ConsId, ArgVars, MaybePreferredVar,
TypeInfoVar, TypeInfoGoal, !VarSet, !VarTypes, !RttiVarMaps) :-
TypeInfoRHS = rhs_functor(ConsId, no, ArgVars),
% Introduce a new variable.
(
MaybePreferredVar = yes(TypeInfoVar)
;
MaybePreferredVar = no,
new_type_info_var_raw(Type, type_info, TypeInfoVar,
!VarSet, !VarTypes, !RttiVarMaps)
),
% Create the construction unification to initialize the variable.
UniMode = (free - ground(shared, none) ->
ground(shared, none) - ground(shared, none)),
list.length(ArgVars, NumArgVars),
list.duplicate(NumArgVars, UniMode, UniModes),
Unification = construct(TypeInfoVar, ConsId, ArgVars, UniModes,
construct_dynamically, cell_is_unique, no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
UnifyContext = unify_context(umc_explicit, []),
% XXX The UnifyContext is wrong.
Unify = unify(TypeInfoVar, TypeInfoRHS, UnifyMode, Unification,
UnifyContext),
% Create a goal_info for the unification.
set_of_var.list_to_set([TypeInfoVar | ArgVars], NonLocals),
list.duplicate(NumArgVars, ground(shared, none), ArgInsts),
% Note that we could perhaps be more accurate than `ground(shared)',
% but it shouldn't make any difference.
InstConsId = cell_inst_cons_id(Cell, NumArgVars),
InstResults = inst_test_results(inst_result_is_ground,
inst_result_does_not_contain_any,
inst_result_contains_instnames_known(set.init),
inst_result_contains_types_unknown),
TypeInfoVarInst = bound(unique, InstResults,
[bound_functor(InstConsId, ArgInsts)]),
InstMapDelta = instmap_delta_from_assoc_list(
[TypeInfoVar - TypeInfoVarInst]),
goal_info_init(NonLocals, InstMapDelta, detism_det, purity_pure, GoalInfo),
TypeInfoGoal = hlds_goal(Unify, GoalInfo).
init_const_type_ctor_info_var(Type, TypeCtor, TypeCtorInfoVar,
ConsId, TypeCtorInfoGoal, !VarSet, !VarTypes, !RttiVarMaps) :-
ConsId = type_ctor_info_cons_id(TypeCtor),
init_const_type_ctor_info_var_from_cons_id(Type, ConsId,
TypeCtorInfoVar, TypeCtorInfoGoal, !VarSet, !VarTypes, !RttiVarMaps).
:- pred init_const_type_ctor_info_var_from_cons_id(mer_type::in, cons_id::in,
prog_var::out, hlds_goal::out, prog_varset::in, prog_varset::out,
vartypes::in, vartypes::out, rtti_varmaps::in, rtti_varmaps::out) is det.
init_const_type_ctor_info_var_from_cons_id(Type, ConsId,
TypeCtorInfoVar, TypeCtorInfoGoal, !VarSet, !VarTypes, !RttiVarMaps) :-
% Introduce a new variable.
new_type_info_var_raw(Type, type_ctor_info, TypeCtorInfoVar,
!VarSet, !VarTypes, !RttiVarMaps),
% Create the construction unification to initialize the variable.
TypeInfoRHS = rhs_functor(ConsId, no, []),
Unification = construct(TypeCtorInfoVar, ConsId, [], [],
construct_dynamically, cell_is_shared, no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
UnifyContext = unify_context(umc_explicit, []),
% XXX The UnifyContext is wrong.
Unify = unify(TypeCtorInfoVar, TypeInfoRHS, UnifyMode,
Unification, UnifyContext),
% Create a goal_info for the unification.
NonLocals = set_of_var.make_singleton(TypeCtorInfoVar),
InstmapDelta = instmap_delta_bind_var(TypeCtorInfoVar),
goal_info_init(NonLocals, InstmapDelta, detism_det, purity_pure, GoalInfo),
TypeCtorInfoGoal = hlds_goal(Unify, GoalInfo).
%---------------------------------------------------------------------------%
:- pred make_head_vars(list(tvar)::in, tvarset::in,
list(prog_var)::out, poly_info::in, poly_info::out) is det.
make_head_vars([], _, [], !Info).
make_head_vars([TypeVar | TypeVars], TypeVarSet, TypeInfoVars, !Info) :-
get_tvar_kind(!.Info ^ poly_tvar_kinds, TypeVar, Kind),
Type = type_variable(TypeVar, Kind),
new_type_info_var(Type, type_info, Var, !Info),
( varset.search_name(TypeVarSet, TypeVar, TypeVarName) ->
poly_info_get_varset(!.Info, VarSet0),
VarName = "TypeInfo_for_" ++ TypeVarName,
varset.name_var(Var, VarName, VarSet0, VarSet),
poly_info_set_varset(VarSet, !Info)
;
true
),
make_head_vars(TypeVars, TypeVarSet, TypeInfoVars1, !Info),
TypeInfoVars = [Var | TypeInfoVars1].
:- pred new_type_info_var(mer_type::in, type_info_kind::in,
prog_var::out, poly_info::in, poly_info::out) is det.
new_type_info_var(Type, Kind, Var, !Info) :-
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
new_type_info_var_raw(Type, Kind, Var, VarSet0, VarSet,
VarTypes0, VarTypes, RttiVarMaps0, RttiVarMaps),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info).
new_type_info_var_raw(Type, Kind, Var, !VarSet, !VarTypes, !RttiVarMaps) :-
% Introduce new variable.
varset.new_var(Var, !VarSet),
term.var_to_int(Var, VarNum),
string.int_to_string(VarNum, VarNumStr),
(
Kind = type_info,
Prefix = "TypeInfo_",
rtti_det_insert_type_info_type(Var, Type, !RttiVarMaps)
;
Kind = type_ctor_info,
Prefix = "TypeCtorInfo_"
% XXX Perhaps we should record the variables holding
% type_ctor_infos in the rtti_varmaps somewhere.
),
Name = Prefix ++ VarNumStr,
varset.name_var(Var, Name, !VarSet),
add_var_type(Var, type_info_type, !VarTypes).
%---------------------------------------------------------------------------%
:- pred get_type_info_locn(tvar::in, type_info_locn::out, poly_info::in,
poly_info::out) is det.
get_type_info_locn(TypeVar, TypeInfoLocn, !Info) :-
% If we have already allocated a location for this type_info, then all
% we need to do is to extract the type_info variable from its location.
(
rtti_search_type_info_locn(!.Info ^ poly_rtti_varmaps, TypeVar,
TypeInfoLocnPrime)
->
TypeInfoLocn = TypeInfoLocnPrime
;
% Otherwise, we need to create a new type_info variable, and set the
% location for this type variable to be that type_info variable.
%
% This is wrong if the type variable is one of the existentially
% quantified variables of a called predicate and the variable occurs
% in an existential typeclass constraint. In that case the type_info
% will be stored in the typeclass_info variable produced by the
% predicate, not in a type_info variable. maybe_extract_type_info
% will fix this up when the typeclass_info is created.
get_tvar_kind(!.Info ^ poly_tvar_kinds, TypeVar, Kind),
Type = type_variable(TypeVar, Kind),
new_type_info_var(Type, type_info, Var, !Info),
TypeInfoLocn = type_info(Var),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
rtti_det_insert_type_info_locn(TypeVar, TypeInfoLocn,
RttiVarMaps0, RttiVarMaps),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info)
).
% Generate code to get the value of a type variable.
%
:- pred get_type_info_from_locn(tvar::in, type_info_locn::in,
prog_var::out, list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
get_type_info_from_locn(TypeVar, TypeInfoLocn, Var, ExtraGoals, !Info) :-
(
% If the typeinfo is available in a variable, just use it.
TypeInfoLocn = type_info(TypeInfoVar),
Var = TypeInfoVar,
ExtraGoals = []
;
% If the typeinfo is in a typeclass_info, then we need to extract it
% before using it.
TypeInfoLocn = typeclass_info(TypeClassInfoVar, Index),
polymorphism_extract_type_info(TypeVar, TypeClassInfoVar, Index,
ExtraGoals, Var, !Info)
).
:- pred polymorphism_extract_type_info(tvar::in, prog_var::in, int::in,
list(hlds_goal)::out, prog_var::out, poly_info::in, poly_info::out) is det.
polymorphism_extract_type_info(TypeVar, TypeClassInfoVar, Index, Goals,
TypeInfoVar, !Info) :-
get_poly_const(Index, IndexVar, IndexGoals, !Info),
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
poly_info_get_module_info(!.Info, ModuleInfo),
poly_info_get_tvar_kinds(!.Info, TVarKinds),
get_tvar_kind(TVarKinds, TypeVar, Kind),
IndexIntOrVar = iov_var(IndexVar),
gen_extract_type_info(ModuleInfo, TypeVar, Kind, TypeClassInfoVar,
IndexIntOrVar, ExtractGoals, TypeInfoVar,
VarSet0, VarSet, VarTypes0, VarTypes, RttiVarMaps0, RttiVarMaps),
Goals = IndexGoals ++ ExtractGoals,
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info).
gen_extract_type_info(ModuleInfo, TypeVar, Kind, TypeClassInfoVar,
IndexIntOrVar, Goals, TypeInfoVar, !VarSet, !VarTypes, !RttiVarMaps) :-
(
IndexIntOrVar = iov_int(Index),
% We cannot call get_poly_const since we don't have a poly_info.
make_int_const_construction_alloc(Index, yes("TypeInfoIndex"),
IndexGoal, IndexVar, !VarSet, !VarTypes),
IndexGoals = [IndexGoal]
;
IndexIntOrVar = iov_var(IndexVar),
IndexGoals = []
),
Type = type_variable(TypeVar, Kind),
new_type_info_var_raw(Type, type_info, TypeInfoVar,
!VarSet, !VarTypes, !RttiVarMaps),
goal_util.generate_simple_call(mercury_private_builtin_module,
"type_info_from_typeclass_info", pf_predicate, only_mode,
detism_det, purity_pure, [TypeClassInfoVar, IndexVar, TypeInfoVar], [],
instmap_delta_bind_var(TypeInfoVar), ModuleInfo, term.context_init,
CallGoal),
Goals = IndexGoals ++ [CallGoal].
:- pred get_poly_const(int::in, prog_var::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
get_poly_const(IntConst, IntVar, Goals, !Info) :-
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_int_const_map(!.Info, IntConstMap0),
( map.search(IntConstMap0, IntConst, IntVarPrime) ->
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
IntVar = IntVarPrime,
Goals = []
;
make_int_const_construction_alloc(IntConst,
yes("PolyConst" ++ string.int_to_string(IntConst)),
Goal, IntVar, VarSet0, VarSet, VarTypes0, VarTypes),
map.det_insert(IntConst, IntVar, IntConstMap0, IntConstMap),
poly_info_set_int_const_map(IntConstMap, !Info),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
Goals = [Goal]
).
%-----------------------------------------------------------------------------%
% Usually when we call make_typeclass_info_head_var, we want to record
% the type_info_locn for each constrained type var so that later goals
% will know where to get the type_info from. However, when setting up
% head vars for existential constraints on the predicate/function we
% are processing, we assume that the type_infos will be produced
% somewhere else in the goal. In this case, we don't want to record
% the type_info_locns (if we did, then the code to actually produce the
% type_info will just try to get it from here, which would be a mode
% error).
%
:- type record_type_info_locns
---> do_record_type_info_locns
; do_not_record_type_info_locns.
% Create a head var for each class constraint.
%
:- pred make_typeclass_info_head_vars(record_type_info_locns::in,
list(prog_constraint)::in, list(prog_var)::out,
poly_info::in, poly_info::out) is det.
make_typeclass_info_head_vars(RecordLocns, Constraints, ExtraHeadVars,
!Info) :-
list.map_foldl(make_typeclass_info_head_var(RecordLocns), Constraints,
ExtraHeadVars, !Info).
:- pred make_typeclass_info_head_var(record_type_info_locns::in,
prog_constraint::in, prog_var::out, poly_info::in, poly_info::out) is det.
make_typeclass_info_head_var(RecordLocns, Constraint, TypeClassInfoVar,
!Info) :-
(
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
rtti_search_typeclass_info_var(RttiVarMaps0, Constraint,
OldTypeClassInfoVar)
->
TypeClassInfoVar = OldTypeClassInfoVar
;
% Make a new variable to contain the dictionary for this typeclass
% constraint.
new_typeclass_info_var(Constraint, typeclass_info_kind,
TypeClassInfoVar, _TypeClassInfoVarType, !Info),
(
RecordLocns = do_record_type_info_locns,
record_constraint_type_info_locns(Constraint, TypeClassInfoVar,
!Info)
;
RecordLocns = do_not_record_type_info_locns
)
).
:- pred record_constraint_type_info_locns(prog_constraint::in, prog_var::in,
poly_info::in, poly_info::out) is det.
record_constraint_type_info_locns(Constraint, ExtraHeadVar, !Info) :-
poly_info_get_module_info(!.Info, ModuleInfo),
% Work out how many superclasses the class has.
Constraint = constraint(ClassName, ClassTypes),
list.length(ClassTypes, ClassArity),
ClassId = class_id(ClassName, ClassArity),
module_info_get_class_table(ModuleInfo, ClassTable),
map.lookup(ClassTable, ClassId, ClassDefn),
SuperClasses = ClassDefn ^ class_supers,
list.length(SuperClasses, NumSuperClasses),
% Find all the type variables in the constraint, and remember what
% index they appear in in the typeclass info.
% The first type_info will be just after the superclass infos.
First = NumSuperClasses + 1,
Last = NumSuperClasses + ClassArity,
assoc_list.from_corresponding_lists(ClassTypes, First `..` Last,
IndexedClassTypes),
% Work out which type variables we haven't seen before, or which we
% assumed earlier would be produced in a type_info (this can happen for
% code which needs mode reordering and which calls existentially
% quantified predicates or deconstructs existentially quantified
% terms).
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
NewTVarAndIndex = (pred(TVarAndIndex::out) is nondet :-
list.member(Type - Index, IndexedClassTypes),
type_vars(Type, TypeVars),
list.member(TypeVar, TypeVars),
( rtti_search_type_info_locn(RttiVarMaps0, TypeVar, TypeInfoLocn) ->
TypeInfoLocn = type_info(_)
;
true
),
TVarAndIndex = TypeVar - Index
),
solutions(NewTVarAndIndex, NewClassTypeVars),
% Make an entry in the TypeInfo locations map for each new type variable.
% The type variable can be found at the previously calculated offset
% with the new typeclass_info.
MakeEntry =
(pred(IndexedTypeVar::in, R0::in, R::out) is det :-
IndexedTypeVar = TheTypeVar - Index,
Location = typeclass_info(ExtraHeadVar, Index),
rtti_set_type_info_locn(TheTypeVar, Location, R0, R)
),
list.foldl(MakeEntry, NewClassTypeVars, RttiVarMaps0, RttiVarMaps),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info).
:- type tci_var_kind
---> base_typeclass_info_kind
; typeclass_info_kind.
:- pred new_typeclass_info_var(prog_constraint::in, tci_var_kind::in,
prog_var::out, mer_type::out, poly_info::in, poly_info::out) is det.
new_typeclass_info_var(Constraint, VarKind, Var, VarType, !Info) :-
poly_info_get_varset(!.Info, VarSet0),
poly_info_get_var_types(!.Info, VarTypes0),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps0),
Constraint = constraint(ClassName, _),
ClassNameString = unqualify_name(ClassName),
% Introduce new variable.
varset.new_var(Var, VarSet0, VarSet1),
(
VarKind = base_typeclass_info_kind,
Name = "BaseTypeClassInfo_for_" ++ ClassNameString
;
VarKind = typeclass_info_kind,
Name = "TypeClassInfo_for_" ++ ClassNameString
),
varset.name_var(Var, Name, VarSet1, VarSet),
build_typeclass_info_type(Constraint, VarType),
add_var_type(Var, VarType, VarTypes0, VarTypes),
rtti_det_insert_typeclass_info_var(Constraint, Var,
RttiVarMaps0, RttiVarMaps),
poly_info_set_varset_and_types(VarSet, VarTypes, !Info),
poly_info_set_rtti_varmaps(RttiVarMaps, !Info).
build_typeclass_info_type(_Constraint, DictionaryType) :-
PrivateBuiltin = mercury_private_builtin_module,
TypeclassInfoTypeName = qualified(PrivateBuiltin, "typeclass_info"),
DictionaryType = defined_type(TypeclassInfoTypeName, [], kind_star).
%---------------------------------------------------------------------------%
type_is_typeclass_info(TypeClassInfoType) :-
type_to_ctor(TypeClassInfoType, TypeCtor),
TypeCtor = type_ctor(qualified(ModuleName, "typeclass_info"), 0),
ModuleName = mercury_private_builtin_module.
type_is_type_info_or_ctor_type(TypeInfoType) :-
type_to_ctor_and_args(TypeInfoType, TypeCtor, []),
TypeCtor = type_ctor(qualified(ModuleName, TypeName), 0),
ModuleName = mercury_private_builtin_module,
( TypeName = "type_info"
; TypeName = "type_ctor_info"
).
build_type_info_type(Type, TypeInfoType) :-
% XXX TypeInfoType = type_ctor_info_type.
( type_has_variable_arity_ctor(Type, _, _) ->
% We cannot use a plain type_ctor_info because we need to
% record the arity.
TypeInfoType = type_info_type
; type_to_ctor_and_args(Type, _Ctor, Args) ->
(
Args = [],
TypeInfoType = type_ctor_info_type
;
Args = [_ | _],
TypeInfoType = type_info_type
)
;
% The type is variable, which means we have a type_info for it.
% That type_info may actually be a type_ctor_info, but the code
% of the current predicate won't treat it as such.
TypeInfoType = type_info_type
).
%---------------------------------------------------------------------------%
% Expand the bodies of all class methods. Class methods for imported
% classes are only expanded if we are performing type specialization,
% so that method lookups for imported classes can be optimized.
%
% The expansion involves inserting a class_method_call with the appropriate
% arguments, which is responsible for extracting the appropriate part
% of the dictionary.
%
:- pred expand_class_method_bodies(module_info::in, module_info::out) is det.
expand_class_method_bodies(!ModuleInfo) :-
module_info_get_class_table(!.ModuleInfo, Classes),
module_info_get_name(!.ModuleInfo, ModuleName),
map.keys(Classes, ClassIds0),
module_info_get_globals(!.ModuleInfo, Globals),
globals.lookup_bool_option(Globals, user_guided_type_specialization,
TypeSpec),
(
TypeSpec = no,
% Don't expand classes from other modules.
list.filter(class_id_is_from_given_module(ModuleName),
ClassIds0, ClassIds)
;
TypeSpec = yes,
ClassIds = ClassIds0
),
map.apply_to_list(ClassIds, Classes, ClassDefns),
list.foldl(expand_class_method_bodies_2, ClassDefns, !ModuleInfo).
:- pred class_id_is_from_given_module(module_name::in, class_id::in)
is semidet.
class_id_is_from_given_module(ModuleName, ClassId) :-
ClassId = class_id(qualified(ModuleName, _), _).
:- pred expand_class_method_bodies_2(hlds_class_defn::in,
module_info::in, module_info::out) is det.
expand_class_method_bodies_2(ClassDefn, !ModuleInfo) :-
Interface = ClassDefn ^ class_hlds_interface,
list.foldl2(expand_class_method_body, Interface, 1, _, !ModuleInfo).
:- pred expand_class_method_body(hlds_class_proc::in, int::in, int::out,
module_info::in, module_info::out) is det.
expand_class_method_body(hlds_class_proc(PredId, ProcId), !ProcNum,
!ModuleInfo) :-
module_info_get_preds(!.ModuleInfo, PredTable0),
map.lookup(PredTable0, PredId, PredInfo0),
pred_info_get_procedures(PredInfo0, ProcTable0),
map.lookup(ProcTable0, ProcId, ProcInfo0),
% Find which of the constraints on the pred is the one introduced
% because it is a class method.
pred_info_get_class_context(PredInfo0, ClassContext),
( ClassContext = constraints([Head | _], _) ->
InstanceConstraint = Head
;
unexpected($module, $pred, "class method is not constrained")
),
proc_info_get_rtti_varmaps(ProcInfo0, RttiVarMaps),
rtti_lookup_typeclass_info_var(RttiVarMaps, InstanceConstraint,
TypeClassInfoVar),
proc_info_get_headvars(ProcInfo0, HeadVars0),
proc_info_get_argmodes(ProcInfo0, Modes0),
proc_info_get_declared_determinism(ProcInfo0, MaybeDetism0),
(
MaybeDetism0 = yes(Detism)
;
MaybeDetism0 = no,
% Omitting the determinism for a method is not allowed. But make_hlds
% will have already detected and reported the error. So here we can
% just pick some value at random; hopefully something that won't cause
% flow-on errors. We also mark the predicate as invalid, also to avoid
% flow-on errors.
Detism = detism_non,
module_info_remove_predid(PredId, !ModuleInfo)
),
% Work out which argument corresponds to the constraint which is introduced
% because this is a class method, then delete it from the list of args to
% the class_method_call. That variable becomes the "dictionary" variable
% for the class_method_call. (cf. the closure for a higher order call).
(
list.nth_member_search(HeadVars0, TypeClassInfoVar, N),
delete_nth(HeadVars0, N, HeadVarsPrime),
delete_nth(Modes0, N, ModesPrime)
->
HeadVars = HeadVarsPrime,
Modes = ModesPrime
;
unexpected($module, $pred, "typeclass_info var not found")
),
InstanceConstraint = constraint(ClassName, InstanceArgs),
list.length(InstanceArgs, InstanceArity),
pred_info_get_call_id(PredInfo0, CallId),
BodyGoalExpr = generic_call(
class_method(TypeClassInfoVar, !.ProcNum,
class_id(ClassName, InstanceArity), CallId),
HeadVars, Modes, arg_reg_types_unset, Detism),
% Make the goal info for the call.
set_of_var.list_to_set(HeadVars0, NonLocals),
instmap_delta_from_mode_list(HeadVars0, Modes0, !.ModuleInfo,
InstmapDelta),
pred_info_get_purity(PredInfo0, Purity),
goal_info_init(NonLocals, InstmapDelta, Detism, Purity, GoalInfo),
BodyGoal = hlds_goal(BodyGoalExpr, GoalInfo),
proc_info_set_goal(BodyGoal, ProcInfo0, ProcInfo),
map.det_update(ProcId, ProcInfo, ProcTable0, ProcTable),
pred_info_set_procedures(ProcTable, PredInfo0, PredInfo1),
( pred_info_is_imported(PredInfo1) ->
pred_info_set_import_status(status_opt_imported, PredInfo1, PredInfo)
;
PredInfo = PredInfo1
),
map.det_update(PredId, PredInfo, PredTable0, PredTable),
module_info_set_preds(PredTable, !ModuleInfo),
!:ProcNum = !.ProcNum + 1.
:- pred delete_nth(list(T)::in, int::in, list(T)::out) is semidet.
delete_nth([X | Xs], N0, Result) :-
( N0 > 1 ->
N = N0 - 1,
delete_nth(Xs, N, TheRest),
Result = [X | TheRest]
;
Result = Xs
).
%---------------------------------------------------------------------------%
:- func get_constrained_vars(prog_constraint) = list(tvar).
get_constrained_vars(Constraint) = CVars :-
Constraint = constraint(_, CTypes),
type_vars_list(CTypes, CVars).
%---------------------------------------------------------------------------%
:- pred all_are_const_struct_args(
assoc_list(prog_var, maybe(const_struct_arg))::in,
list(const_struct_arg)::out) is semidet.
all_are_const_struct_args([], []).
all_are_const_struct_args([VarMCA | VarsMCAs], [ConstArg | ConstArgs]) :-
VarMCA = _Var - MCA,
MCA = yes(ConstArg),
all_are_const_struct_args(VarsMCAs, ConstArgs).
:- pred get_inst_of_const_struct_arg(const_struct_db::in, const_struct_arg::in,
mer_inst::out)
is det.
get_inst_of_const_struct_arg(ConstStructDb, ConstArg, Inst) :-
(
ConstArg = csa_constant(ConsId, _),
Inst = bound(shared, inst_test_results_fgtc,
[bound_functor(ConsId, [])])
;
ConstArg = csa_const_struct(StructNum),
lookup_const_struct_num(ConstStructDb, StructNum, Struct),
Struct = const_struct(_, _, _, Inst)
).
%---------------------------------------------------------------------------%
:- pred materialize_base_typeclass_info_var(prog_constraint::in, cons_id::in,
prog_var::out, list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
materialize_base_typeclass_info_var(Constraint, ConsId, Var, Goals, !Info) :-
poly_info_get_const_struct_var_map(!.Info, ConstStructVarMap0),
build_typeclass_info_type(Constraint, ConstArgType),
ConstArg = csa_constant(ConsId, ConstArgType),
( map.search(ConstStructVarMap0, ConstArg, OldVar) ->
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
Var = OldVar,
Goals = []
;
new_typeclass_info_var(Constraint, base_typeclass_info_kind, Var,
_VarType, !Info),
% Create the construction unification to initialize the variable.
RHS = rhs_functor(ConsId, no, []),
Unification = construct(Var, ConsId, [], [],
construct_dynamically, cell_is_shared, no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
UnifyContext = unify_context(umc_explicit, []),
% XXX The UnifyContext is wrong.
Unify = unify(Var, RHS, UnifyMode, Unification, UnifyContext),
% Create the unification goal.
NonLocals = set_of_var.make_singleton(Var),
InstmapDelta = instmap_delta_bind_var(Var),
goal_info_init(NonLocals, InstmapDelta, detism_det, purity_pure,
GoalInfo),
Goal = hlds_goal(Unify, GoalInfo),
Goals = [Goal]
).
:- pred materialize_typeclass_info_var(prog_constraint::in, int::in,
prog_var::out, list(hlds_goal)::out, poly_info::in, poly_info::out) is det.
materialize_typeclass_info_var(Constraint, InstanceIdConstNum, Var, Goals,
!Info) :-
poly_info_get_const_struct_var_map(!.Info, ConstStructVarMap0),
InstanceIdConstArg = csa_const_struct(InstanceIdConstNum),
( map.search(ConstStructVarMap0, InstanceIdConstArg, OldVar) ->
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
Var = OldVar,
Goals = []
;
new_typeclass_info_var(Constraint, typeclass_info_kind, Var, _VarType,
!Info),
map.det_insert(InstanceIdConstArg, Var,
ConstStructVarMap0, ConstStructVarMap),
poly_info_set_const_struct_var_map(ConstStructVarMap, !Info),
% Create the construction unification to initialize the variable.
ConsId = typeclass_info_const(InstanceIdConstNum),
RHS = rhs_functor(ConsId, no, []),
Unification = construct(Var, ConsId, [], [],
construct_statically, cell_is_shared, no_construct_sub_info),
UnifyMode = (free -> ground(shared, none)) -
(ground(shared, none) -> ground(shared, none)),
UnifyContext = unify_context(umc_explicit, []),
% XXX The UnifyContext is wrong.
GoalExpr = unify(Var, RHS, UnifyMode, Unification, UnifyContext),
% Create a goal_info for the unification.
NonLocals = set_of_var.make_singleton(Var),
InstmapDelta = instmap_delta_bind_var(Var),
goal_info_init(NonLocals, InstmapDelta, detism_det, purity_pure,
GoalInfo),
Goal = hlds_goal(GoalExpr, GoalInfo),
Goals = [Goal]
).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- type const_or_var_arg
---> cova_const(const_struct_arg)
; cova_var(prog_var).
:- pred make_const_or_var_arg(pair(prog_var, maybe(const_struct_arg))::in,
const_or_var_arg::out) is det.
make_const_or_var_arg(Var - MCA, ConstOrVarArg) :-
(
MCA = no,
ConstOrVarArg = cova_var(Var)
;
MCA = yes(ConstArg),
ConstOrVarArg = cova_const(ConstArg)
).
:- type type_info_var_map ==
map(type_ctor,
map(list(mer_type), pair(prog_var, maybe(const_struct_arg)))).
:- type typeclass_info_map_entry
---> typeclass_info_map_entry(
% The cons_id representing the base_typeclass_info.
cons_id,
% Maps the arguments of the typeclass_info_cell_constructor
% after the base_typeclass_info to the variable that holds the
% typeclass_info for that cell.
map(list(const_or_var_arg),
pair(prog_var, maybe(const_struct_arg)))
).
:- type typeclass_info_map ==
map(class_name, map(list(mer_type), typeclass_info_map_entry)).
:- type int_const_map == map(int, prog_var).
% If the value that can be a constant structure argument is currently
% available in a variable, give the id of that variable.
%
:- type const_struct_var_map == map(const_struct_arg, prog_var).
:- type poly_info
---> poly_info(
% The first two fields are from the proc_info.
poly_varset :: prog_varset,
poly_vartypes :: vartypes,
% The next two fields from the pred_info.
poly_typevarset :: tvarset,
poly_tvar_kinds :: tvar_kind_map,
% Gives information about the locations of type_infos
% and typeclass_infos.
poly_rtti_varmaps :: rtti_varmaps,
% Specifies why each constraint that was eliminated from the
% pred was able to be eliminated (this allows us to efficiently
% construct the dictionary).
% Note that the rtti_varmaps is separate from the
% constraint_proof_map, since the second is the information
% calculated by typecheck.m, while the first is the information
% calculated here in polymorphism.m.
poly_proof_map :: constraint_proof_map,
% Specifies the constraints at each location in the goal.
poly_constraint_map :: constraint_map,
% The next four maps hold information about what
% type_ctor_infos, type_infos, base_typeclass_infos,
% typeclass_infos and ints are guaranteed to be available
% (i.e. created by previous code on all execution paths)
% at the current point in the code, so they can be reused.
% The fifth field counts the number of times that one of these
% variables has in fact been reused.
%
% The type_infos and typeclass_infos are in the first two maps.
% The type_ctor_infos and base_typeclass_infos are in the
% fourth map. The integers are in the third map.
% The fourth map also caches typeclass_infos for instance ids.
poly_type_info_var_map :: type_info_var_map,
poly_typeclass_info_map :: typeclass_info_map,
poly_int_const_map :: int_const_map,
poly_const_struct_var_map :: const_struct_var_map,
poly_num_reuses :: int,
poly_snapshot_num :: int,
% The database of constant structures of the module.
% If a type_info or typeclass_info we construct is a constant
% term, we allocate it in this database.
poly_const_struct_db :: const_struct_db,
poly_pred_info :: pred_info,
poly_module_info :: module_info
).
%---------------------------------------------------------------------------%
% Init_poly_info initializes a poly_info from a pred_info and clauses_info.
% (See also create_poly_info.)
%
:- pred init_poly_info(module_info::in, pred_info::in, clauses_info::in,
poly_info::out) is det.
init_poly_info(ModuleInfo, PredInfo, ClausesInfo, PolyInfo) :-
clauses_info_get_varset(ClausesInfo, VarSet),
clauses_info_get_vartypes(ClausesInfo, VarTypes),
pred_info_get_typevarset(PredInfo, TypeVarSet),
pred_info_get_tvar_kinds(PredInfo, TypeVarKinds),
pred_info_get_constraint_proofs(PredInfo, Proofs),
pred_info_get_constraint_map(PredInfo, ConstraintMap),
rtti_varmaps_init(RttiVarMaps),
map.init(TypeInfoVarMap),
map.init(TypeClassInfoMap),
map.init(IntConstMap),
map.init(ConstStructVarMap),
NumReuses = 0,
SnapshotNum = 0,
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
PolyInfo = poly_info(VarSet, VarTypes, TypeVarSet, TypeVarKinds,
RttiVarMaps, Proofs, ConstraintMap,
TypeInfoVarMap, TypeClassInfoMap, IntConstMap, ConstStructVarMap,
NumReuses, SnapshotNum, ConstStructDb, PredInfo, ModuleInfo).
% Create_poly_info creates a poly_info for an existing procedure.
% (See also init_poly_info.)
%
create_poly_info(ModuleInfo, PredInfo, ProcInfo, PolyInfo) :-
pred_info_get_typevarset(PredInfo, TypeVarSet),
pred_info_get_tvar_kinds(PredInfo, TypeVarKinds),
pred_info_get_constraint_proofs(PredInfo, Proofs),
pred_info_get_constraint_map(PredInfo, ConstraintMap),
proc_info_get_varset(ProcInfo, VarSet),
proc_info_get_vartypes(ProcInfo, VarTypes),
proc_info_get_rtti_varmaps(ProcInfo, RttiVarMaps),
map.init(TypeInfoVarMap),
map.init(TypeClassInfoMap),
map.init(IntConstMap),
map.init(ConstStructVarMap),
NumReuses = 0,
SnapshotNum = 0,
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
PolyInfo = poly_info(VarSet, VarTypes, TypeVarSet, TypeVarKinds,
RttiVarMaps, Proofs, ConstraintMap, TypeInfoVarMap,
TypeClassInfoMap, IntConstMap, ConstStructVarMap,
NumReuses, SnapshotNum, ConstStructDb, PredInfo, ModuleInfo).
poly_info_extract(Info, !PredInfo, !ProcInfo, !:ModuleInfo) :-
Info = poly_info(VarSet, VarTypes, TypeVarSet, TypeVarKinds,
RttiVarMaps, _Proofs, _ConstraintMap,
_TypeInfoVarMap, _TypeClassInfoMap, _IntConstMap, _ConstStructVarMap,
_NumReuses, _SnapshotNum, ConstStructDb, _OldPredInfo, !:ModuleInfo),
module_info_set_const_struct_db(ConstStructDb, !ModuleInfo),
% Set the new values of the fields in proc_info and pred_info.
proc_info_set_varset(VarSet, !ProcInfo),
proc_info_set_vartypes(VarTypes, !ProcInfo),
proc_info_set_rtti_varmaps(RttiVarMaps, !ProcInfo),
pred_info_set_typevarset(TypeVarSet, !PredInfo),
pred_info_set_tvar_kinds(TypeVarKinds, !PredInfo).
%---------------------------------------------------------------------------%
:- pred poly_info_get_varset(poly_info::in, prog_varset::out) is det.
:- pred poly_info_get_var_types(poly_info::in, vartypes::out) is det.
:- pred poly_info_get_typevarset(poly_info::in, tvarset::out) is det.
:- pred poly_info_get_tvar_kinds(poly_info::in, tvar_kind_map::out) is det.
:- pred poly_info_get_rtti_varmaps(poly_info::in, rtti_varmaps::out) is det.
:- pred poly_info_get_proofs(poly_info::in, constraint_proof_map::out) is det.
:- pred poly_info_get_constraint_map(poly_info::in, constraint_map::out)
is det.
:- pred poly_info_get_type_info_var_map(poly_info::in,
type_info_var_map::out) is det.
:- pred poly_info_get_typeclass_info_map(poly_info::in,
typeclass_info_map::out) is det.
:- pred poly_info_get_int_const_map(poly_info::in, int_const_map::out) is det.
:- pred poly_info_get_num_reuses(poly_info::in, int::out) is det.
:- pred poly_info_get_const_struct_db(poly_info::in, const_struct_db::out)
is det.
:- pred poly_info_get_const_struct_var_map(poly_info::in,
const_struct_var_map::out) is det.
:- pred poly_info_get_pred_info(poly_info::in, pred_info::out) is det.
:- pred poly_info_get_module_info(poly_info::in, module_info::out) is det.
poly_info_get_varset(PolyInfo, PolyInfo ^ poly_varset).
poly_info_get_var_types(PolyInfo, PolyInfo ^ poly_vartypes).
poly_info_get_typevarset(PolyInfo, PolyInfo ^ poly_typevarset).
poly_info_get_tvar_kinds(PolyInfo, PolyInfo ^ poly_tvar_kinds).
poly_info_get_rtti_varmaps(PolyInfo, PolyInfo ^ poly_rtti_varmaps).
poly_info_get_proofs(PolyInfo, PolyInfo ^ poly_proof_map).
poly_info_get_constraint_map(PolyInfo, PolyInfo ^ poly_constraint_map).
poly_info_get_type_info_var_map(PolyInfo, PolyInfo ^ poly_type_info_var_map).
poly_info_get_typeclass_info_map(PolyInfo, PolyInfo ^ poly_typeclass_info_map).
poly_info_get_int_const_map(PolyInfo, PolyInfo ^ poly_int_const_map).
poly_info_get_num_reuses(PolyInfo, PolyInfo ^ poly_num_reuses).
poly_info_get_const_struct_db(PolyInfo, PolyInfo ^ poly_const_struct_db).
poly_info_get_const_struct_var_map(PolyInfo,
PolyInfo ^ poly_const_struct_var_map).
poly_info_get_pred_info(PolyInfo, PolyInfo ^ poly_pred_info).
poly_info_get_module_info(PolyInfo, PolyInfo ^ poly_module_info).
:- pred poly_info_set_varset(prog_varset::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_varset_and_types(prog_varset::in, vartypes::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_typevarset(tvarset::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_tvar_kinds(tvar_kind_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_rtti_varmaps(rtti_varmaps::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_proofs(constraint_proof_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_type_info_var_map(type_info_var_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_typeclass_info_map(typeclass_info_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_int_const_map(int_const_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_num_reuses(int::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_const_struct_db(const_struct_db::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_const_struct_var_map(const_struct_var_map::in,
poly_info::in, poly_info::out) is det.
poly_info_set_varset(VarSet, !PI) :-
!PI ^ poly_varset := VarSet.
poly_info_set_varset_and_types(VarSet, VarTypes, !PI) :-
!PI ^ poly_varset := VarSet,
!PI ^ poly_vartypes := VarTypes.
poly_info_set_typevarset(TVarSet, !PI) :-
!PI ^ poly_typevarset := TVarSet.
poly_info_set_tvar_kinds(TVarKinds, !PI) :-
!PI ^ poly_tvar_kinds := TVarKinds.
poly_info_set_rtti_varmaps(RttiVarMaps, !PI) :-
!PI ^ poly_rtti_varmaps := RttiVarMaps.
poly_info_set_proofs(Proofs, !PI) :-
!PI ^ poly_proof_map := Proofs.
poly_info_set_type_info_var_map(TypeInfoVarMap, !PI) :-
!PI ^ poly_type_info_var_map := TypeInfoVarMap.
poly_info_set_typeclass_info_map(TypeClassInfoMap, !PI) :-
!PI ^ poly_typeclass_info_map := TypeClassInfoMap.
poly_info_set_int_const_map(IntConstMap, !PI) :-
!PI ^ poly_int_const_map := IntConstMap.
poly_info_set_num_reuses(NumReuses, !PI) :-
!PI ^ poly_num_reuses := NumReuses.
poly_info_set_const_struct_db(ConstStructDb, !PI) :-
!PI ^ poly_const_struct_db := ConstStructDb.
poly_info_set_const_struct_var_map(ConstStructVarMap, !PI) :-
!PI ^ poly_const_struct_var_map := ConstStructVarMap.
%---------------------------------------------------------------------------%
:- type cache_maps
---> cache_maps(
cm_snapshot_num :: int,
cm_type_info_var_map :: type_info_var_map,
cm_typeclass_info_map :: typeclass_info_map,
cm_int_const_map :: int_const_map,
cm_const_struct_var_map :: const_struct_var_map
).
:- pred get_cache_maps_snapshot(string::in, cache_maps::out,
poly_info::in, poly_info::out) is det.
:- pred set_cache_maps_snapshot(string::in, cache_maps::in,
poly_info::in, poly_info::out) is det.
:- pred empty_cache_maps(poly_info::in, poly_info::out) is det.
get_cache_maps_snapshot(Name, CacheMaps, !Info) :-
SnapshotNum = !.Info ^ poly_snapshot_num,
TypeInfoVarMap = !.Info ^ poly_type_info_var_map,
TypeClassInfoMap = !.Info ^ poly_typeclass_info_map,
IntConstMap = !.Info ^ poly_int_const_map,
ConstStructVarMap = !.Info ^ poly_const_struct_var_map,
CacheMaps = cache_maps(SnapshotNum, TypeInfoVarMap, TypeClassInfoMap,
IntConstMap, ConstStructVarMap),
!Info ^ poly_snapshot_num := SnapshotNum + 1,
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
(
SelectedPred = yes,
Name \= ""
->
IndentStr = string.duplicate_char(' ', Level * 4),
io.write_string(IndentStr, !IO),
io.format("get_cache_maps_snapshot %d %s\n",
[i(SnapshotNum), s(Name)], !IO),
io.write_string(IndentStr, !IO),
NumVars = varset.num_allocated(!.Info ^ poly_varset),
io.format("num_allocated vars: %d\n\n", [i(NumVars)], !IO)
;
true
)
)
)
).
set_cache_maps_snapshot(Name, CacheMaps, !Info) :-
CacheMaps = cache_maps(SnapshotNum, TypeInfoVarMap, TypeClassInfoMap,
IntConstMap, ConstStructVarMap),
!Info ^ poly_type_info_var_map := TypeInfoVarMap,
!Info ^ poly_typeclass_info_map := TypeClassInfoMap,
!Info ^ poly_int_const_map := IntConstMap,
!Info ^ poly_const_struct_var_map := ConstStructVarMap,
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
(
SelectedPred = yes,
Name \= ""
->
IndentStr = string.duplicate_char(' ', Level * 4),
io.write_string(IndentStr, !IO),
io.format("set_cache_maps_snapshot %d %s\n",
[i(SnapshotNum), s(Name)], !IO),
io.write_string(IndentStr, !IO),
NumVars = varset.num_allocated(!.Info ^ poly_varset),
io.format("num_allocated vars: %d\n\n", [i(NumVars)], !IO),
io.write_string(IndentStr, !IO),
io.write_string("type_info_var_map ", !IO),
io.write(CacheMaps ^ cm_type_info_var_map, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("typeclass_info_map ", !IO),
io.write(CacheMaps ^ cm_typeclass_info_map, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("struct_var_map ", !IO),
io.write(CacheMaps ^ cm_const_struct_var_map, !IO),
io.nl(!IO),
io.nl(!IO)
;
true
)
)
)
).
empty_cache_maps(!Info) :-
!Info ^ poly_type_info_var_map := map.init,
!Info ^ poly_typeclass_info_map := map.init,
!Info ^ poly_int_const_map := map.init,
!Info ^ poly_const_struct_var_map := map.init.
%---------------------------------------------------------------------------%
:- type var_maps
---> var_maps(
vm_snapshot_num :: int,
vm_varset :: prog_varset,
vm_vartypes :: vartypes,
vm_rtti_varmaps :: rtti_varmaps,
vm_cache_maps :: cache_maps
).
:- pred get_var_maps_snapshot(string::in, var_maps::out,
poly_info::in, poly_info::out) is det.
get_var_maps_snapshot(Name, VarMaps, !Info) :-
SnapshotNum = !.Info ^ poly_snapshot_num,
VarSet = !.Info ^ poly_varset,
VarTypes = !.Info ^ poly_vartypes,
RttiVarMaps = !.Info ^ poly_rtti_varmaps,
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', Level * 4),
io.write_string(IndentStr, !IO),
io.format("get_var_maps_snapshot %d %s\n",
[i(SnapshotNum), s(Name)], !IO),
io.write_string(IndentStr, !IO),
NumVars = varset.num_allocated(VarSet),
io.format("num_allocated vars: %d\n\n", [i(NumVars)], !IO)
)
)
)
),
get_cache_maps_snapshot("", CacheMaps, !Info),
VarMaps = var_maps(SnapshotNum, VarSet, VarTypes, RttiVarMaps, CacheMaps).
:- pred set_var_maps_snapshot(string::in, var_maps::in,
poly_info::in, poly_info::out) is det.
set_var_maps_snapshot(Name, VarMaps, !Info) :-
VarMaps = var_maps(SnapshotNum, VarSet, VarTypes, RttiVarMaps, CacheMaps),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
some [SelectedPred, Level, IndentStr] (
promise_pure (
semipure get_selected_pred(SelectedPred),
semipure get_level(Level),
(
SelectedPred = no
;
SelectedPred = yes,
IndentStr = string.duplicate_char(' ', Level * 4),
io.write_string(IndentStr, !IO),
io.format("set_var_maps_snapshot %d %s\n",
[i(SnapshotNum), s(Name)], !IO),
io.write_string(IndentStr, !IO),
io.write_string("type_info_var_map ", !IO),
io.write(CacheMaps ^ cm_type_info_var_map, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("typeclass_info_map ", !IO),
io.write(CacheMaps ^ cm_typeclass_info_map, !IO),
io.nl(!IO),
io.write_string(IndentStr, !IO),
io.write_string("struct_var_map ", !IO),
io.write(CacheMaps ^ cm_const_struct_var_map, !IO),
io.nl(!IO),
io.nl(!IO)
)
)
)
),
!Info ^ poly_varset := VarSet,
!Info ^ poly_vartypes := VarTypes,
!Info ^ poly_rtti_varmaps := RttiVarMaps,
set_cache_maps_snapshot("", CacheMaps, !Info).
%---------------------------------------------------------------------------%
:- end_module check_hlds.polymorphism.
%---------------------------------------------------------------------------%