Files
mercury/compiler/polymorphism.m
Fergus Henderson 5e86fb5715 Fix some bugs in the handling of "non-simple" type class constraints
Estimated hours taken: 12

Fix some bugs in the handling of "non-simple" type class constraints
(ones for which the types being constrained are not just type variables).

compiler/prog_io_typeclass.m:
	Ensure that constraints on type class declarations must be "simple".
	This is needed the ensure termination of type checking.
	(We already did this for instance declarations, but not for
	superclass constraints on type class declarations.)

compiler/prog_data.m:
	Document the invariant that the types in a type class constraint
	must not contain any information in their term__context fields.

compiler/type_util.m:
compiler/equiv_type.m:
compiler/polymorphism.m:
compiler/prog_io_typeclass.m:
	Enforce the above-mentioned invariant.

compiler/typecheck.m:
	Allow the declared constraints to be a superset of the
	inferred constraints.
	When performing context reduction, eliminate declared
	constraints at each step rather than only at the end.
	Remove declared constraints and apply superclass rules
	before applying instance rules.
	When applying instance rules, make sure that it is a type
	error if there is no matching instance rule for a ground
	constraint.
	If context reduction results in an error, restore the
	original type assign set, to avoid repeating the same
	error message at every subsequent call to perform_context_reduction.

compiler/check_typeclass.m:
	Change the way we superclass conformance for instance declarations
	to take advantage of the new "DeclaredConstraints" argument to
	typecheck__reduce_context_by_rule_application.
1998-04-08 15:23:35 +00:00

2489 lines
89 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995-1998 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 author: fjh
% This module is a pass over the HLDS.
% It does a syntactic transformation to implement polymorphism, including
% typeclasses, using higher-order predicates, and also invokes
% `lambda__transform_lambda' to handle lambda expressions by creating new
% predicates for them.
%
%-----------------------------------------------------------------------------%
%
% Tranformation 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, index/2).
%
%-----------------------------------------------------------------------------%
%
% Representation of type information:
%
% IMPORTANT: ANY CHANGES TO THE DOCUMENTATION HERE MUST BE REFLECTED BY
% SIMILAR CHANGES TO THE #defines IN "runtime/type_info.h"
% AND VICE VERSA.
%
% Type information is represented using one or two cells. The cell which
% is always present is the base_type_info structure, laid out like this:
%
% word 0 <arity of type constructor>
% e.g. 0 for `int', 1 for `list(T)', 2 for `map(K, V)'.
% word 1 <=/2 predicate for type>
% word 2 <index/2 predicate for type>
% word 3 <compare/3 predicate for type>
% word 4 <base_type_layout for type>
% word 5 <base_type_functors for type>
% word 6 <string name of type constructor>
% e.g. "int" for `int', "list" for `list(T)',
% "map" for `map(K,V)'
% word 7 <string name of module>
%
% The other cell is the type_info structure, laid out like this:
%
% word 0 <pointer to the base_type_info structure>
% word 1+ <the type_infos for the type params, at least one>
%
% (but see note below for how higher order 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 base_type_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
% base_type_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 base_type_info structure.
%
%-----------------------------------------------------------------------------%
%
% Higher order types:
%
% There is a slight variation on this for higher-order types. Higher
% order type_infos always have a pointer to the pred/0 base_type_info,
% regardless of their true arity, so we store the real arity in the
% type-info as well.
%
% word 0 <pointer to the base_type_info structure (pred/0)>
% word 1 <arity of predicate>
% word 2+ <the type_infos for the type params, at least one>
%
%-----------------------------------------------------------------------------%
%
% Sharing base_type_info structures:
%
% For compilation models that can put code addresses in static ground terms,
% we can arrange to create one copy of the base_type_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 base_type_info, but initialize its code
% addresses during startup (that is, during the module
% initialization code).
%
% Currently we use option 2.
%
%-----------------------------------------------------------------------------%
%
% Example of transformation:
%
% Take the following code as an example, ignoring the requirement for
% super-homogeneous 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) :-
% BaseTypeInfoT2 = base_type_info(
% 1,
% '__Unify__'<list/1>,
% '__Index__'<list/1>,
% '__Compare__'<list/1>,
% <base_type_layout for list/1>,
% <base_type_functors for list/1>,
% "list",
% "list"),
% TypeInfoT2 = type_info(
% BaseTypeInfoT2,
% TypeInfoT1),
% q(TypeInfoT2, [X]),
% TypeInfoT3 = base_type_info(
% 0,
% builtin_unify_int,
% builtin_index_int,
% builtin_compare_int,
% <base_type_layout for int/0>,
% <base_type_functors for int/0>,
% "int",
% "mercury_builtin"),
% r(TypeInfoT3, 0).
%
% Note that base_type_infos are actually generated as references to a
% single shared base_type_info.
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
%
% Tranformation of code using typeclasses:
%
% Every predicate which has a typeclass constraint is given an extra
% argument for every constraint in the predicate's type declaration.
% The argument is the "dictionary", or "typeclass_info" for the typeclass.
% The dictionary contains pointers to each of the class methods.
%
%-----------------------------------------------------------------------------%
%
% Representation of a typeclass_info:
% The typeclass_info is represented in two parts (the typeclass_info
% itself, and a base_typeclass_info), in a similar fashion to the
% type_info being represented in two parts (the type_info and the
% base_type_info).
%
% The base_typeclass_info contains:
% * the number of constraints on the instance decl.
% * pointer to method #1
% ...
% * pointer to method #n
%
% The typeclass_info contains:
% * a pointer to the base typeclass info
% * typeclass info #1 for constraint on instance decl
% * ...
% * typeclass info #n for constraint on instance decl
% * typeclass info for superclass #1
% ...
% * typeclass info for superclass #n
% * type info #1
% * ...
% * type info #n
%
% The base_type_info is produced statically, and there is one for each instance
% declaration. For each constraint on the instance declaration, the
% corresponding typeclass info is stored in the second part.
%
% eg. for the following program:
%
% :- typeclass foo(T) where [...].
% :- instance foo(int) where [...].
% :- instance foo(list(T)) <= foo(T) where [...].
%
% The typeclass_info for foo(int) is:
% The base_type_info:
% * 0 (arity of the instance declaration)
% * pointer to method #1
% ...
% * pointer to method #n
%
% The type_info:
% * a pointer to the base typeclass info
% * type info for int
%
% The typeclass_info for foo(list(T)) is:
% The base_type_info:
% * 1 (arity of the instance declaration)
% * pointer to method #1
% ...
% * pointer to method #n
%
% The type_info contains:
% * a pointer to the base typeclass info
% * typeclass info for foo(T)
% * type info for list(T)
%
% If the "T" for the list is known, the whole typeclass_info will be static
% data. When we do not know until runtime, the typeclass_info is constructed
% dynamically.
%
%-----------------------------------------------------------------------------%
%
% Example of transformation:
%
% Take the following code as an example (assuming the declarations above),
% ignoring the requirement for super-homogeneous form for clarity:
%
% :- pred p(T1) <= foo(T1).
% :- pred q(T2, T3) <= foo(T2), bar(T3).
% :- pred r(T4, T5) <= foo(T4).
%
% p(X) :- q([X], 0), r(X, 0).
%
% We add an extra argument for each typeclass constraint, and one argument for
% each unconstrained type variable.
%
% :- pred p(typeclass_info(foo(T1)), T1).
% :- pred q(typeclass_info(foo(T2)), typeclass_info(bar(T3)), T2, T3).
% :- pred r(typeclass_info(foo(T4)), type_info(T5), T4, T5).
%
% We transform the body of p to this:
%
% p(TypeClassInfoT1, X) :-
% BaseTypeClassInfoT2 = base_typeclass_info(
% 1,
% ...
% ... (The methods for the foo class from the list
% ... instance)
% ...
% ),
% TypeClassInfoT2 = typeclass_info(
% BaseClassTypeInfoT2,
% TypeClassInfoT1,
% <type_info for list(T1)>),
% BaseTypeClassInfoT3 = base_typeclass_info(
% 0,
% ...
% ... (The methods for the bar class from the int
% ... instance)
% ...
% ),
% TypeClassInfoT3 = typeclass_info(
% BaseClassTypeInfoT3,
% <type_info for int>),
% q(TypeClassInfoT2, TypeClassInfoT3, [X], 0),
% BaseTypeClassInfoT4 = baseclass_type_info(
% 0,
% ...
% ... (The methods for the foo class from the int
% ... instance)
% ...
% ),
% TypeClassInfoT4 = typeclass_info(
% BaseTypeClassInfoT4,
% <type_info for int>),
% r(TypeClassInfoT1, <type_info for int>, X, 0).
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module polymorphism.
:- interface.
:- import_module hlds_module.
:- import_module io.
:- pred polymorphism__process_module(module_info, module_info,
io__state, io__state).
:- mode polymorphism__process_module(in, out, di, uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_pred, hlds_goal, hlds_data, llds, (lambda).
:- import_module prog_data, type_util, mode_util, quantification, instmap.
:- import_module code_util, unify_proc, special_pred, prog_util, make_hlds.
:- import_module (inst), hlds_out, base_typeclass_info, goal_util, passes_aux.
:- import_module bool, int, string, list, set, map.
:- import_module term, varset, std_util, require, assoc_list.
%-----------------------------------------------------------------------------%
% This whole section just traverses the module structure.
% We do two passes, the first to fix up the procedure bodies,
% (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(ModuleInfo0, ModuleInfo, IO0, IO) :-
module_info_preds(ModuleInfo0, Preds0),
map__keys(Preds0, PredIds0),
polymorphism__process_preds(PredIds0, ModuleInfo0, ModuleInfo1,
IO0, IO),
module_info_preds(ModuleInfo1, Preds1),
map__keys(Preds1, PredIds1),
polymorphism__fixup_preds(PredIds1, ModuleInfo1, ModuleInfo2),
polymorphism__expand_class_method_bodies(ModuleInfo2, ModuleInfo).
:- pred polymorphism__process_preds(list(pred_id), module_info, module_info,
io__state, io__state).
:- mode polymorphism__process_preds(in, in, out, di, uo) is det.
polymorphism__process_preds([], ModuleInfo, ModuleInfo) --> [].
polymorphism__process_preds([PredId | PredIds], ModuleInfo0, ModuleInfo) -->
polymorphism__process_pred(PredId, ModuleInfo0, ModuleInfo1),
polymorphism__process_preds(PredIds, ModuleInfo1, ModuleInfo).
:- pred polymorphism__process_pred(pred_id, module_info, module_info,
io__state, io__state).
:- mode polymorphism__process_pred(in, in, out, di, uo) is det.
polymorphism__process_pred(PredId, ModuleInfo0, ModuleInfo, IO0, IO) :-
module_info_pred_info(ModuleInfo0, PredId, PredInfo),
pred_info_module(PredInfo, PredModule),
pred_info_name(PredInfo, PredName),
pred_info_arity(PredInfo, PredArity),
(
polymorphism__no_type_info_builtin(PredModule,
PredName, PredArity)
->
ModuleInfo = ModuleInfo0,
IO = IO0
;
pred_info_procids(PredInfo, ProcIds),
polymorphism__process_procs(PredId, ProcIds,
ModuleInfo0, ModuleInfo, IO0, IO)
).
:- pred polymorphism__process_procs(pred_id, list(proc_id),
module_info, module_info,
io__state, io__state).
:- mode polymorphism__process_procs(in, in, in, out, di, uo) is det.
polymorphism__process_procs(_PredId, [], ModuleInfo, ModuleInfo, IO, IO).
polymorphism__process_procs(PredId, [ProcId | ProcIds], ModuleInfo0,
ModuleInfo, IO0, IO) :-
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
map__lookup(ProcTable0, ProcId, ProcInfo0),
write_proc_progress_message("% Transforming polymorphism for ",
PredId, ProcId, ModuleInfo0, IO0, IO1),
polymorphism__process_proc(ProcInfo0, PredInfo0, ModuleInfo0,
ProcInfo, PredInfo1, ModuleInfo1),
pred_info_procedures(PredInfo1, ProcTable1),
map__det_update(ProcTable1, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo1, ProcTable, PredInfo),
module_info_preds(ModuleInfo1, PredTable1),
map__det_update(PredTable1, PredId, PredInfo, PredTable),
module_info_set_preds(ModuleInfo1, PredTable, ModuleInfo2),
polymorphism__process_procs(PredId, ProcIds, ModuleInfo2, ModuleInfo,
IO1, IO).
% unsafe_type_cast and unsafe_promise_unique are polymorphic
% builtins which do not need their type_infos. unsafe_type_cast
% can be introduced by common.m after polymorphism is run, so it
% is much simpler to avoid introducing type_info arguments for it.
% Since both of these are really just assignment unifications, it
% is desirable to generate them inline.
:- pred polymorphism__no_type_info_builtin(module_name, string, int).
:- mode polymorphism__no_type_info_builtin(in, in, out) is semidet.
polymorphism__no_type_info_builtin(MercuryBuiltin, "unsafe_type_cast", 2) :-
mercury_private_builtin_module(MercuryBuiltin).
polymorphism__no_type_info_builtin(MercuryBuiltin,
"unsafe_promise_unique", 2) :-
mercury_private_builtin_module(MercuryBuiltin).
%---------------------------------------------------------------------------%
:- pred polymorphism__fixup_preds(list(pred_id), module_info, module_info).
:- mode polymorphism__fixup_preds(in, in, out) is det.
polymorphism__fixup_preds([], ModuleInfo, ModuleInfo).
polymorphism__fixup_preds([PredId | PredIds], ModuleInfo0, ModuleInfo) :-
%
% Recompute the arg types by finding the headvars and the var->type
% mapping (from the first procedure for the predicate) 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_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_procedures(PredInfo0, ProcTable0),
pred_info_procids(PredInfo0, ProcIds),
( ProcIds = [ProcId | _] ->
map__lookup(ProcTable0, ProcId, ProcInfo),
proc_info_vartypes(ProcInfo, VarTypes),
proc_info_headvars(ProcInfo, HeadVars),
pred_info_arg_types(PredInfo0, TypeVarSet, ArgTypes0),
list__length(ArgTypes0, NumOldArgs),
list__length(HeadVars, NumNewArgs),
NumExtraArgs is NumNewArgs - NumOldArgs,
(
list__split_list(NumExtraArgs, HeadVars, ExtraHeadVars,
_OldHeadVars)
->
map__apply_to_list(ExtraHeadVars, VarTypes,
ExtraArgTypes),
list__append(ExtraArgTypes, ArgTypes0, ArgTypes)
;
error("polymorphism.m: list__split_list failed")
),
pred_info_set_arg_types(PredInfo0, TypeVarSet, ArgTypes,
PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(ModuleInfo0, PredTable, ModuleInfo1)
;
ModuleInfo1 = ModuleInfo0
),
polymorphism__fixup_preds(PredIds, ModuleInfo1, ModuleInfo).
%---------------------------------------------------------------------------%
:- type poly_info --->
poly_info(
varset, % from the proc_info
map(var, type), % from the proc_info
tvarset, % from the proc_info
map(tvar, type_info_locn),
% specifies the location of
% the type_info var
% for each of the pred's type
% parameters
map(class_constraint, var),
% specifies the location of
% the typeclass_info var
% for each of the pred's class
% constraints
map(class_constraint, constraint_proof),
% 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 two maps above
% are separate since the second
% is the information calculated
% by typecheck.m, while the
% first is the information
% calculated here in
% polymorphism.m
string, % pred name
module_info
).
:- pred polymorphism__process_proc(proc_info, pred_info, module_info,
proc_info, pred_info, module_info).
:- mode polymorphism__process_proc(in, in, in, out, out, out) is det.
polymorphism__process_proc(ProcInfo0, PredInfo0, ModuleInfo0,
ProcInfo, PredInfo, ModuleInfo) :-
% grab the appropriate fields from the pred_info and proc_info
pred_info_arg_types(PredInfo0, ArgTypeVarSet, ArgTypes),
pred_info_typevarset(PredInfo0, TypeVarSet0),
pred_info_get_class_context(PredInfo0, ClassContext),
pred_info_get_constraint_proofs(PredInfo0, Proofs),
pred_info_name(PredInfo0, PredName),
proc_info_headvars(ProcInfo0, HeadVars0),
proc_info_varset(ProcInfo0, VarSet0),
proc_info_vartypes(ProcInfo0, VarTypes0),
proc_info_goal(ProcInfo0, Goal0),
proc_info_argmodes(ProcInfo0, ArgModes0),
% 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).
term__vars_list(ArgTypes, HeadTypeVars0),
% 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.
polymorphism__make_typeclass_info_head_vars(ClassContext, ModuleInfo0,
VarSet0, VarTypes0, ExtraHeadTypeclassInfoVars,
TypeClassInfoMap, ConstrainedTVars,
VarSet1, VarTypes1),
list__delete_elems(HeadTypeVars0, ConstrainedTVars,
UnconstrainedTVars0),
list__remove_dups(UnconstrainedTVars0, UnconstrainedTVars),
polymorphism__make_head_vars(UnconstrainedTVars, ArgTypeVarSet,
VarSet1, VarTypes1, ExtraHeadTypeInfoVars, VarSet2, VarTypes2),
% First the type_infos, then the typeclass_infos,
% but we have to do it in reverse because we're appending...
list__append(ExtraHeadTypeclassInfoVars, HeadVars0, HeadVars1),
list__append(ExtraHeadTypeInfoVars, HeadVars1, HeadVars),
% Work out the total number of new vars
list__length(ExtraHeadTypeInfoVars, NumExtraVars0),
list__length(ExtraHeadTypeclassInfoVars, NumExtraVars1),
NumExtraVars is NumExtraVars1 + NumExtraVars0,
in_mode(In),
list__duplicate(NumExtraVars, In, ExtraModes),
list__append(ExtraModes, ArgModes0, ArgModes),
% Make a map of the locations of the unconstrained typeinfos
AddLocn = lambda([TVarAndVar::in, TIM0::in, TIM::out] is det,
(
TVarAndVar = TVar - TheVar,
map__det_insert(TIM0, TVar, type_info(TheVar), TIM)
)),
assoc_list__from_corresponding_lists(UnconstrainedTVars,
ExtraHeadTypeInfoVars, TVarsAndVars),
list__foldl(AddLocn, TVarsAndVars, TypeClassInfoMap, TypeInfoMap1),
% Make a map of the locations of the typeclass_infos
map__from_corresponding_lists(ClassContext, ExtraHeadTypeclassInfoVars,
TypeclassInfoLocations0),
Info0 = poly_info(VarSet2, VarTypes2, TypeVarSet0,
TypeInfoMap1, TypeclassInfoLocations0,
Proofs, PredName, ModuleInfo0),
% process any polymorphic calls inside the goal
polymorphism__process_goal(Goal0, Goal1, Info0, Info1),
polymorphism__fixup_quantification(Goal1, Goal, _, Info1, Info),
Info = poly_info(VarSet, VarTypes, TypeVarSet,
TypeInfoMap, TypeclassInfoLocations,
_Proofs, _PredName, ModuleInfo),
% set the new values of the fields in proc_info and pred_info
proc_info_set_headvars(ProcInfo0, HeadVars, ProcInfo1),
proc_info_set_goal(ProcInfo1, Goal, ProcInfo2),
proc_info_set_varset(ProcInfo2, VarSet, ProcInfo3),
proc_info_set_vartypes(ProcInfo3, VarTypes, ProcInfo4),
proc_info_set_argmodes(ProcInfo4, ArgModes, ProcInfo5),
proc_info_set_typeinfo_varmap(ProcInfo5, TypeInfoMap, ProcInfo6),
proc_info_set_typeclass_info_varmap(ProcInfo6, TypeclassInfoLocations,
ProcInfo),
pred_info_set_typevarset(PredInfo0, TypeVarSet, PredInfo).
:- pred polymorphism__process_goal(hlds_goal, hlds_goal,
poly_info, poly_info).
:- mode polymorphism__process_goal(in, out, in, out) is det.
polymorphism__process_goal(Goal0 - GoalInfo0, Goal) -->
polymorphism__process_goal_expr(Goal0, GoalInfo0, Goal).
:- pred polymorphism__process_goal_expr(hlds_goal_expr, hlds_goal_info,
hlds_goal, poly_info, poly_info).
:- mode polymorphism__process_goal_expr(in, in, out, in, out) is det.
% 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. (Or at least I
% think we don't... -fjh.)
polymorphism__process_goal_expr(higher_order_call(A, B, C, D, E, F),
GoalInfo, higher_order_call(A, B, C, D, E, F) - GoalInfo)
--> [].
% The same goes for class method calls
polymorphism__process_goal_expr(class_method_call(A, B, C, D, E, F),
GoalInfo, class_method_call(A, B, C, D, E, F) - GoalInfo)
--> [].
polymorphism__process_goal_expr(call(PredId0, ProcId0, ArgVars0,
Builtin, Context, Name0), GoalInfo, Goal) -->
% Check for a call to a special predicate like compare/3
% for which the type is known at compile-time.
% Replace such calls with calls to the particular version
% for that type.
(
{ Name0 = unqualified(PredName0) },
{ list__length(ArgVars0, Arity) },
{ special_pred_name_arity(SpecialPredId, PredName0,
MangledPredName, Arity) },
=(poly_info(_, VarTypes, _, _, _, _, _, ModuleInfo)),
{ special_pred_get_type(MangledPredName, ArgVars0, MainVar) },
{ map__lookup(VarTypes, MainVar, Type) },
{ Type \= term__variable(_) },
% don't try this for any special preds if they're not
% implemented
{ special_pred_list(SpecialPredIds) },
{ list__member(SpecialPredId, SpecialPredIds) }
->
{ classify_type(Type, ModuleInfo, TypeCategory) },
{ polymorphism__get_special_proc(TypeCategory, Type,
SpecialPredId, ModuleInfo, Name, PredId1, ProcId1) }
;
{ PredId1 = PredId0 },
{ ProcId1 = ProcId0 },
{ Name = Name0 }
),
polymorphism__process_call(PredId1, ProcId1, ArgVars0,
PredId, ProcId, ArgVars, ExtraVars, ExtraGoals),
{ goal_info_get_nonlocals(GoalInfo, NonLocals0) },
{ set__insert_list(NonLocals0, ExtraVars, NonLocals) },
{ goal_info_set_nonlocals(GoalInfo, NonLocals, CallGoalInfo) },
{ Call = call(PredId, ProcId, ArgVars, Builtin, Context, Name)
- CallGoalInfo },
{ list__append(ExtraGoals, [Call], GoalList) },
{ conj_list_to_goal(GoalList, GoalInfo, Goal) }.
polymorphism__process_goal_expr(unify(XVar, Y, Mode, Unification, Context),
GoalInfo, Goal) -->
(
{ Unification = complicated_unify(UniMode, CanFail) },
{ Y = var(YVar) }
->
=(poly_info(_, VarTypes, _, TypeInfoMap, _, _, _, ModuleInfo)),
{ map__lookup(VarTypes, XVar, Type) },
( { Type = term__variable(TypeVar) } ->
% Convert polymorphic unifications into calls to
% `unify/2', the general unification predicate, passing
% the appropriate Type_info
% =(TypeInfoVar, X, Y)
% where TypeInfoVar is the type_info variable
% associated with the type of the variables that
% are being unified.
{ module_info_get_predicate_table(ModuleInfo,
PredicateTable) },
{ mercury_public_builtin_module(MercuryBuiltin) },
{ predicate_table_search_pred_m_n_a(PredicateTable,
MercuryBuiltin, "unify", 2, [CallPredId])
->
PredId = CallPredId
;
error("polymorphism.m: can't find `mercury_builtin:unify/2'")
},
% XXX Bug! - we should check that the mode is (in, in),
% and report an error (e.g. "unification of
% polymorphically typed variables in partially
% instantiated mode") if it isn't
{ hlds_pred__in_in_unification_proc_id(ProcId) },
{ map__lookup(TypeInfoMap, TypeVar, TypeInfoLocn) },
{ SymName = unqualified("unify") },
{ code_util__builtin_state(ModuleInfo, PredId, ProcId,
BuiltinState) },
{ CallContext = call_unify_context(XVar, Y, Context) },
(
% If the typeinfo is available in a
% variable, just use it
{ TypeInfoLocn = type_info(TypeInfoVar) },
{ ArgVars = [TypeInfoVar, XVar, YVar] },
{ Goal = call(PredId, ProcId, ArgVars,
BuiltinState, yes(CallContext), SymName)
- GoalInfo }
;
% If the typeinfo is in a
% typeclass_info, first extract it,
% then use it
{ TypeInfoLocn =
typeclass_info(TypeClassInfoVar,
Index) },
extract_type_info(Type, TypeVar,
TypeClassInfoVar, Index,
Goals, TypeInfoVar),
{ ArgVars = [TypeInfoVar, XVar, YVar] },
{ Call = call(PredId, ProcId, ArgVars,
BuiltinState, yes(CallContext), SymName)
- GoalInfo },
{ list__append(Goals, [Call], TheGoals) },
{ Goal = conj(TheGoals) - GoalInfo }
)
; { type_is_higher_order(Type, _, _) } ->
{ SymName = unqualified("builtin_unify_pred") },
{ ArgVars = [XVar, YVar] },
{ module_info_get_predicate_table(ModuleInfo,
PredicateTable) },
{
mercury_private_builtin_module(PrivateBuiltin),
predicate_table_search_pred_m_n_a(
PredicateTable,
PrivateBuiltin, "builtin_unify_pred", 2,
[PredId0])
->
PredId = PredId0
;
error("can't locate mercury_builtin:builtin_unify_pred/2")
},
{ hlds_pred__in_in_unification_proc_id(ProcId) },
{ CallContext = call_unify_context(XVar, Y, Context) },
{ Call = call(PredId, ProcId, ArgVars, not_builtin,
yes(CallContext), SymName) },
polymorphism__process_goal_expr(Call, GoalInfo, Goal)
; { type_to_type_id(Type, TypeId, _) } ->
% Convert other complicated unifications into
% calls to specific unification predicates, and then
% recursively call polymorphism__process_goal_expr
% to insert extra arguments if necessary.
{ module_info_get_special_pred_map(ModuleInfo,
SpecialPredMap) },
{ map__lookup(SpecialPredMap, unify - TypeId, PredId) },
{ determinism_components(Det, CanFail, at_most_one) },
{ unify_proc__lookup_mode_num(ModuleInfo, TypeId,
UniMode, Det, ProcId) },
{ SymName = unqualified("__Unify__") },
{ ArgVars = [XVar, YVar] },
{ CallContext = call_unify_context(XVar, Y, Context) },
{ Call = call(PredId, ProcId, ArgVars, not_builtin,
yes(CallContext), SymName) },
polymorphism__process_goal_expr(Call, GoalInfo, Goal)
;
{ error("polymorphism: type_to_type_id failed") }
)
;
{ Y = lambda_goal(PredOrFunc, ArgVars, Vars,
Modes, Det, LambdaGoal0) }
->
% for lambda expressions, we must recursively traverse the
% lambda goal and then convert the lambda expression
% into a new predicate
polymorphism__process_goal(LambdaGoal0, LambdaGoal1),
polymorphism__fixup_quantification(LambdaGoal1,
LambdaGoal, NonLocalTypeInfos),
polymorphism__process_lambda(PredOrFunc, Vars, Modes,
Det, ArgVars, NonLocalTypeInfos, LambdaGoal,
Unification, Y1, Unification1),
{ Goal = unify(XVar, Y1, Mode, Unification1, Context)
- GoalInfo }
;
% ordinary unifications are left unchanged,
{ Goal = unify(XVar, Y, Mode, Unification, Context) - GoalInfo }
).
% the rest of the clauses just process goals recursively
polymorphism__process_goal_expr(conj(Goals0), GoalInfo,
conj(Goals) - GoalInfo) -->
polymorphism__process_goal_list(Goals0, Goals).
polymorphism__process_goal_expr(disj(Goals0, SM), GoalInfo,
disj(Goals, SM) - GoalInfo) -->
polymorphism__process_goal_list(Goals0, Goals).
polymorphism__process_goal_expr(not(Goal0), GoalInfo, not(Goal) - GoalInfo) -->
polymorphism__process_goal(Goal0, Goal).
polymorphism__process_goal_expr(switch(Var, CanFail, Cases0, SM), GoalInfo,
switch(Var, CanFail, Cases, SM) - GoalInfo) -->
polymorphism__process_case_list(Cases0, Cases).
polymorphism__process_goal_expr(some(Vars, Goal0), GoalInfo,
some(Vars, Goal) - GoalInfo) -->
polymorphism__process_goal(Goal0, Goal).
polymorphism__process_goal_expr(if_then_else(Vars, A0, B0, C0, SM), GoalInfo,
if_then_else(Vars, A, B, C, SM) - GoalInfo) -->
polymorphism__process_goal(A0, A),
polymorphism__process_goal(B0, B),
polymorphism__process_goal(C0, C).
polymorphism__process_goal_expr(pragma_c_code(IsRecursive, PredId0, ProcId0,
ArgVars0, ArgInfo0, OrigArgTypes0, PragmaCode),
GoalInfo, Goal) -->
polymorphism__process_call(PredId0, ProcId0, ArgVars0,
PredId, ProcId, ArgVars, ExtraVars, ExtraGoals),
%
% update the non-locals
%
{ goal_info_get_nonlocals(GoalInfo, NonLocals0) },
{ set__insert_list(NonLocals0, ExtraVars, NonLocals) },
{ goal_info_set_nonlocals(GoalInfo, NonLocals, CallGoalInfo) },
%
% insert the type_info vars into the arg-name map,
% so that the c_code can refer to the type_info variable
% for type T as `TypeInfo_for_T'.
%
=(poly_info(_, _, _, _, _, _, _, ModuleInfo)),
{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
{ pred_info_arg_types(PredInfo, PredTypeVarSet, PredArgTypes) },
{ term__vars_list(PredArgTypes, PredTypeVars0) },
{ list__remove_dups(PredTypeVars0, PredTypeVars) },
{ polymorphism__c_code_add_typeinfos(ExtraVars, PredTypeVars,
PredTypeVarSet, ArgInfo0, ArgInfo) },
%
% insert type_info types for all the inserted type_info vars
% into the arg-types list
%
{ mercury_private_builtin_module(PrivateBuiltin) },
{ MakeType = lambda([TypeVar::in, TypeInfoType::out] is det,
construct_type(qualified(PrivateBuiltin, "type_info") - 1,
[term__variable(TypeVar)], TypeInfoType)) },
{ list__map(MakeType, PredTypeVars, TypeInfoTypes) },
{ list__append(TypeInfoTypes, OrigArgTypes0, OrigArgTypes) },
%
% plug it all back together
%
{ Call = pragma_c_code(IsRecursive, PredId, ProcId, ArgVars,
ArgInfo, OrigArgTypes, PragmaCode) - CallGoalInfo },
{ list__append(ExtraGoals, [Call], GoalList) },
{ conj_list_to_goal(GoalList, GoalInfo, Goal) }.
:- pred polymorphism__c_code_add_typeinfos(list(var), list(tvar), tvarset,
list(maybe(pair(string, mode))), list(maybe(pair(string, mode)))).
:- mode polymorphism__c_code_add_typeinfos(in, in, in, in, out) is det.
polymorphism__c_code_add_typeinfos([], [], _, ArgNames, ArgNames).
polymorphism__c_code_add_typeinfos([_Var|Vars], [TVar|TVars], TypeVarSet,
ArgNames0, ArgNames) :-
polymorphism__c_code_add_typeinfos(Vars, TVars, TypeVarSet,
ArgNames0, ArgNames1),
( varset__search_name(TypeVarSet, TVar, TypeVarName) ->
string__append("TypeInfo_for_", TypeVarName, C_VarName),
in_mode(Input),
ArgNames = [yes(C_VarName - Input) | ArgNames1]
;
ArgNames = [no | ArgNames1]
).
polymorphism__c_code_add_typeinfos([], [_|_], _, _, _) :-
error("polymorphism__c_code_add_typeinfos: length mismatch").
polymorphism__c_code_add_typeinfos([_|_], [], _, _, _) :-
error("polymorphism__c_code_add_typeinfos: length mismatch").
:- pred polymorphism__process_goal_list(list(hlds_goal), list(hlds_goal),
poly_info, poly_info).
:- mode polymorphism__process_goal_list(in, out, in, out) is det.
polymorphism__process_goal_list([], []) --> [].
polymorphism__process_goal_list([Goal0 | Goals0], [Goal | Goals]) -->
polymorphism__process_goal(Goal0, Goal),
polymorphism__process_goal_list(Goals0, Goals).
:- pred polymorphism__process_case_list(list(case), list(case),
poly_info, poly_info).
:- mode polymorphism__process_case_list(in, out, in, out) is det.
polymorphism__process_case_list([], []) --> [].
polymorphism__process_case_list([Case0 | Cases0], [Case | Cases]) -->
{ Case0 = case(ConsId, Goal0) },
polymorphism__process_goal(Goal0, Goal),
{ Case = case(ConsId, Goal) },
polymorphism__process_case_list(Cases0, Cases).
%-----------------------------------------------------------------------------%
:- pred polymorphism__process_call(pred_id, proc_id, list(var),
pred_id, proc_id, list(var),
list(var), list(hlds_goal),
poly_info, poly_info).
:- mode polymorphism__process_call(in, in, in, out, out, out, out, out,
in, out) is det.
polymorphism__process_call(PredId0, ProcId0, ArgVars0, PredId, ProcId, ArgVars,
ExtraVars, ExtraGoals, Info0, Info) :-
Info0 = poly_info(A, VarTypes, TypeVarSet0, D, E, F, G, ModuleInfo),
module_info_pred_info(ModuleInfo, PredId0, PredInfo),
pred_info_arg_types(PredInfo, PredTypeVarSet, PredArgTypes0),
pred_info_get_class_context(PredInfo, PredClassContext0),
% rename apart
% (this merge might be a performance bottleneck?)
varset__merge_subst(TypeVarSet0, PredTypeVarSet, TypeVarSet, Subst),
term__apply_substitution_to_list(PredArgTypes0, Subst,
PredArgTypes),
term__vars_list(PredArgTypes, PredTypeVars0),
pred_info_module(PredInfo, PredModule),
pred_info_name(PredInfo, PredName),
pred_info_arity(PredInfo, PredArity),
(
(
% optimize for common case of non-polymorphic call
PredTypeVars0 = []
;
% some builtins don't need the type_info
polymorphism__no_type_info_builtin(PredModule,
PredName, PredArity)
)
->
PredId = PredId0,
ProcId = ProcId0,
ArgVars = ArgVars0,
ExtraGoals = [],
ExtraVars = [],
Info = Info0
;
list__remove_dups(PredTypeVars0, PredTypeVars1),
map__apply_to_list(ArgVars0, VarTypes, ActualArgTypes),
( type_list_subsumes(PredArgTypes, ActualArgTypes,
TypeSubst1) ->
TypeSubst = TypeSubst1
;
error("polymorphism__process_goal_expr: type unification failed")
),
apply_subst_to_constraints(Subst, PredClassContext0,
PredClassContext),
Info1 = poly_info(A, VarTypes, TypeVarSet, D, E, F, G,
ModuleInfo),
% Make the typeclass_infos for the call, and return
% a list of which variables were constrained by the
% context
polymorphism__make_typeclass_info_vars(
PredClassContext, Subst, TypeSubst,
hlds_class_proc(PredId0, ProcId0),
hlds_class_proc(PredId, ProcId),
ExtraTypeClassVars, ExtraTypeClassGoals,
ConstrainedVars, Info1, Info2),
% No need to make typeinfos for the constrained vars
list__delete_elems(PredTypeVars1, ConstrainedVars,
PredTypeVars),
term__var_list_to_term_list(PredTypeVars, PredTypes0),
term__apply_rec_substitution_to_list(PredTypes0, TypeSubst,
PredTypes),
polymorphism__make_type_info_vars(PredTypes,
ExtraTypeInfoVars, ExtraTypeInfoGoals,
Info2, Info),
list__append(ExtraTypeClassVars, ArgVars0, ArgVars1),
list__append(ExtraTypeInfoVars, ArgVars1, ArgVars),
list__append(ExtraTypeClassGoals, ExtraTypeInfoGoals,
ExtraGoals),
list__append(ExtraTypeClassVars, ExtraTypeInfoVars,
ExtraVars)
).
:- pred polymorphism__fixup_quantification(hlds_goal, hlds_goal,
set(var), poly_info, poly_info).
:- mode polymorphism__fixup_quantification(in, out, out, in, out) is det.
%
% If the predicate we are processing is a polymorphic predicate,
% or contains polymorphically-typed goals, we
% may need to fix up the quantification (non-local variables)
% so that it includes the type-info variables in the non-locals set.
%
polymorphism__fixup_quantification(Goal0, Goal, NewOutsideVars, Info0, Info) :-
Info0 = poly_info(VarSet0, VarTypes0, TypeVarSet, TypeVarMap,
TypeClassVarMap, Proofs, PredName, ModuleInfo),
( map__is_empty(TypeVarMap) ->
set__init(NewOutsideVars),
Info = Info0,
Goal = Goal0
;
goal_util__extra_nonlocal_typeinfos(TypeVarMap,
VarTypes0, Goal0, NewOutsideVars),
Goal0 = _ - GoalInfo0,
goal_info_get_nonlocals(GoalInfo0, NonLocals),
set__union(NewOutsideVars, NonLocals, OutsideVars),
implicitly_quantify_goal(Goal0, VarSet0, VarTypes0,
OutsideVars, Goal, VarSet, VarTypes, _Warnings),
Info = poly_info(VarSet, VarTypes, TypeVarSet, TypeVarMap,
TypeClassVarMap, Proofs, PredName, ModuleInfo)
).
:- pred polymorphism__process_lambda(pred_or_func, list(var),
list(mode), determinism, list(var), set(var),
hlds_goal, unification, unify_rhs, unification,
poly_info, poly_info).
:- mode polymorphism__process_lambda(in, in, in, in, in, in, in, in, out, out,
in, out) is det.
polymorphism__process_lambda(PredOrFunc, Vars, Modes, Det, OrigNonLocals,
NonLocalTypeInfos, LambdaGoal, Unification0, Functor,
Unification, PolyInfo0, PolyInfo) :-
PolyInfo0 = poly_info(VarSet, VarTypes, TVarSet, TVarMap,
TCVarMap, Proofs, PredName, ModuleInfo0),
% Calculate the constraints which apply to this lambda
% expression.
map__keys(TCVarMap, AllConstraints),
map__apply_to_list(Vars, VarTypes, LambdaVarTypes),
list__map(type_util__vars, LambdaVarTypes, LambdaTypeVarsList),
list__condense(LambdaTypeVarsList, LambdaTypeVars),
list__filter(polymorphism__constraint_contains_vars(LambdaTypeVars),
AllConstraints, Constraints),
lambda__transform_lambda(PredOrFunc, PredName, Vars, Modes, Det,
OrigNonLocals, NonLocalTypeInfos, LambdaGoal, Unification0,
VarSet, VarTypes, Constraints, TVarSet, TVarMap, TCVarMap,
ModuleInfo0, Functor, Unification, ModuleInfo),
PolyInfo = poly_info(VarSet, VarTypes, TVarSet, TVarMap,
TCVarMap, Proofs, PredName, ModuleInfo).
:- pred polymorphism__constraint_contains_vars(list(var), class_constraint).
:- mode polymorphism__constraint_contains_vars(in, in) is semidet.
polymorphism__constraint_contains_vars(LambdaVars, ClassConstraint) :-
ClassConstraint = constraint(_, ConstraintTypes),
list__map(type_util__vars, ConstraintTypes, ConstraintVarsList),
list__condense(ConstraintVarsList, ConstraintVars),
% Probably not the most efficient way of doing it, but I
% wouldn't think that it matters.
set__list_to_set(LambdaVars, LambdaVarsSet),
set__list_to_set(ConstraintVars, ConstraintVarsSet),
set__subset(ConstraintVarsSet, LambdaVarsSet).
%---------------------------------------------------------------------------%
% 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.
% If the called predicate is a class method, and we know which instance
% it is, then instead of creating a type_info variable for the type class
% instance, just return the pred_proc_id for that instance.
% Otherwise return the original pred_proc_id unchanged.
:- pred polymorphism__make_typeclass_info_vars(list(class_constraint),
substitution, tsubst, hlds_class_proc, hlds_class_proc,
list(var), list(hlds_goal), list(var),
poly_info, poly_info).
:- mode polymorphism__make_typeclass_info_vars(in, in, in, in, out,
out, out, out, in, out) is det.
polymorphism__make_typeclass_info_vars(PredClassContext, Subst, TypeSubst,
PredProcId0, PredProcId,
ExtraVars, ExtraGoals, ConstrainedVars, Info0, Info) :-
% initialise the accumulators
ExtraVars0 = [],
ExtraGoals0 = [],
ConstrainedVars0 = [],
% The PredProcId is set to `yes(_)' for the first call only,
% because we can only specialize method calls if we know
% which instance of the method's type class it is; knowing
% the instances for any of the other type class constraints
% on a method doesn't help us specialize the call.
MaybePredProcId0 = yes(PredProcId0),
% do the work
polymorphism__make_typeclass_info_vars_2(PredClassContext,
Subst, TypeSubst, MaybePredProcId0, MaybePredProcId,
ExtraVars0, ExtraVars1,
ExtraGoals0, ExtraGoals1,
ConstrainedVars0, ConstrainedVars,
Info0, Info),
% We build up the vars and goals in reverse order
list__reverse(ExtraVars1, ExtraVars),
list__reverse(ExtraGoals1, ExtraGoals),
% If we succeeded in specializing this call, then use
% the specialization, otherwise use the original call.
( MaybePredProcId = yes(PredProcId1) ->
PredProcId = PredProcId1
;
PredProcId = PredProcId0
).
% Accumulator version of the above.
:- pred polymorphism__make_typeclass_info_vars_2(
list(class_constraint), substitution, tsubst,
maybe(hlds_class_proc), maybe(hlds_class_proc),
list(var), list(var),
list(hlds_goal), list(hlds_goal),
list(var), list(var),
poly_info, poly_info).
:- mode polymorphism__make_typeclass_info_vars_2(in, in, in,
in, out, in, out, in, out, in, out, in, out) is det.
polymorphism__make_typeclass_info_vars_2([], _Subst, _TypeSubst,
MaybePredProcId, MaybePredProcId,
ExtraVars, ExtraVars,
ExtraGoals, ExtraGoals,
ConstrainedVars, ConstrainedVars,
Info, Info).
polymorphism__make_typeclass_info_vars_2([C|Cs], Subst, TypeSubst,
MaybePredProcId0, MaybePredProcId,
ExtraVars0, ExtraVars,
ExtraGoals0, ExtraGoals,
ConstrainedVars0, ConstrainedVars,
Info0, Info) :-
polymorphism__make_typeclass_info_var(C, Subst, TypeSubst,
MaybePredProcId0, MaybePredProcId,
ExtraGoals0, ExtraGoals1,
ConstrainedVars0, ConstrainedVars1,
Info0, Info1, MaybeExtraVar),
maybe_insert_var(MaybeExtraVar, ExtraVars0, ExtraVars1),
polymorphism__make_typeclass_info_vars_2(Cs, Subst, TypeSubst,
no, _,
ExtraVars1, ExtraVars,
ExtraGoals1, ExtraGoals,
ConstrainedVars1, ConstrainedVars,
Info1, Info).
:- pred polymorphism__make_typeclass_info_var(class_constraint,
substitution, tsubst, maybe(hlds_class_proc), maybe(hlds_class_proc),
list(hlds_goal), list(hlds_goal),
list(var), list(var),
poly_info, poly_info,
maybe(var)).
:- mode polymorphism__make_typeclass_info_var(in, in, in, in, out,
in, out, in, out, in, out, out) is det.
polymorphism__make_typeclass_info_var(Constraint, Subst, TypeSubst,
MaybePredProcId0, MaybePredProcId,
ExtraGoals0, ExtraGoals,
ConstrainedVars0, ConstrainedVars,
Info0, Info, MaybeVar) :-
Constraint = constraint(ClassName, NewConstrainedTypes),
list__length(NewConstrainedTypes, ClassArity),
ClassId = class_id(ClassName, ClassArity),
term__vars_list(NewConstrainedTypes, NewConstrainedVars),
list__append(NewConstrainedVars, ConstrainedVars0, ConstrainedVars),
term__apply_rec_substitution_to_list(NewConstrainedTypes, TypeSubst,
ConstrainedTypes0),
% we need to maintain the invariant that types in class constraints
% do not contain any information in their term__context fields
strip_term_contexts(ConstrainedTypes0, ConstrainedTypes),
NewC = constraint(ClassName, ConstrainedTypes),
Info0 = poly_info(VarSet0, VarTypes0, TypeVarSet0, TypeInfoMap0,
TypeClassInfoMap0, Proofs, PredName, ModuleInfo),
(
map__search(TypeClassInfoMap0, NewC, Location)
->
% We already have a typeclass_info for this constraint
ExtraGoals = ExtraGoals0,
Var = Location,
MaybeVar = yes(Var),
MaybePredProcId = no,
Info = Info0
;
% We don't have the typeclass_info as a parameter to
% the pred, so we must be able to create it from
% somewhere else
% Work out how to make it
map__lookup(Proofs, NewC, Proof),
(
% We have to construct the typeclass_info
% using an instance declaration
Proof = apply_instance(ProofInstanceDefn, InstanceNum),
% The subst has already been applied to these
% constraints in typecheck.m
ProofInstanceDefn = hlds_instance_defn(_,
InstanceConstraints, _, _, _, _, _),
%
% Check whether the callee is a class method,
% and that this contraint is the first constraint
% in that callee's constraint list (the one for
% its own type class).
% If so, specialize the call by replacing the
% generic class method call with a direct call
% to the class method for this instance.
%
(
% check that this constraint is the
% first constraint in the callee's
% constraint list
MaybePredProcId0 = yes(PredProcId0),
% check that the called pred is a class method
PredProcId0 = hlds_class_proc(PredId0, _),
module_info_pred_info(ModuleInfo, PredId0,
PredInfo),
pred_info_get_markers(PredInfo, Markers),
check_marker(Markers, class_method),
% enabling this optimisation causes a bug
% where implied instances are concerned.
% When the class method call is inlined, the
% extra typeclass_infos from the instance
% declaration are not included. Until that
% bug is fixed, we will disable the
% optimisation.
semidet_fail
->
% Get the class methods, and figure out
% the method number of this class method.
module_info_classes(ModuleInfo, ClassTable),
map__lookup(ClassTable, ClassId, ClassDefn),
ClassDefn = hlds_class_defn(_, _, ClassMethods,
_, _),
( list__nth_member_search(ClassMethods,
PredProcId0, MethodNum0) ->
MethodNum = MethodNum0
;
error("poly: nth_member_search failed")
),
% Get the instance methods, and lookup
% the pred for the corresponding method number.
% (NB. We can't use ProofInstanceDefn,
% because its MaybeInstanceMethods field
% has not been updated (is still `no').)
module_info_instances(ModuleInfo,
InstanceTable),
map__lookup(InstanceTable, ClassId,
InstanceDefns),
list__index1_det(InstanceDefns, InstanceNum,
InstanceDefn),
InstanceDefn = hlds_instance_defn(_, _, _, _,
MaybeInstanceMethods, _, _),
( MaybeInstanceMethods = yes(InstanceMethods0)
->
InstanceMethods = InstanceMethods0
;
error("poly: no instance methods")
),
list__index1_det(InstanceMethods, MethodNum,
InstanceMethod),
MaybePredProcId = yes(InstanceMethod),
MaybeVar = no,
ExtraGoals = ExtraGoals0,
Info = Info0
;
% Make the type_infos for the types
% that are constrained by this. These
% are packaged in the typeclass_info
polymorphism__make_type_info_vars(
ConstrainedTypes,
InstanceExtraTypeInfoVars,
TypeInfoGoals,
Info0, Info1),
% Make the typeclass_infos for the
% constraints from the context of the
% instance decl.
polymorphism__make_typeclass_info_vars_2(
InstanceConstraints, Subst, TypeSubst,
no, _,
[], InstanceExtraTypeClassInfoVars,
ExtraGoals0, ExtraGoals1,
[], _,
Info1, Info2),
polymorphism__construct_typeclass_info(
InstanceExtraTypeInfoVars,
InstanceExtraTypeClassInfoVars,
ClassId, InstanceNum, Var, NewGoals,
Info2, Info),
MaybeVar = yes(Var),
MaybePredProcId = no,
% Oh, yuck. The type_info goals have
% already been reversed, so lets
% reverse them back.
list__reverse(TypeInfoGoals, RevTypeInfoGoals),
list__append(ExtraGoals1, RevTypeInfoGoals,
ExtraGoals2),
list__append(NewGoals, ExtraGoals2, ExtraGoals)
)
;
% We have to extract the typeclass_info from
% another one
Proof = superclass(SubClassConstraint0),
% First create a variable to hold the new
% typeclass_info
unqualify_name(ClassName, ClassNameString),
polymorphism__new_typeclass_info_var(VarSet0, VarTypes0,
ClassNameString, Var, VarSet1, VarTypes1),
MaybeVar = yes(Var),
MaybePredProcId = no,
% Then work out where to extract it from
SubClassConstraint0 =
constraint(SubClassName, SubClassTypes0),
term__apply_substitution_to_list(SubClassTypes0, Subst,
SubClassTypes1),
% we need to maintain the invariant that types in
% class constraints do not contain any information
% in their term__context fields
strip_term_contexts(SubClassTypes1, SubClassTypes),
SubClassConstraint =
constraint(SubClassName, SubClassTypes),
list__length(SubClassTypes, SubClassArity),
SubClassId = class_id(SubClassName, SubClassArity),
Info1 = poly_info(VarSet1, VarTypes1, TypeVarSet0,
TypeInfoMap0, TypeClassInfoMap0, Proofs,
PredName, ModuleInfo),
% Make the typeclass_info for the subclass
polymorphism__make_typeclass_info_var(
SubClassConstraint, Subst, TypeSubst,
no, _,
ExtraGoals0, ExtraGoals1,
[], _,
Info1, Info2,
MaybeSubClassVar),
( MaybeSubClassVar = yes(SubClassVar0) ->
SubClassVar = SubClassVar0
;
error("MaybeSubClassVar = no")
),
% Look up the definition of the subclass
module_info_classes(ModuleInfo, ClassTable),
map__lookup(ClassTable, SubClassId, SubClassDefn),
SubClassDefn = hlds_class_defn(SuperClasses0,
SubClassVars, _, _, _),
% Work out which superclass typeclass_info to
% take
ToTerm = lambda([TheVar::in, TheTerm::out] is det,
(
TheTerm = term__variable(TheVar)
)),
list__map(ToTerm, SubClassVars, SubClassVarTerms),
(
type_list_subsumes(SubClassVarTerms,
SubClassTypes, SubTypeSubst0)
->
SubTypeSubst0 = SubTypeSubst
;
error("polymorphism__make_typeclass_info_var")
),
apply_rec_subst_to_constraints(SubTypeSubst,
SuperClasses0, SuperClasses),
(
list__nth_member_search(SuperClasses,
Constraint, SuperClassIndex0)
->
SuperClassIndex0 = SuperClassIndex
;
% We shouldn't have got this far if
% the constraints were not satifsied
error("polymorphism.m: constraint not in constraint list")
),
Info2 = poly_info(VarSet2, VarTypes2, TypeVarSet2,
TypeInfoMap2, TypeClassInfoMap2, Proofs2,
PredName2, ModuleInfo2),
polymorphism__make_count_var(SuperClassIndex, VarSet2,
VarTypes2, IndexVar, IndexGoal, VarSet,
VarTypes),
Info = poly_info(VarSet, VarTypes, TypeVarSet2,
TypeInfoMap2, TypeClassInfoMap2, Proofs2,
PredName2, ModuleInfo2),
% We extract the superclass typeclass_info by
% inserting a call to
% superclass_from_typeclass_info in
% mercury_builtin.
% Make the goal for the call
varset__init(Empty),
mercury_private_builtin_module(PrivateBuiltin),
ExtractSuperClass = qualified(PrivateBuiltin,
"superclass_from_typeclass_info"),
construct_type(qualified(PrivateBuiltin,
"typeclass_info") - 0,
[], TypeClassInfoType),
construct_type(unqualified("int") - 0, [], IntType),
get_pred_id_and_proc_id(ExtractSuperClass, predicate,
Empty,
[TypeClassInfoType, IntType, TypeClassInfoType],
ModuleInfo, PredId, ProcId),
Call = call(PredId, ProcId,
[SubClassVar, IndexVar, Var],
not_builtin, no,
ExtractSuperClass
),
% Make the goal info for the call
set__list_to_set([SubClassVar, IndexVar, Var],
NonLocals),
instmap_delta_from_assoc_list(
[Var - ground(shared, no)],
InstmapDelta),
goal_info_init(NonLocals, InstmapDelta, det, GoalInfo),
% Put them together
SuperClassGoal = Call - GoalInfo,
% Add it to the accumulator
ExtraGoals = [SuperClassGoal,IndexGoal|ExtraGoals1]
)
).
:- pred polymorphism__construct_typeclass_info(list(var), list(var), class_id,
int, var, list(hlds_goal), poly_info, poly_info).
:- mode polymorphism__construct_typeclass_info(in, in, in, in, out, out,
in, out) is det.
polymorphism__construct_typeclass_info(ArgTypeInfoVars, ArgTypeClassInfoVars,
ClassId, InstanceNum, NewVar, NewGoals, Info0, Info) :-
Info0 = poly_info(_, _, _, _, _, _, _, ModuleInfo),
module_info_instances(ModuleInfo, InstanceTable),
map__lookup(InstanceTable, ClassId, InstanceList),
list__index1_det(InstanceList, InstanceNum, InstanceDefn),
InstanceDefn = hlds_instance_defn(_, _, InstanceTypes, _, _, _,
SuperClassProofs),
module_info_classes(ModuleInfo, ClassTable),
map__lookup(ClassTable, ClassId, ClassDefn),
polymorphism__get_arg_superclass_vars(ClassDefn, InstanceTypes,
SuperClassProofs, ArgSuperClassVars, SuperClassGoals,
Info0, Info1),
Info1 = poly_info(VarSet0, VarTypes0, TVarSet, TVarMap, TCVarMap,
Proofs, PredName, _),
% lay out the argument variables as expected in the
% typeclass_info
list__append(ArgTypeClassInfoVars, ArgSuperClassVars, ArgVars0),
list__append(ArgVars0, ArgTypeInfoVars, ArgVars),
ClassId = class_id(ClassName, _Arity),
unqualify_name(ClassName, ClassNameString),
polymorphism__new_typeclass_info_var(VarSet0, VarTypes0,
ClassNameString, BaseVar, VarSet1, VarTypes1),
base_typeclass_info__make_instance_string(InstanceTypes,
InstanceString),
% XXX I don't think we actually need to carry the module name
% around.
ModuleName = unqualified("some bogus module name"),
ConsId = base_typeclass_info_const(ModuleName, ClassId, InstanceString),
BaseTypeClassInfoTerm = functor(ConsId, []),
% create the construction unification to initialize the variable
BaseUnification = construct(BaseVar, ConsId, [], []),
BaseUnifyMode = (free -> ground(shared, no)) -
(ground(shared, no) -> ground(shared, no)),
BaseUnifyContext = unify_context(explicit, []),
% XXX the UnifyContext is wrong
BaseUnify = unify(BaseVar, BaseTypeClassInfoTerm, BaseUnifyMode,
BaseUnification, BaseUnifyContext),
% create a goal_info for the unification
set__list_to_set([BaseVar], NonLocals),
instmap_delta_from_assoc_list([BaseVar - ground(shared, no)],
InstmapDelta),
goal_info_init(NonLocals, InstmapDelta, det, BaseGoalInfo),
BaseGoal = BaseUnify - BaseGoalInfo,
% build a unification to add the argvars to the
% base_typeclass_info
mercury_private_builtin_module(PrivateBuiltin),
NewConsId = cons(qualified(PrivateBuiltin, "typeclass_info"), 1),
NewArgVars = [BaseVar|ArgVars],
TypeClassInfoTerm = functor(NewConsId, NewArgVars),
% introduce a new variable
polymorphism__new_typeclass_info_var(VarSet1, VarTypes1,
ClassNameString, NewVar, VarSet, VarTypes),
% create the construction unification to initialize the
% variable
UniMode = (free - ground(shared, no) ->
ground(shared, no) - ground(shared, no)),
list__length(NewArgVars, NumArgVars),
list__duplicate(NumArgVars, UniMode, UniModes),
Unification = construct(NewVar, NewConsId, NewArgVars,
UniModes),
UnifyMode = (free -> ground(shared, no)) -
(ground(shared, no) -> ground(shared, no)),
UnifyContext = unify_context(explicit, []),
% XXX the UnifyContext is wrong
Unify = unify(NewVar, TypeClassInfoTerm, UnifyMode,
Unification, UnifyContext),
% create a goal_info for the unification
goal_info_init(GoalInfo0),
set__list_to_set([NewVar | NewArgVars], TheNonLocals),
goal_info_set_nonlocals(GoalInfo0, TheNonLocals, GoalInfo1),
list__duplicate(NumArgVars, ground(shared, no), ArgInsts),
% note that we could perhaps be more accurate than
% `ground(shared)', but it shouldn't make any
% difference.
InstConsId = cons( qualified(PrivateBuiltin, "typeclass_info"),
NumArgVars),
instmap_delta_from_assoc_list(
[NewVar -
bound(unique, [functor(InstConsId, ArgInsts)])],
InstMapDelta),
goal_info_set_instmap_delta(GoalInfo1, InstMapDelta, GoalInfo2),
goal_info_set_determinism(GoalInfo2, det, GoalInfo),
TypeClassInfoGoal = Unify - GoalInfo,
NewGoals0 = [TypeClassInfoGoal, BaseGoal],
list__append(SuperClassGoals, NewGoals0, NewGoals),
Info = poly_info(VarSet, VarTypes, TVarSet, TVarMap,
TCVarMap, Proofs, PredName, ModuleInfo).
%---------------------------------------------------------------------------%
:- pred polymorphism__get_arg_superclass_vars(hlds_class_defn, list(type),
map(class_constraint, constraint_proof), list(var), list(hlds_goal),
poly_info, poly_info).
:- mode polymorphism__get_arg_superclass_vars(in, in, in, out, out,
in, out) is det.
polymorphism__get_arg_superclass_vars(ClassDefn, InstanceTypes,
SuperClassProofs, NewVars, NewGoals, Info0, Info) :-
Info0 = poly_info(VarSet0, VarTypes0, TVarSet, TVarMap0, TCVarMap0,
Proofs, PredName, ModuleInfo),
ClassDefn = hlds_class_defn(SuperClasses, ClassVars, _, ClassVarSet, _),
map__from_corresponding_lists(ClassVars, InstanceTypes, TypeSubst),
varset__merge_subst(VarSet0, ClassVarSet, VarSet1, Subst),
Info1 = poly_info(VarSet1, VarTypes0, TVarSet, TVarMap0, TCVarMap0,
SuperClassProofs, PredName, ModuleInfo),
polymorphism__make_superclasses_from_proofs(SuperClasses, Subst,
TypeSubst, [], NewGoals, Info1, Info2, [], NewVars),
Info2 = poly_info(VarSet, VarTypes, _, TVarMap, TCVarMap, _, _, _),
Info = poly_info(VarSet, VarTypes, TVarSet, TVarMap, TCVarMap,
Proofs, PredName, ModuleInfo) .
:- pred polymorphism__make_superclasses_from_proofs(list(class_constraint),
substitution, tsubst, list(hlds_goal), list(hlds_goal),
poly_info, poly_info, list(var), list(var)).
:- mode polymorphism__make_superclasses_from_proofs(in, in, in, in, out,
in, out, in, out) is det.
polymorphism__make_superclasses_from_proofs([], _, _,
Goals, Goals, Info, Info, Vars, Vars).
polymorphism__make_superclasses_from_proofs([C|Cs], Subst, TypeSubst,
Goals0, Goals, Info0, Info, Vars0, Vars) :-
polymorphism__make_superclasses_from_proofs(Cs, Subst, TypeSubst,
Goals0, Goals1, Info0, Info1, Vars0, Vars1),
polymorphism__make_typeclass_info_var(C, Subst, TypeSubst,
no, _, Goals1, Goals, [], _, Info1, Info, MaybeVar),
maybe_insert_var(MaybeVar, Vars1, Vars).
:- pred maybe_insert_var(maybe(var), list(var), list(var)).
:- mode maybe_insert_var(in, in, out) is det.
maybe_insert_var(no, Vars, Vars).
maybe_insert_var(yes(Var), Vars, [Var | Vars]).
%---------------------------------------------------------------------------%
% 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(type),
list(var), list(hlds_goal), poly_info, poly_info).
:- mode polymorphism__make_type_info_vars(in, out, out, in, out) is det.
polymorphism__make_type_info_vars([], [], [], Info, Info).
polymorphism__make_type_info_vars([Type | Types],
ExtraVars, ExtraGoals, Info0, Info) :-
polymorphism__make_type_info_var(Type,
Var, ExtraGoals1, Info0, Info1),
polymorphism__make_type_info_vars(Types,
ExtraVars2, ExtraGoals2, Info1, Info),
ExtraVars = [Var | ExtraVars2],
list__append(ExtraGoals1, ExtraGoals2, ExtraGoals).
:- pred polymorphism__make_type_info_var(type, var, list(hlds_goal),
poly_info, poly_info).
:- mode polymorphism__make_type_info_var(in, out, out, in, out) is det.
polymorphism__make_type_info_var(Type, Var, ExtraGoals, Info0, Info) :-
(
type_is_higher_order(Type, PredOrFunc, TypeArgs)
->
% This occurs for code where a predicate calls a polymorphic
% predicate with a known higher-order value of the type
% variable.
% The transformation we perform is basically the same as
% in the first-order case below, except that we map
% pred/func types to builtin pred/0 or func/0 for the
% purposes of creating type_infos.
% To allow univ_to_type to check the type_infos
% correctly, the actual arity of the pred is added to
% the type_info of higher-order types.
hlds_out__pred_or_func_to_str(PredOrFunc, PredOrFuncStr),
TypeId = unqualified(PredOrFuncStr) - 0,
polymorphism__construct_type_info(Type, TypeId, TypeArgs,
yes, Var, ExtraGoals, Info0, Info)
;
type_to_type_id(Type, TypeId, 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__construct_type_info(Type, TypeId, TypeArgs,
no, Var, ExtraGoals, Info0, Info)
;
Type = term__variable(TypeVar1),
Info0 = poly_info(_, _, _, TypeInfoMap0, _, _, _, _),
map__search(TypeInfoMap0, TypeVar1, TypeInfoLocn)
->
% This occurs for code where a predicate calls a polymorphic
% predicate with a bound but unknown value of the type variable.
% For example, in
%
% :- pred p(T1).
% :- pred q(T2).
%
% p(X) :- q(X).
%
% we know that `T2' is bound to `T1', and we translate it into
%
% :- pred p(TypeInfo(T1), T1).
% :- pred q(TypeInfo(T2), T2).
%
% p(TypeInfo, X) :- q(TypeInfo, X).
(
% If the typeinfo is available in a variable,
% just use it
TypeInfoLocn = type_info(TypeInfoVar),
Var = TypeInfoVar,
ExtraGoals = [],
Info = Info0
;
% If the typeinfo is in a typeclass_info, first
% extract it, then use it
TypeInfoLocn = typeclass_info(TypeClassInfoVar, Index),
extract_type_info(Type, TypeVar1, TypeClassInfoVar,
Index, ExtraGoals, Var, Info0, Info)
)
;
Type = term__variable(_TypeVar1)
->
% This occurs for code where a predicate calls a polymorphic
% predicate with an unbound type variable, for example
%
% :- pred p.
% :- pred q(list(T)).
% p :- q([]).
% this case is now treated as an error;
% it should be caught by purity.m.
error("polymorphism__make_var: unbound type variable")
/************
This is what we used to do... but this didn't handle the case of type
variables used by lambda expressions properly.
Binding unbound type variables to `void' is now done in purity.m,
because it is easier to do it correctly there.
% In this case T is unbound, so there cannot be any objects
% of type T, and so q/1 cannot possibly use the unification
% predicate for type T. We pass the type-info for the
% type `void'/0.
%
% :- pred p.
% :- pred q(type_info(T), list(T)).
% p :- q(<void/0>, []).
%
% Passing `void'/0 should ensure that we get a runtime
% error if the special predicates for this type are
% ever used (void has its special predicates set to
% `unused'/0).
%
% XXX what about io__read_anything/3?
% e.g.
% foo --> io__read_anything(_).
% ?
% introduce a new variable, and
% create a construction unification which initializes the
% variable to zero
TypeId = unqualified("void") - 0,
polymorphism__construct_type_info(Type, TypeId, [],
no, Var, ExtraGoals, Info0, Info1),
Info1 = poly_info(A, B, C, TypeInfoMap1, E, F, G, H),
map__det_insert(TypeInfoMap1, TypeVar1, type_info(Var),
TypeInfoMap),
Info = poly_info(A, B, C, TypeInfoMap, E, F, G, H)
***************/
;
error("polymorphism__make_var: unknown type")
).
:- pred polymorphism__construct_type_info(type, type_id, list(type),
bool, var, list(hlds_goal), poly_info, poly_info).
:- mode polymorphism__construct_type_info(in, in, in, in, out, out,
in, out) is det.
polymorphism__construct_type_info(Type, TypeId, TypeArgs, IsHigherOrder,
Var, ExtraGoals, Info0, Info) :-
% Create the typeinfo vars for the arguments
polymorphism__make_type_info_vars(TypeArgs, ArgTypeInfoVars,
ArgTypeInfoGoals, Info0, Info1),
Info1 = poly_info(VarSet1, VarTypes1, C, D, E, F, G, ModuleInfo),
polymorphism__init_const_base_type_info_var(Type,
TypeId, ModuleInfo, VarSet1, VarTypes1,
BaseVar, BaseGoal, VarSet2, VarTypes2),
polymorphism__maybe_init_second_cell(ArgTypeInfoVars,
ArgTypeInfoGoals, Type, IsHigherOrder,
BaseVar, VarSet2, VarTypes2, [BaseGoal],
Var, VarSet, VarTypes, ExtraGoals),
Info = poly_info(VarSet, VarTypes, C, D, E, F, G, ModuleInfo).
% Create a unification for the two-cell type_info
% variable for this type if the type arity is not zero:
% TypeInfoVar = type_info(BaseVar,
% ArgTypeInfoVars...).
% For closures, we add the actual arity before the
% arguments, because all closures have a BaseVar
% of "pred/0".
% TypeInfoVar = type_info(BaseVar, Arity,
% ArgTypeInfoVars...).
:- pred polymorphism__maybe_init_second_cell(list(var), list(hlds_goal), type,
bool, var, varset, map(var, type), list(hlds_goal),
var, varset, map(var, type), list(hlds_goal)).
:- mode polymorphism__maybe_init_second_cell(in, in, in, in, in, in, in, in,
out, out, out, out) is det.
polymorphism__maybe_init_second_cell(ArgTypeInfoVars, ArgTypeInfoGoals, Type,
IsHigherOrder, BaseVar, VarSet0, VarTypes0, ExtraGoals0,
Var, VarSet, VarTypes, ExtraGoals) :-
(
ArgTypeInfoVars = [],
IsHigherOrder = no
->
Var = BaseVar,
% Since this base_type_info is pretending to be
% a type_info, we need to adjust its type.
% Since base_type_info_const cons_ids are handled
% specially, this should not cause problems.
mercury_private_builtin_module(MercuryBuiltin),
construct_type(qualified(MercuryBuiltin, "type_info") - 1,
[Type], NewBaseVarType),
map__det_update(VarTypes0, BaseVar, NewBaseVarType, VarTypes),
VarSet = VarSet0,
ExtraGoals = ExtraGoals0
;
% Unfortunately, if we have higher order terms, we
% can no longer just optimise them to be the actual
% base_type_info
(
IsHigherOrder = yes
->
list__length(ArgTypeInfoVars, PredArity),
polymorphism__make_count_var(PredArity, VarSet0,
VarTypes0, ArityVar, ArityGoal, VarSet1,
VarTypes1),
TypeInfoArgVars = [BaseVar, ArityVar | ArgTypeInfoVars],
TypeInfoArgGoals = [ArityGoal | ArgTypeInfoGoals]
;
TypeInfoArgVars = [BaseVar | ArgTypeInfoVars],
TypeInfoArgGoals = ArgTypeInfoGoals,
VarTypes1 = VarTypes0,
VarSet1 = VarSet0
),
polymorphism__init_type_info_var(Type,
TypeInfoArgVars, "type_info",
VarSet1, VarTypes1, Var, TypeInfoGoal,
VarSet, VarTypes),
list__append(TypeInfoArgGoals, [TypeInfoGoal], ExtraGoals1),
list__append(ExtraGoals0, ExtraGoals1, ExtraGoals)
).
% Create a unification `CountVar = <NumTypeArgs>'
:- pred polymorphism__make_count_var(int, varset, map(var, type),
var, hlds_goal, varset, map(var, type)).
:- mode polymorphism__make_count_var(in, in, in, out, out, out, out) is det.
polymorphism__make_count_var(NumTypeArgs, VarSet0, VarTypes0,
CountVar, CountGoal, VarSet, VarTypes) :-
varset__new_var(VarSet0, CountVar, VarSet1),
varset__name_var(VarSet1, CountVar, "TypeArity", VarSet),
construct_type(unqualified("int") - 0, [], IntType),
map__set(VarTypes0, CountVar, IntType, VarTypes),
polymorphism__init_with_int_constant(CountVar, NumTypeArgs, CountGoal).
% Create a construction unification `Var = <Num>'
% where Var is a freshly introduced variable and Num is an
% integer constant.
:- pred polymorphism__init_with_int_constant(var, int, hlds_goal).
:- mode polymorphism__init_with_int_constant(in, in, out) is det.
polymorphism__init_with_int_constant(CountVar, Num, CountUnifyGoal) :-
CountConsId = int_const(Num),
CountUnification = construct(CountVar, CountConsId, [], []),
CountTerm = functor(CountConsId, []),
CountInst = bound(unique, [functor(int_const(Num), [])]),
CountUnifyMode = (free -> CountInst) - (CountInst -> CountInst),
CountUnifyContext = unify_context(explicit, []),
% XXX the UnifyContext is wrong
CountUnify = unify(CountVar, CountTerm, CountUnifyMode,
CountUnification, CountUnifyContext),
% create a goal_info for the unification
set__singleton_set(CountNonLocals, CountVar),
instmap_delta_from_assoc_list([CountVar - CountInst], InstmapDelta),
goal_info_init(CountNonLocals, InstmapDelta, det, CountGoalInfo),
CountUnifyGoal = CountUnify - CountGoalInfo.
% Create the unifications to initialize the special pred
% variables for this type:
%
% SpecialPred1 = __Unify__<type>,
% SpecialPred2 = __Index__<type>,
% SpecialPred3 = __Compare__<type>.
:- pred polymorphism__get_special_proc_list(
type, module_info, varset, map(var, type),
list(var), list(hlds_goal), varset, map(var, type)).
:- mode polymorphism__get_special_proc_list(in, in, in, in,
out, out, out, out) is det.
polymorphism__get_special_proc_list(Type, ModuleInfo, VarSet0, VarTypes0,
SpecialPredVars, SpecialPredGoals, VarSet, VarTypes) :-
special_pred_list(SpecialPreds),
polymorphism__get_special_proc_list_2(SpecialPreds,
Type, ModuleInfo, VarSet0, VarTypes0,
SpecialPredVars, SpecialPredGoals, VarSet, VarTypes).
:- pred polymorphism__get_special_proc_list_2(list(special_pred_id),
type, module_info, varset, map(var, type),
list(var), list(hlds_goal), varset, map(var, type)).
:- mode polymorphism__get_special_proc_list_2(in, in, in, in, in,
out, out, out, out) is det.
polymorphism__get_special_proc_list_2([],
_Type, _ModuleInfo, VarSet, VarTypes,
[], [], VarSet, VarTypes).
polymorphism__get_special_proc_list_2([Id | Ids],
Type, ModuleInfo, VarSet0, VarTypes0,
[Var | Vars], [Goal | Goals], VarSet, VarTypes) :-
% introduce a fresh variable of the appropriate higher-order pred type
special_pred_info(Id, Type, PredName, TypeArgs, _Modes, _Det),
varset__new_var(VarSet0, Var, VarSet1a),
string__append("Var__", PredName, VarName),
varset__name_var(VarSet1a, Var, VarName, VarSet1),
term__context_init(Context),
PredType = term__functor(term__atom("pred"), TypeArgs, Context),
map__set(VarTypes0, Var, PredType, VarTypes1),
% get the ConsId for the address of the appropriate pred
% for the operation specified by Id applied to Type.
classify_type(Type, ModuleInfo, TypeCategory),
polymorphism__get_special_proc(TypeCategory, Type, Id, ModuleInfo,
PredName2, PredId, ProcId),
ConsId = code_addr_const(PredId, ProcId),
% create a construction unification which unifies the fresh
% variable with the address constant obtained above
Unification = construct(Var, ConsId, [], []),
Term = functor(cons(PredName2, 0), []),
Inst = bound(unique, [functor(cons(PredName2, 0), [])]),
UnifyMode = (free -> Inst) - (Inst -> Inst),
UnifyContext = unify_context(explicit, []),
% XXX the UnifyContext is wrong
Unify = unify(Var, Term, UnifyMode, Unification, UnifyContext),
% create a goal_info for the unification
set__singleton_set(NonLocals, Var),
instmap_delta_from_assoc_list([Var - Inst], InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
Goal = Unify - GoalInfo,
polymorphism__get_special_proc_list_2(Ids,
Type, ModuleInfo, VarSet1, VarTypes1,
Vars, Goals, VarSet, VarTypes).
:- pred polymorphism__get_special_proc(builtin_type, type, special_pred_id,
module_info, sym_name, pred_id, proc_id).
:- mode polymorphism__get_special_proc(in, in, in, in, out, out, out) is det.
polymorphism__get_special_proc(TypeCategory, Type, SpecialPredId, ModuleInfo,
PredName, PredId, ProcId) :-
( TypeCategory = user_type ->
module_info_get_special_pred_map(ModuleInfo, SpecialPredMap),
( type_to_type_id(Type, TypeId, _TypeArgs) ->
map__lookup(SpecialPredMap, SpecialPredId - TypeId,
PredId)
;
error(
"polymorphism__get_special_proc: type_to_type_id failed")
),
module_info_pred_info(ModuleInfo, PredId, PredInfo),
pred_info_module(PredInfo, Module),
pred_info_name(PredInfo, Name),
PredName = qualified(Module, Name)
;
polymorphism__get_category_name(TypeCategory, CategoryName),
special_pred_name_arity(SpecialPredId, SpecialName, _, Arity),
string__append_list(
["builtin_", SpecialName, "_", CategoryName], Name),
polymorphism__get_builtin_pred_id(Name, Arity, ModuleInfo,
PredId),
PredName = unqualified(Name)
),
special_pred_mode_num(SpecialPredId, ProcInt),
proc_id_to_int(ProcId, ProcInt).
:- pred polymorphism__get_category_name(builtin_type, string).
:- mode polymorphism__get_category_name(in, out) is det.
polymorphism__get_category_name(int_type, "int").
polymorphism__get_category_name(char_type, "int").
polymorphism__get_category_name(enum_type, "int").
polymorphism__get_category_name(float_type, "float").
polymorphism__get_category_name(str_type, "string").
polymorphism__get_category_name(pred_type, "pred").
polymorphism__get_category_name(polymorphic_type, _) :-
error("polymorphism__get_category_name: polymorphic type").
polymorphism__get_category_name(user_type, _) :-
error("polymorphism__get_category_name: user_type").
% find the builtin predicate with the specified name
:- pred polymorphism__get_builtin_pred_id(string, int, module_info, pred_id).
:- mode polymorphism__get_builtin_pred_id(in, in, in, out) is det.
polymorphism__get_builtin_pred_id(Name, Arity, ModuleInfo, PredId) :-
module_info_get_predicate_table(ModuleInfo, PredicateTable),
(
mercury_private_builtin_module(PrivateBuiltin),
predicate_table_search_pred_m_n_a(PredicateTable,
PrivateBuiltin, Name, Arity, [PredId1])
->
PredId = PredId1
;
error("polymorphism__get_pred_id: pred_id lookup failed")
).
% Create a unification for a type_info or base_type_info variable:
%
% TypeInfoVar = type_info(CountVar,
% SpecialPredVars...,
% ArgTypeInfoVars...)
%
% or
%
% BaseTypeInfoVar = base_type_type_info(CountVar,
% SpecialPredVars...)
%
% These unifications WILL lead to the creation of cells on the
% heap at runtime.
:- pred polymorphism__init_type_info_var(type, list(var), string,
varset, map(var, type), var, hlds_goal, varset, map(var, type)).
:- mode polymorphism__init_type_info_var(in, in, in, in, in, out, out, out, out)
is det.
polymorphism__init_type_info_var(Type, ArgVars, Symbol, VarSet0, VarTypes0,
TypeInfoVar, TypeInfoGoal, VarSet, VarTypes) :-
mercury_private_builtin_module(PrivateBuiltin),
ConsId = cons(qualified(PrivateBuiltin, Symbol), 1),
TypeInfoTerm = functor(ConsId, ArgVars),
% introduce a new variable
polymorphism__new_type_info_var(Type, Symbol, VarSet0, VarTypes0,
TypeInfoVar, VarSet, VarTypes),
% create the construction unification to initialize the variable
UniMode = (free - ground(shared, no) ->
ground(shared, no) - ground(shared, no)),
list__length(ArgVars, NumArgVars),
list__duplicate(NumArgVars, UniMode, UniModes),
Unification = construct(TypeInfoVar, ConsId, ArgVars, UniModes),
UnifyMode = (free -> ground(shared, no)) -
(ground(shared, no) -> ground(shared, no)),
UnifyContext = unify_context(explicit, []),
% XXX the UnifyContext is wrong
Unify = unify(TypeInfoVar, TypeInfoTerm, UnifyMode,
Unification, UnifyContext),
% create a goal_info for the unification
set__list_to_set([TypeInfoVar | ArgVars], NonLocals),
list__duplicate(NumArgVars, ground(shared, no), ArgInsts),
% note that we could perhaps be more accurate than
% `ground(shared)', but it shouldn't make any
% difference.
InstConsId = cons(qualified(PrivateBuiltin, Symbol), NumArgVars),
instmap_delta_from_assoc_list(
[TypeInfoVar - bound(unique, [functor(InstConsId, ArgInsts)])],
InstMapDelta),
goal_info_init(NonLocals, InstMapDelta, det, GoalInfo),
TypeInfoGoal = Unify - GoalInfo.
% Create a unification for a type_info or base_type_info variable:
%
% BaseTypeInfoVar = base_type_type_info(CountVar,
% SpecialPredVars...)
%
% This unification will NOT lead to the creation of a cell on the
% heap at runtime; it will cause BaseTypeInfoVar to refer to the
% statically allocated base_type_info cell for the type, allocated
% in the module that defines the type.
:- pred polymorphism__init_const_base_type_info_var(type, type_id,
module_info, varset, map(var, type), var, hlds_goal,
varset, map(var, type)).
:- mode polymorphism__init_const_base_type_info_var(in, in, in, in, in,
out, out, out, out) is det.
polymorphism__init_const_base_type_info_var(Type, TypeId,
ModuleInfo, VarSet0, VarTypes0, BaseTypeInfoVar,
BaseTypeInfoGoal, VarSet, VarTypes) :-
type_util__type_id_module(ModuleInfo, TypeId, ModuleName),
type_util__type_id_name(ModuleInfo, TypeId, TypeName),
TypeId = _ - Arity,
ConsId = base_type_info_const(ModuleName, TypeName, Arity),
TypeInfoTerm = functor(ConsId, []),
% introduce a new variable
polymorphism__new_type_info_var(Type, "base_type_info",
VarSet0, VarTypes0, BaseTypeInfoVar, VarSet, VarTypes),
% create the construction unification to initialize the variable
Unification = construct(BaseTypeInfoVar, ConsId, [], []),
UnifyMode = (free -> ground(shared, no)) -
(ground(shared, no) -> ground(shared, no)),
UnifyContext = unify_context(explicit, []),
% XXX the UnifyContext is wrong
Unify = unify(BaseTypeInfoVar, TypeInfoTerm, UnifyMode,
Unification, UnifyContext),
% create a goal_info for the unification
set__list_to_set([BaseTypeInfoVar], NonLocals),
instmap_delta_from_assoc_list([BaseTypeInfoVar - ground(shared, no)],
InstmapDelta),
goal_info_init(NonLocals, InstmapDelta, det, GoalInfo),
BaseTypeInfoGoal = Unify - GoalInfo.
%---------------------------------------------------------------------------%
:- pred polymorphism__make_head_vars(list(tvar), tvarset,
varset, map(var, type),
list(var), varset, map(var, type)).
:- mode polymorphism__make_head_vars(in, in, in, in, out, out, out) is det.
polymorphism__make_head_vars([], _, VarSet, VarTypes, [], VarSet, VarTypes).
polymorphism__make_head_vars([TypeVar|TypeVars], TypeVarSet,
VarSet0, VarTypes0,
TypeInfoVars, VarSet, VarTypes) :-
Type = term__variable(TypeVar),
polymorphism__new_type_info_var(Type, "type_info", VarSet0, VarTypes0,
Var, VarSet1, VarTypes1),
( varset__search_name(TypeVarSet, TypeVar, TypeVarName) ->
string__append("TypeInfo_for_", TypeVarName, VarName),
varset__name_var(VarSet1, Var, VarName, VarSet2)
;
VarSet2 = VarSet1
),
TypeInfoVars = [Var | TypeInfoVars1],
polymorphism__make_head_vars(TypeVars, TypeVarSet,
VarSet2, VarTypes1,
TypeInfoVars1, VarSet, VarTypes).
:- pred polymorphism__new_type_info_var(type, string, varset, map(var, type),
var, varset, map(var, type)).
:- mode polymorphism__new_type_info_var(in, in, in, in, out, out, out) is det.
polymorphism__new_type_info_var(Type, Symbol, VarSet0, VarTypes0,
Var, VarSet, VarTypes) :-
% introduce new variable
varset__new_var(VarSet0, Var, VarSet1),
term__var_to_int(Var, VarNum),
string__int_to_string(VarNum, VarNumStr),
string__append("TypeInfo_", VarNumStr, Name),
varset__name_var(VarSet1, Var, Name, VarSet),
mercury_private_builtin_module(PrivateBuiltin),
construct_type(qualified(PrivateBuiltin, Symbol) - 1, [Type],
UnifyPredType),
map__set(VarTypes0, Var, UnifyPredType, VarTypes).
%---------------------------------------------------------------------------%
:- pred extract_type_info(type, tvar, var, int, list(hlds_goal),
var, poly_info, poly_info).
:- mode extract_type_info(in, in, in, in, out, out, in, out) is det.
extract_type_info(Type, TypeVar, TypeClassInfoVar, Index, Goals,
TypeInfoVar, PolyInfo0, PolyInfo) :-
PolyInfo0 = poly_info(VarSet0, VarTypes0, C, TypeInfoLocns0,
E, F, G, ModuleInfo),
extract_type_info_2(Type, TypeVar, TypeClassInfoVar, Index, ModuleInfo,
Goals, TypeInfoVar, VarSet0, VarTypes0, TypeInfoLocns0,
VarSet, VarTypes, TypeInfoLocns),
PolyInfo = poly_info(VarSet, VarTypes, C, TypeInfoLocns, E, F, G,
ModuleInfo).
:- pred extract_type_info_2(type, tvar, var, int, module_info, list(hlds_goal),
var, varset, map(var, type), map(tvar, type_info_locn),
varset, map(var, type), map(tvar, type_info_locn)).
:- mode extract_type_info_2(in, in, in, in, in, out, out, in, in, in, out, out,
out) is det.
extract_type_info_2(Type, _TypeVar, TypeClassInfoVar, Index, ModuleInfo, Goals,
TypeInfoVar, VarSet0, VarTypes0, TypeInfoLocns0,
VarSet, VarTypes, TypeInfoLocns) :-
% We need a tvarset to pass to get_pred_id_and_proc_id
varset__init(TVarSet0),
varset__new_var(TVarSet0, TVar, TVarSet),
mercury_private_builtin_module(PrivateBuiltin),
ExtractTypeInfo = qualified(PrivateBuiltin,
"type_info_from_typeclass_info"),
construct_type(qualified(PrivateBuiltin, "typeclass_info") - 0, [],
TypeClassInfoType),
construct_type(unqualified("int") - 0, [], IntType),
construct_type(qualified(PrivateBuiltin, "type_info") - 1,
[term__variable(TVar)], TypeInfoType),
get_pred_id_and_proc_id(ExtractTypeInfo, predicate, TVarSet,
[TypeClassInfoType, IntType, TypeInfoType],
ModuleInfo, PredId, ProcId),
polymorphism__make_count_var(Index, VarSet0, VarTypes0, IndexVar,
IndexGoal, VarSet1, VarTypes1),
polymorphism__new_type_info_var(Type, "type_info", VarSet1, VarTypes1,
TypeInfoVar, VarSet2, VarTypes2),
% We have to put an extra type_info at the front of the call to
% type_info_from_typeclass_info, and pass it a bogus value
% because the pred has a type parameter... even though we are
% actually _extracting_ the type_info. Existential typing of
% type_info_from_typeclass_info would fix this.
polymorphism__new_type_info_var(Type, "type_info", VarSet2, VarTypes2,
DummyTypeInfoVar, VarSet, VarTypes),
% Now we put a dummy value in the dummy type-info variable.
polymorphism__init_with_int_constant(DummyTypeInfoVar, 0,
DummyTypeInfoGoal),
% Make the goal info for the call
set__list_to_set([DummyTypeInfoVar, TypeClassInfoVar, IndexVar,
TypeInfoVar], NonLocals),
instmap_delta_from_assoc_list([TypeInfoVar - ground(shared, no)],
InstmapDelta),
goal_info_init(NonLocals, InstmapDelta, det, GoalInfo),
Call = call(PredId, ProcId,
[DummyTypeInfoVar, TypeClassInfoVar, IndexVar, TypeInfoVar],
not_builtin, no, ExtractTypeInfo) - GoalInfo,
Goals = [IndexGoal, DummyTypeInfoGoal, Call],
/* We should do this, except that makes us incorrectly compute the
* non-locals for the goal, since it appears to fixup_quantification
* that the type-info is non-local, but the typeclass-info is not.
% Update the location of the type_info so that we don't go to
% the bother of re-extracting it.
map__det_update(TypeInfoLocns0, TypeVar, type_info(TypeInfoVar),
TypeInfoLocns).
*/
TypeInfoLocns = TypeInfoLocns0.
%---------------------------------------------------------------------------%
% Add a head var for each class constraint, and make an entry in the
% typeinfo locations map for each constrained type var.
:- pred polymorphism__make_typeclass_info_head_vars(list(class_constraint),
module_info, varset, map(var, type), list(var),
map(var, type_info_locn), list(var), varset, map(var, type)).
:- mode polymorphism__make_typeclass_info_head_vars(in, in, in, in,
out, out, out, out, out) is det.
polymorphism__make_typeclass_info_head_vars(ClassContext, ModuleInfo, VarSet0,
VarTypes0, ExtraHeadVars, TypeClassInfoMap, ConstrainedTVars,
VarSet, VarTypes) :-
% initialise the new accumulators
ExtraHeadVars0 = [],
map__init(TypeClassInfoMap0),
% do the work
polymorphism__make_typeclass_info_head_vars_2(ClassContext, ModuleInfo,
VarSet0, VarSet,
VarTypes0, VarTypes,
ExtraHeadVars0, ExtraHeadVars1,
TypeClassInfoMap0, TypeClassInfoMap),
% A type var has a location in a typeclass info iff it is
% constrained
map__keys(TypeClassInfoMap, ConstrainedTVars),
% The ExtraHeadVars are built up in reverse
list__reverse(ExtraHeadVars1, ExtraHeadVars).
:- pred polymorphism__make_typeclass_info_head_vars_2(list(class_constraint),
module_info, varset, varset,
map(var, type), map(var, type),
list(var), list(var),
map(var, type_info_locn), map(var, type_info_locn)).
:- mode polymorphism__make_typeclass_info_head_vars_2(in, in, in, out, in, out,
in, out, in, out) is det.
polymorphism__make_typeclass_info_head_vars_2([], _,
VarSet, VarSet,
VarTypes, VarTypes,
ExtraHeadVars, ExtraHeadVars,
TypeInfoLocations, TypeInfoLocations).
polymorphism__make_typeclass_info_head_vars_2([C|Cs], ModuleInfo,
VarSet0, VarSet,
VarTypes0, VarTypes,
ExtraHeadVars0, ExtraHeadVars,
TypeClassInfoMap0, TypeClassInfoMap) :-
C = constraint(ClassName0, ClassTypes),
% Work out how many superclass the class has
list__length(ClassTypes, ClassArity),
ClassId = class_id(ClassName0, ClassArity),
module_info_classes(ModuleInfo, ClassTable),
map__lookup(ClassTable, ClassId, ClassDefn),
ClassDefn = hlds_class_defn(SuperClasses, _, _, _, _),
list__length(SuperClasses, NumSuperClasses),
unqualify_name(ClassName0, ClassName),
% Make a new variable to contain the dictionary for this
% typeclass constraint
polymorphism__new_typeclass_info_var(VarSet0, VarTypes0, ClassName,
Var, VarSet1, VarTypes1),
ExtraHeadVars1 = [Var | ExtraHeadVars0],
% 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 is NumSuperClasses + 1,
term__vars_list(ClassTypes, ClassTypeVars0),
MakeIndex = lambda([Elem0::in, Elem::out,
Index0::in, Index::out] is det,
(
Elem = Elem0 - Index0,
Index is Index0 + 1,
% the following call is a work-around for a compiler
% bug with intermodule optimization: it is needed to
% resolve a type ambiguity
is_pair(Elem)
)),
list__map_foldl(MakeIndex, ClassTypeVars0, ClassTypeVars, First, _),
% Work out which ones haven't been seen before
IsNew = lambda([TypeVar0::in] is semidet,
(
TypeVar0 = TypeVar - _Index,
\+ map__search(TypeClassInfoMap0, TypeVar, _)
)),
list__filter(IsNew, ClassTypeVars, 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 = lambda([IndexedTypeVar::in,
LocnMap0::in, LocnMap::out] is det,
(
IndexedTypeVar = TheTypeVar - Location,
map__det_insert(LocnMap0, TheTypeVar,
typeclass_info(Var, Location), LocnMap)
)),
list__foldl(MakeEntry, NewClassTypeVars,
TypeClassInfoMap0, TypeClassInfoMap1),
% Handle the rest of the constraints
polymorphism__make_typeclass_info_head_vars_2(Cs, ModuleInfo,
VarSet1, VarSet,
VarTypes1, VarTypes,
ExtraHeadVars1, ExtraHeadVars,
TypeClassInfoMap1, TypeClassInfoMap).
:- pred is_pair(pair(_, _)::in) is det.
is_pair(_).
:- pred polymorphism__new_typeclass_info_var(varset, map(var, type),
string, var,
varset, map(var, type)).
:- mode polymorphism__new_typeclass_info_var(in, in, in, out, out, out) is det.
polymorphism__new_typeclass_info_var(VarSet0, VarTypes0, ClassName,
Var, VarSet, VarTypes) :-
% introduce new variable
varset__new_var(VarSet0, Var, VarSet1),
string__append("TypeClassInfo_for_", ClassName, Name),
varset__name_var(VarSet1, Var, Name, VarSet),
mercury_private_builtin_module(PrivateBuiltin),
construct_type(qualified(PrivateBuiltin, "typeclass_info") - 0,
[], DictionaryType),
map__set(VarTypes0, Var, DictionaryType, VarTypes).
%---------------------------------------------------------------------------%
% Expand the bodies of all class methods for typeclasses which
% were defined in this module. The expansion involves inserting a
% class_method_call with the appropriate arguments, which is
% responsible for extracting the appropriate part of the dictionary.
:- pred polymorphism__expand_class_method_bodies(module_info, module_info).
:- mode polymorphism__expand_class_method_bodies(in, out) is det.
polymorphism__expand_class_method_bodies(ModuleInfo0, ModuleInfo) :-
module_info_classes(ModuleInfo0, Classes),
module_info_name(ModuleInfo0, ModuleName),
map__keys(Classes, ClassIds0),
% Don't expand classes from other modules
FromThisModule = lambda([ClassId::in] is semidet,
(
ClassId = class_id(qualified(ModuleName, _), _)
)),
list__filter(FromThisModule, ClassIds0, ClassIds),
map__apply_to_list(ClassIds, Classes, ClassDefns),
list__foldl(expand_bodies, ClassDefns, ModuleInfo0, ModuleInfo).
:- pred expand_bodies(hlds_class_defn, module_info, module_info).
:- mode expand_bodies(in, in, out) is det.
expand_bodies(hlds_class_defn(_, _, Interface, _, _),
ModuleInfo0, ModuleInfo) :-
list__foldl2(expand_one_body, Interface, 1, _, ModuleInfo0, ModuleInfo).
:- pred expand_one_body(hlds_class_proc, int, int, module_info, module_info).
:- mode expand_one_body(in, in, out, in, out) is det.
expand_one_body(hlds_class_proc(PredId, ProcId), ProcNum0, ProcNum,
ModuleInfo0, ModuleInfo) :-
module_info_preds(ModuleInfo0, PredTable0),
map__lookup(PredTable0, PredId, PredInfo0),
pred_info_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 = [Head|_]
->
InstanceConstraint = Head
;
error("expand_one_body: class method is not constrained")
),
proc_info_typeclass_info_varmap(ProcInfo0, VarMap),
map__lookup(VarMap, InstanceConstraint, TypeClassInfoVar),
proc_info_headvars(ProcInfo0, HeadVars0),
proc_info_vartypes(ProcInfo0, Types0),
proc_info_argmodes(ProcInfo0, Modes0),
proc_info_declared_determinism(ProcInfo0, Detism0),
(
Detism0 = yes(Detism1)
->
Detism = Detism1
;
error("missing determinism decl. How did we get this far?")
),
% 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, HeadVars1),
delete_nth(Modes0, N, Modes1)
->
HeadVars = HeadVars1,
map__apply_to_list(HeadVars1, Types0, Types),
Modes = Modes1
;
error("expand_one_body: typeclass_info var not found")
),
BodyGoalExpr = class_method_call(TypeClassInfoVar, ProcNum0,
HeadVars, Types, Modes, Detism),
% Make the goal info for the call.
set__list_to_set(HeadVars0, NonLocals),
instmap_delta_from_mode_list(HeadVars0, Modes0, ModuleInfo0,
InstmapDelta),
goal_info_init(NonLocals, InstmapDelta, Detism, GoalInfo),
BodyGoal = BodyGoalExpr - GoalInfo,
proc_info_set_goal(ProcInfo0, BodyGoal, ProcInfo),
map__det_update(ProcTable0, ProcId, ProcInfo, ProcTable),
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
map__det_update(PredTable0, PredId, PredInfo, PredTable),
module_info_set_preds(ModuleInfo0, PredTable, ModuleInfo),
ProcNum is ProcNum0 + 1.
:- pred delete_nth(list(T)::in, int::in, list(T)::out) is semidet.
delete_nth([X|Xs], N0, Result) :-
(
N0 > 1
->
N is N0 - 1,
delete_nth(Xs, N, TheRest),
Result = [X|TheRest]
;
Result = Xs
).
%---------------------------------------------------------------------------%
:- pred polymorphism__get_module_info(module_info, poly_info, poly_info).
:- mode polymorphism__get_module_info(out, in, out) is det.
polymorphism__get_module_info(ModuleInfo, PolyInfo, PolyInfo) :-
PolyInfo = poly_info(_, _, _, _, _, _, _, ModuleInfo).
:- pred polymorphism__set_module_info(module_info, poly_info, poly_info).
:- mode polymorphism__set_module_info(in, in, out) is det.
polymorphism__set_module_info(ModuleInfo, PolyInfo0, PolyInfo) :-
PolyInfo0 = poly_info(A, B, C, D, E, F, G, _),
PolyInfo = poly_info(A, B, C, D, E, F, G, ModuleInfo).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%