mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-16 14:25:56 +00:00
Estimated hours taken: 1200
Aditi compilation.
compiler/options.m:
The documentation for these is commented out because the Aditi
system is not currently useful to the general public.
--aditi: enable Aditi compilation.
--dump-rl: write the intermediate RL to `<module>.rl_dump'.
--dump-rl-bytecode: write a text version of the bytecodes
to `<module>.rla'
--aditi-only: don't produce a `.c' file.
--filenames-from-stdin: accept a list of filenames to compile
from stdin. This is used by the query shell.
--optimize-rl, --optimize-rl-cse, --optimize-rl-invariants,
--optimize-rl-index, --detect-rl-streams:
Options to control RL optimization passes.
--aditi-user:
Default owner of any Aditi procedures,
defaults to $USER or "guest".
--generate-schemas:
write schemas for base relations to `<module>'.base_schema
and schemas for derived relations to `<module>'.derived_schema.
This is used by the query shell.
compiler/handle_options.m:
Handle the default for --aditi-user.
compiler/hlds_pred.m:
compiler/prog_data.m:
compiler/prog_io_pragma.m:
compiler/make_hlds.m:
Add some Aditi pragma declarations - `aditi', `supp_magic', `context',
`naive', `psn' (predicate semi-naive), `aditi_memo', `aditi_no_memo',
`base_relation', `owner' and `index'.
Separate out code to parse a predicate name and arity.
compiler/hlds_pred.m:
Add predicates to identify Aditi procedures.
Added markers `generate_inline' and `aditi_interface', which
are used internally for Aditi code generation.
Add an `owner' field to pred_infos, which is used for database
security checks.
Add a field to pred_infos to hold the list of indexes for a base
relation.
compiler/make_hlds.m:
Some pragmas must be exported if the corresponding predicates
are exported, check this.
Make sure stratification of Aditi procedures is checked.
Predicates with a mode declaration but no type declaration
are no longer assumed to be local.
Set the `do_aditi_compilation' field of the module_info if there
are any local Aditi procedures or base relations.
Check that `--aditi' is set if Aditi compilation is required.
compiler/post_typecheck.m:
Check that every Aditi predicate has an `aditi__state' argument,
which is used to ensure sequencing of updates and that Aditi
procedures are only called within transactions.
compiler/dnf.m:
Changed the definition of disjunctive normal form slightly
so that a call followed by some atomic goals not including
any database calls is considered atomic. magic.m can handle
this kind of goal, and it results in more efficient RL code.
compiler/hlds_module.m:
compiler/dependency_graph.m:
Added dependency_graph__get_scc_entry_points which finds
the procedures in an SCC which could be called from outside.
Added a new field to the dependency_info, the
aditi_dependency_ordering. This contains all Aditi SCCs of
the original program, with multiple SCCs merged where
possible to improve the effectiveness of differential evaluation
and the low level RL optimizations.
compiler/hlds_module.m:
Add a field to record whether there are any local Aditi procedures
in the current module.
Added versions of module_info_pred_proc_info and
module_info_set_pred_proc_info which take a pred_proc_id,
not a separate pred_id and proc_id.
compiler/polymorphism.m:
compiler/lambda.m:
Make sure that predicates created for closures in Aditi procedures
have the correct markers.
compiler/goal_util.m:
Added goal_util__switch_to_disjunction,
goal_util__case_to_disjunct (factored out from simplify.m)
and goal_util__if_then_else_to_disjunction. These are
require because supplementary magic sets can't handle
if-then-elses or switches.
compiler/type_util.m:
Added type_is_aditi_state/1.
compiler/mode_util.m:
Added partition_args/5 which partitions a list of arguments
into inputs and others.
compiler/inlining.m:
Don't inline memoed procedures.
Don't inline Aditi procedures into non-Aditi procedures.
compiler/intermod.m:
Handle Aditi markers.
Clean up handling of markers which should not appear in `.opt' files.
compiler/simplify.m:
Export a slightly different interface for use by magic.m.
Remove explicit quantifications where possible.
Merge multiple nested quantifications.
Don't report infinite recursion warnings for Aditi procedures.
compiler/prog_out.m:
Generalised the code to output a module list to write any list.
compiler/code_gen.m:
compiler/arg_info.m:
Don't process Aditi procedures.
compiler/mercury_compile.m:
Call magic.m and rl_gen.m.
Don't perform the low-level annotation passes on Aditi procedures.
Remove calls to constraint.m - sometime soon a rewritten version
will be called directly from deforestation.
compiler/passes_aux.m:
Add predicates to process only non-Aditi procedures.
compiler/llds.m:
compiler/llds_out.m:
Added new `code_addr' enum members, do_{det,semidet,nondet}_aditi_call,
which are defined in extras/aditi/aditi.m.
compiler/call_gen.m:
Handle generation of do_*_aditi_call.
compiler/llds_out.m:
Write the RL code for the module as a constant char array
in the `.c' file.
compiler/term_errors.m:
compiler/error_util.m:
Move code to describe predicates into error_util.m
Allow the caller to explicitly add line breaks.
Added error_util:list_to_pieces to format a list of
strings.
Reordered some arguments for currying.
compiler/hlds_out.m:
Don't try to print clauses if there are none.
runtime/mercury_init.h:
util/mkinit.c:
scripts/c2init.in:
Added a function `mercury__load_aditi_rl_code()' to the generated
`<module>_init.c' file which throws all the RL code for the program
at the database. This should be called at connection time by
`aditi__connect'.
Added an option `--aditi' which controls the output
`mercury__load_aditi_rl_code()'.
compiler/notes/compiler_design.html:
Document the new files.
Mmakefile:
bindist/Mmakefile:
Don't distribute extras/aditi yet.
New files:
compiler/magic.m:
compiler/magic_util.m:
Supplementary magic sets transformation. Report errors
for constructs that Aditi can't handle.
compiler/context.m:
Supplementary context transformation.
compiler/rl_gen.m:
compiler/rl_relops.m:
Aditi code generation.
compiler/rl_info.m:
Code generator state.
compiler/rl.m:
Intermediate RL representation.
compiler/rl_util:
Predicates to collect information about RL instructions.
compiler/rl_dump.m:
Print out the representation in rl.m.
compiler/rl_opt.m:
Control low-level RL optimizations.
compiler/rl_block.m:
Break a procedure into basic blocks.
compiler/rl_analyse.m:
Generic dataflow analysis for RL procedures.
compiler/rl_liveness.m:
Make sure all relations are initialised before used, clear
references to relations that are no longer required.
compiler/rl_loop.m:
Loop invariant removal.
compiler/rl_block_opt.m:
CSE and instruction merging on basic blocks.
compiler/rl_key.m:
Detect upper/lower bounds for which a goal could succeed.
compiler/rl_sort.m:
Use indexing for joins and projections.
Optimize away unnecessary sorting and indexing.
compiler/rl_stream.m:
Detect relations which don't need to be materialised.
compiler/rl_code.m:
RL bytecode definitions. Automatically generated from the Aditi
header files.
compiler/rl_out.m:
compiler/rl_file.m:
Output the RL bytecodes in binary to <module>.rlo (for use by Aditi)
and in text to <module>.rla (for use by the RL interpreter).
Also output the schema information if --generate-schemas is set.
compiler/rl_exprn.m:
Generate bytecodes for join conditions.
extras/aditi/Mmakefile:
extras/aditi/aditi.m:
Definitions of some Aditi library predicates and the
interfacing and transaction processing code.
516 lines
20 KiB
Mathematica
516 lines
20 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: lambda.m
|
|
% main author: fjh
|
|
|
|
% This module is a pass over the HLDS to deal with lambda expressions.
|
|
%
|
|
% Lambda expressions are converted into separate predicates, so for
|
|
% example we translate
|
|
%
|
|
% :- pred p(int::in) is det.
|
|
% p(X) :-
|
|
% V__1 = lambda([Y::out] is nondet, q(Y, X))),
|
|
% solutions(V__1, List),
|
|
% ...
|
|
% :- pred q(int::out, int::in) is nondet.
|
|
%
|
|
% into
|
|
%
|
|
% p(X) :-
|
|
% V__1 = '__LambdaGoal__1'(X)
|
|
% solutions(V__1, List),
|
|
% ...
|
|
%
|
|
% :- pred '__LambdaGoal__1'(int::in, int::out) is nondet.
|
|
% '__LambdaGoal__1'(X, Y) :- q(Y, X).
|
|
%
|
|
%
|
|
% Note that the mode checker requires that a lambda expression
|
|
% not bind any of the non-local variables such as `X' in the above
|
|
% example.
|
|
%
|
|
% Similarly, a lambda expression may not bind any of the type_infos for
|
|
% those variables; that is, none of the non-local variables
|
|
% should be existentially typed (from the perspective of the lambda goal).
|
|
% When we run the polymorphism.m pass before mode checking, this will
|
|
% be checked by mode analysis. XXX But currently it is not checked.
|
|
%
|
|
% It might be OK to allow the parameters of the lambda goal to be
|
|
% existentially typed, but currently that is not supported.
|
|
% One difficulty is that it's hard to determine here which type variables
|
|
% should be existentially quantified. The information is readily
|
|
% available during type inference, and really type inference should save
|
|
% that information in a field in the lambda_goal struct, but currently it
|
|
% doesn't; it saves the head_type_params field in the pred_info, which
|
|
% tells us which type variables where produced by the body, but for
|
|
% any given lambda goal we don't know whether the type variable was
|
|
% produced by something outside the lambda goal or by something inside
|
|
% the lambda goal (only in the latter case should it be existentially
|
|
% quantified).
|
|
% The other difficulty is that taking the address of a predicate with an
|
|
% existential type would require second-order polymorphism: for a predicate
|
|
% declared as `:- some [T] pred p(int, T)', the expression `p' must have
|
|
% type `some [T] pred(int, T)', which is quite a different thing to saying
|
|
% that there is some type `T' for which `p' has type `pred(int, T)' --
|
|
% we don't know what `T' is until the predicate is called, and it might
|
|
% be different for each call.
|
|
% Currently we don't support second-order polymorphism, so we
|
|
% don't support existentially typed lambda expressions either.
|
|
%
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module (lambda).
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_module, hlds_pred, hlds_goal, hlds_data, prog_data.
|
|
:- import_module list, map, set.
|
|
|
|
:- pred lambda__process_pred(pred_id, module_info, module_info).
|
|
:- mode lambda__process_pred(in, in, out) is det.
|
|
|
|
:- pred lambda__transform_lambda(pred_or_func, string, list(prog_var),
|
|
list(mode), determinism, list(prog_var), set(prog_var),
|
|
hlds_goal, unification, prog_varset, map(prog_var, type),
|
|
class_constraints, tvarset, map(tvar, type_info_locn),
|
|
map(class_constraint, prog_var), pred_markers, aditi_owner,
|
|
module_info, unify_rhs, unification, module_info).
|
|
:- mode lambda__transform_lambda(in, in, in, in, in, in, in, in, in,
|
|
in, in, in, in, in, in, in, in, in, out, out, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module make_hlds, globals, options, term, varset.
|
|
:- import_module goal_util, prog_util, mode_util, inst_match, llds, arg_info.
|
|
|
|
:- import_module bool, string, std_util, require.
|
|
|
|
:- type lambda_info --->
|
|
lambda_info(
|
|
prog_varset, % from the proc_info
|
|
map(prog_var, type), % from the proc_info
|
|
class_constraints, % from the pred_info
|
|
tvarset, % from the proc_info
|
|
map(tvar, type_info_locn),
|
|
% from the proc_info
|
|
% (typeinfos)
|
|
map(class_constraint, prog_var),
|
|
% from the proc_info
|
|
% (typeclass_infos)
|
|
pred_markers, % from the pred_info
|
|
pred_or_func,
|
|
string, % pred/func name
|
|
aditi_owner,
|
|
module_info
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This whole section just traverses the module structure.
|
|
|
|
lambda__process_pred(PredId, ModuleInfo0, ModuleInfo) :-
|
|
module_info_pred_info(ModuleInfo0, PredId, PredInfo),
|
|
pred_info_procids(PredInfo, ProcIds),
|
|
lambda__process_procs(PredId, ProcIds, ModuleInfo0, ModuleInfo).
|
|
|
|
:- pred lambda__process_procs(pred_id, list(proc_id), module_info, module_info).
|
|
:- mode lambda__process_procs(in, in, in, out) is det.
|
|
|
|
lambda__process_procs(_PredId, [], ModuleInfo, ModuleInfo).
|
|
lambda__process_procs(PredId, [ProcId | ProcIds], ModuleInfo0, ModuleInfo) :-
|
|
lambda__process_proc(PredId, ProcId, ModuleInfo0, ModuleInfo1),
|
|
lambda__process_procs(PredId, ProcIds, ModuleInfo1, ModuleInfo).
|
|
|
|
:- pred lambda__process_proc(pred_id, proc_id, module_info, module_info).
|
|
:- mode lambda__process_proc(in, in, in, out) is det.
|
|
|
|
lambda__process_proc(PredId, ProcId, ModuleInfo0, ModuleInfo) :-
|
|
module_info_preds(ModuleInfo0, PredTable0),
|
|
map__lookup(PredTable0, PredId, PredInfo0),
|
|
pred_info_procedures(PredInfo0, ProcTable0),
|
|
map__lookup(ProcTable0, ProcId, ProcInfo0),
|
|
|
|
lambda__process_proc_2(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, ModuleInfo).
|
|
|
|
:- pred lambda__process_proc_2(proc_info, pred_info, module_info,
|
|
proc_info, pred_info, module_info).
|
|
:- mode lambda__process_proc_2(in, in, in, out, out, out) is det.
|
|
|
|
lambda__process_proc_2(ProcInfo0, PredInfo0, ModuleInfo0,
|
|
ProcInfo, PredInfo, ModuleInfo) :-
|
|
% grab the appropriate fields from the pred_info and proc_info
|
|
pred_info_name(PredInfo0, PredName),
|
|
pred_info_get_is_pred_or_func(PredInfo0, PredOrFunc),
|
|
pred_info_typevarset(PredInfo0, TypeVarSet0),
|
|
pred_info_get_markers(PredInfo0, Markers),
|
|
pred_info_get_class_context(PredInfo0, Constraints0),
|
|
pred_info_get_aditi_owner(PredInfo0, Owner),
|
|
proc_info_varset(ProcInfo0, VarSet0),
|
|
proc_info_vartypes(ProcInfo0, VarTypes0),
|
|
proc_info_goal(ProcInfo0, Goal0),
|
|
proc_info_typeinfo_varmap(ProcInfo0, TVarMap0),
|
|
proc_info_typeclass_info_varmap(ProcInfo0, TCVarMap0),
|
|
|
|
% process the goal
|
|
Info0 = lambda_info(VarSet0, VarTypes0, Constraints0, TypeVarSet0,
|
|
TVarMap0, TCVarMap0, Markers, PredOrFunc,
|
|
PredName, Owner, ModuleInfo0),
|
|
lambda__process_goal(Goal0, Goal, Info0, Info),
|
|
Info = lambda_info(VarSet, VarTypes, Constraints, TypeVarSet,
|
|
TVarMap, TCVarMap, _, _, _, _, ModuleInfo),
|
|
|
|
% set the new values of the fields in proc_info and pred_info
|
|
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
|
|
proc_info_set_varset(ProcInfo1, VarSet, ProcInfo2),
|
|
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo3),
|
|
proc_info_set_typeinfo_varmap(ProcInfo3, TVarMap, ProcInfo4),
|
|
proc_info_set_typeclass_info_varmap(ProcInfo4, TCVarMap, ProcInfo),
|
|
pred_info_set_typevarset(PredInfo0, TypeVarSet, PredInfo1),
|
|
pred_info_set_class_context(PredInfo1, Constraints, PredInfo).
|
|
|
|
:- pred lambda__process_goal(hlds_goal, hlds_goal,
|
|
lambda_info, lambda_info).
|
|
:- mode lambda__process_goal(in, out, in, out) is det.
|
|
|
|
lambda__process_goal(Goal0 - GoalInfo0, Goal) -->
|
|
lambda__process_goal_2(Goal0, GoalInfo0, Goal).
|
|
|
|
:- pred lambda__process_goal_2(hlds_goal_expr, hlds_goal_info,
|
|
hlds_goal, lambda_info, lambda_info).
|
|
:- mode lambda__process_goal_2(in, in, out, in, out) is det.
|
|
|
|
lambda__process_goal_2(unify(XVar, Y, Mode, Unification, Context), GoalInfo,
|
|
Unify - GoalInfo) -->
|
|
( { Y = lambda_goal(PredOrFunc, NonLocalVars, Vars,
|
|
Modes, Det, LambdaGoal0) } ->
|
|
% for lambda expressions, we must convert the lambda expression
|
|
% into a new predicate
|
|
lambda__process_lambda(PredOrFunc, Vars, Modes, Det,
|
|
NonLocalVars, LambdaGoal0,
|
|
Unification, Y1, Unification1),
|
|
{ Unify = unify(XVar, Y1, Mode, Unification1, Context) }
|
|
;
|
|
% ordinary unifications are left unchanged
|
|
{ Unify = unify(XVar, Y, Mode, Unification, Context) }
|
|
).
|
|
|
|
% the rest of the clauses just process goals recursively
|
|
|
|
lambda__process_goal_2(conj(Goals0), GoalInfo, conj(Goals) - GoalInfo) -->
|
|
lambda__process_goal_list(Goals0, Goals).
|
|
lambda__process_goal_2(par_conj(Goals0, SM), GoalInfo,
|
|
par_conj(Goals, SM) - GoalInfo) -->
|
|
lambda__process_goal_list(Goals0, Goals).
|
|
lambda__process_goal_2(disj(Goals0, SM), GoalInfo, disj(Goals, SM) - GoalInfo)
|
|
-->
|
|
lambda__process_goal_list(Goals0, Goals).
|
|
lambda__process_goal_2(not(Goal0), GoalInfo, not(Goal) - GoalInfo) -->
|
|
lambda__process_goal(Goal0, Goal).
|
|
lambda__process_goal_2(switch(Var, CanFail, Cases0, SM), GoalInfo,
|
|
switch(Var, CanFail, Cases, SM) - GoalInfo) -->
|
|
lambda__process_cases(Cases0, Cases).
|
|
lambda__process_goal_2(some(Vars, Goal0), GoalInfo,
|
|
some(Vars, Goal) - GoalInfo) -->
|
|
lambda__process_goal(Goal0, Goal).
|
|
lambda__process_goal_2(if_then_else(Vars, A0, B0, C0, SM), GoalInfo,
|
|
if_then_else(Vars, A, B, C, SM) - GoalInfo) -->
|
|
lambda__process_goal(A0, A),
|
|
lambda__process_goal(B0, B),
|
|
lambda__process_goal(C0, C).
|
|
lambda__process_goal_2(higher_order_call(A,B,C,D,E,F), GoalInfo,
|
|
higher_order_call(A,B,C,D,E,F) - GoalInfo) -->
|
|
[].
|
|
lambda__process_goal_2(class_method_call(A,B,C,D,E,F), GoalInfo,
|
|
class_method_call(A,B,C,D,E,F) - GoalInfo) -->
|
|
[].
|
|
lambda__process_goal_2(call(A,B,C,D,E,F), GoalInfo,
|
|
call(A,B,C,D,E,F) - GoalInfo) -->
|
|
[].
|
|
lambda__process_goal_2(pragma_c_code(A,B,C,D,E,F,G), GoalInfo,
|
|
pragma_c_code(A,B,C,D,E,F,G) - GoalInfo) -->
|
|
[].
|
|
|
|
:- pred lambda__process_goal_list(list(hlds_goal), list(hlds_goal),
|
|
lambda_info, lambda_info).
|
|
:- mode lambda__process_goal_list(in, out, in, out) is det.
|
|
|
|
lambda__process_goal_list([], []) --> [].
|
|
lambda__process_goal_list([Goal0 | Goals0], [Goal | Goals]) -->
|
|
lambda__process_goal(Goal0, Goal),
|
|
lambda__process_goal_list(Goals0, Goals).
|
|
|
|
:- pred lambda__process_cases(list(case), list(case),
|
|
lambda_info, lambda_info).
|
|
:- mode lambda__process_cases(in, out, in, out) is det.
|
|
|
|
lambda__process_cases([], []) --> [].
|
|
lambda__process_cases([case(ConsId, Goal0) | Cases0],
|
|
[case(ConsId, Goal) | Cases]) -->
|
|
lambda__process_goal(Goal0, Goal),
|
|
lambda__process_cases(Cases0, Cases).
|
|
|
|
:- pred lambda__process_lambda(pred_or_func, list(prog_var), list(mode),
|
|
determinism, list(prog_var), hlds_goal, unification,
|
|
unify_rhs, unification, lambda_info, lambda_info).
|
|
:- mode lambda__process_lambda(in, in, in, in, in, in, in, out, out,
|
|
in, out) is det.
|
|
|
|
lambda__process_lambda(PredOrFunc, Vars, Modes, Det, OrigNonLocals0, LambdaGoal,
|
|
Unification0, Functor, Unification, LambdaInfo0, LambdaInfo) :-
|
|
LambdaInfo0 = lambda_info(VarSet, VarTypes, Constraints, TVarSet,
|
|
TVarMap, TCVarMap, Markers, POF, PredName, Owner, ModuleInfo0),
|
|
% XXX existentially typed lambda expressions are not yet supported
|
|
% (see the documentation at top of this file)
|
|
ExistQVars = [],
|
|
LambdaGoal = _ - LambdaGoalInfo,
|
|
goal_info_get_nonlocals(LambdaGoalInfo, LambdaNonLocals),
|
|
goal_util__extra_nonlocal_typeinfos(TVarMap, TCVarMap, VarTypes,
|
|
ExistQVars, LambdaNonLocals, ExtraTypeInfos),
|
|
lambda__transform_lambda(PredOrFunc, PredName, Vars, Modes, Det,
|
|
OrigNonLocals0, ExtraTypeInfos, LambdaGoal, Unification0,
|
|
VarSet, VarTypes, Constraints, TVarSet, TVarMap, TCVarMap,
|
|
Markers, Owner, ModuleInfo0, Functor, Unification, ModuleInfo),
|
|
LambdaInfo = lambda_info(VarSet, VarTypes, Constraints, TVarSet,
|
|
TVarMap, TCVarMap, Markers, POF, PredName, Owner, ModuleInfo).
|
|
|
|
lambda__transform_lambda(PredOrFunc, OrigPredName, Vars, Modes, Detism,
|
|
OrigVars, ExtraTypeInfos, LambdaGoal, Unification0,
|
|
VarSet, VarTypes, Constraints, TVarSet, TVarMap, TCVarMap,
|
|
Markers, Owner, ModuleInfo0, Functor,
|
|
Unification, ModuleInfo) :-
|
|
(
|
|
Unification0 = construct(Var0, _, _, UniModes0)
|
|
->
|
|
Var = Var0,
|
|
UniModes1 = UniModes0
|
|
;
|
|
error("polymorphism__transform_lambda: weird unification")
|
|
),
|
|
|
|
% Optimize a special case: replace
|
|
% `lambda([Y1, Y2, ...] is Detism, p(X1, X2, ..., Y1, Y2, ...))'
|
|
% where `p' has determinism `Detism' with
|
|
% `p(X1, X2, ...)'
|
|
%
|
|
% This optimization is only valid if the modes of the Xi are
|
|
% input, since only input arguments can be curried.
|
|
% It's also only valid if all the inputs in the Yi precede the
|
|
% outputs. It's also not valid if any of the Xi are in the Yi.
|
|
|
|
LambdaGoal = _ - LambdaGoalInfo,
|
|
goal_info_get_nonlocals(LambdaGoalInfo, NonLocals0),
|
|
set__delete_list(NonLocals0, Vars, NonLocals1),
|
|
module_info_globals(ModuleInfo0, Globals),
|
|
|
|
% If typeinfo_liveness is set, all type_infos for the
|
|
% arguments should be included, not just the ones
|
|
% that are used.
|
|
globals__lookup_bool_option(Globals,
|
|
typeinfo_liveness, TypeInfoLiveness),
|
|
( TypeInfoLiveness = yes ->
|
|
set__union(NonLocals1, ExtraTypeInfos, NonLocals)
|
|
;
|
|
NonLocals = NonLocals1
|
|
),
|
|
|
|
set__to_sorted_list(NonLocals, ArgVars1),
|
|
(
|
|
LambdaGoal = call(PredId0, ProcId0, CallVars,
|
|
_, _, PredName0) - _,
|
|
module_info_pred_proc_info(ModuleInfo0, PredId0, ProcId0, _,
|
|
Call_ProcInfo),
|
|
|
|
% check that this procedure uses an args_method which
|
|
% is always directly higher-order callable.
|
|
proc_info_args_method(Call_ProcInfo, Call_ArgsMethod),
|
|
module_info_globals(ModuleInfo0, Globals),
|
|
arg_info__args_method_is_ho_callable(Globals,
|
|
Call_ArgsMethod, yes),
|
|
|
|
list__remove_suffix(CallVars, Vars, InitialVars),
|
|
|
|
% check that none of the variables that we're trying to
|
|
% use as curried arguments are lambda-bound variables
|
|
\+ (
|
|
list__member(InitialVar, InitialVars),
|
|
list__member(InitialVar, Vars)
|
|
),
|
|
|
|
proc_info_interface_code_model(Call_ProcInfo, Call_CodeModel),
|
|
determinism_to_code_model(Detism, CodeModel),
|
|
% Check that the code models are compatible.
|
|
% Note that det is not compatible with semidet,
|
|
% and semidet is not compatible with nondet,
|
|
% since the arguments go in different registers.
|
|
% But det is compatible with nondet.
|
|
( CodeModel = Call_CodeModel
|
|
; CodeModel = model_non, Call_CodeModel = model_det
|
|
),
|
|
% check that the curried arguments are all input
|
|
proc_info_argmodes(Call_ProcInfo, Call_ArgModes),
|
|
list__length(InitialVars, NumInitialVars),
|
|
list__take(NumInitialVars, Call_ArgModes, CurriedArgModes),
|
|
\+ ( list__member(Mode, CurriedArgModes),
|
|
\+ mode_is_input(ModuleInfo0, Mode)
|
|
)
|
|
->
|
|
ArgVars = InitialVars,
|
|
PredId = PredId0,
|
|
ProcId = ProcId0,
|
|
PredName = PredName0,
|
|
ModuleInfo = ModuleInfo0,
|
|
NumArgVars = NumInitialVars,
|
|
mode_util__modes_to_uni_modes(CurriedArgModes, CurriedArgModes,
|
|
ModuleInfo0, UniModes)
|
|
;
|
|
% Prepare to create a new predicate for the lambda
|
|
% expression: work out the arguments, module name, predicate
|
|
% name, arity, arg types, determinism,
|
|
% context, status, etc. for the new predicate.
|
|
|
|
ArgVars = ArgVars1,
|
|
list__append(ArgVars, Vars, AllArgVars),
|
|
|
|
module_info_name(ModuleInfo0, ModuleName),
|
|
module_info_next_lambda_count(ModuleInfo0, LambdaCount,
|
|
ModuleInfo1),
|
|
goal_info_get_context(LambdaGoalInfo, OrigContext),
|
|
term__context_line(OrigContext, OrigLine),
|
|
make_pred_name_with_context(ModuleName, "IntroducedFrom",
|
|
PredOrFunc, OrigPredName, OrigLine,
|
|
LambdaCount, PredName),
|
|
goal_info_get_context(LambdaGoalInfo, LambdaContext),
|
|
% The TVarSet is a superset of what it really ought be,
|
|
% but that shouldn't matter.
|
|
% XXX existentially typed lambda expressions are not
|
|
% yet supported (see the documentation at top of this file)
|
|
ExistQVars = [],
|
|
lambda__uni_modes_to_modes(UniModes1, OrigArgModes),
|
|
|
|
% We have to jump through hoops to work out the mode
|
|
% of the lambda predicate. For introduced
|
|
% type_info arguments, we use the mode "in". For the original
|
|
% non-local vars, we use the modes from `UniModes1'.
|
|
% For the lambda var arguments at the end,
|
|
% we use the mode in the lambda expression.
|
|
|
|
list__length(ArgVars, NumArgVars),
|
|
in_mode(In),
|
|
list__duplicate(NumArgVars, In, InModes),
|
|
map__from_corresponding_lists(ArgVars, InModes,
|
|
ArgModesMap),
|
|
|
|
map__from_corresponding_lists(OrigVars, OrigArgModes,
|
|
OrigArgModesMap),
|
|
map__overlay(ArgModesMap, OrigArgModesMap, ArgModesMap1),
|
|
map__apply_to_list(ArgVars, ArgModesMap1, ArgModes1),
|
|
|
|
% Recompute the uni_modes.
|
|
mode_util__modes_to_uni_modes(ArgModes1, ArgModes1,
|
|
ModuleInfo1, UniModes),
|
|
|
|
list__append(ArgModes1, Modes, AllArgModes),
|
|
map__apply_to_list(AllArgVars, VarTypes, ArgTypes),
|
|
|
|
(
|
|
% Pass through the aditi markers for
|
|
% aggregate query closures.
|
|
% XXX we should differentiate between normal
|
|
% top-down closures and aggregate query closures,
|
|
% possibly by using a different type for aggregate
|
|
% queries. Currently all nondet lambda expressions
|
|
% within Aditi predicates are treated as aggregate
|
|
% inputs.
|
|
determinism_components(Detism, _, at_most_many),
|
|
check_marker(Markers, aditi)
|
|
->
|
|
markers_to_marker_list(Markers, MarkerList0),
|
|
list__filter(
|
|
lambda([Marker::in] is semidet,
|
|
% Pass through only Aditi markers.
|
|
% Don't pass through `context' markers, since
|
|
% they are useless for non-recursive predicates
|
|
% such as the created predicate.
|
|
( Marker = aditi
|
|
; Marker = dnf
|
|
; Marker = psn
|
|
; Marker = naive
|
|
; Marker = supp_magic
|
|
; Marker = aditi_memo
|
|
; Marker = aditi_no_memo
|
|
)),
|
|
MarkerList0, MarkerList),
|
|
marker_list_to_markers(MarkerList, LambdaMarkers)
|
|
;
|
|
init_markers(LambdaMarkers)
|
|
),
|
|
|
|
% Choose an args_method which is always directly callable
|
|
% from do_call_*_closure even if the inputs don't preceed
|
|
% the outputs in the declaration. mercury_ho_call.c requires
|
|
% that procedures which are directly higher-order-called use
|
|
% the compact args_method.
|
|
%
|
|
% Previously we permuted the argument variables so that
|
|
% inputs came before outputs, but that resulted in the
|
|
% HLDS not being type or mode correct which caused problems
|
|
% for some transformations and for rerunning mode analysis.
|
|
arg_info__ho_call_args_method(Globals, ArgsMethod),
|
|
|
|
% Now construct the proc_info and pred_info for the new
|
|
% single-mode predicate, using the information computed above
|
|
|
|
proc_info_create(VarSet, VarTypes, AllArgVars,
|
|
AllArgModes, Detism, LambdaGoal, LambdaContext,
|
|
TVarMap, TCVarMap, ArgsMethod, ProcInfo),
|
|
|
|
pred_info_create(ModuleName, PredName, TVarSet, ExistQVars,
|
|
ArgTypes, true, LambdaContext, local, LambdaMarkers,
|
|
PredOrFunc, Constraints, Owner, ProcInfo,
|
|
ProcId, PredInfo),
|
|
|
|
% save the new predicate in the predicate table
|
|
|
|
module_info_get_predicate_table(ModuleInfo1, PredicateTable0),
|
|
predicate_table_insert(PredicateTable0, PredInfo,
|
|
PredId, PredicateTable),
|
|
module_info_set_predicate_table(ModuleInfo1, PredicateTable,
|
|
ModuleInfo)
|
|
),
|
|
Functor = functor(cons(PredName, NumArgVars), ArgVars),
|
|
ConsId = pred_const(PredId, ProcId),
|
|
Unification = construct(Var, ConsId, ArgVars, UniModes).
|
|
|
|
:- pred lambda__uni_modes_to_modes(list(uni_mode), list(mode)).
|
|
:- mode lambda__uni_modes_to_modes(in, out) is det.
|
|
|
|
% This predicate works out the modes of the original non-local
|
|
% variables of a lambda expression based on the list of uni_mode
|
|
% in the unify_info for the lambda unification.
|
|
|
|
lambda__uni_modes_to_modes([], []).
|
|
lambda__uni_modes_to_modes([UniMode | UniModes], [Mode | Modes]) :-
|
|
UniMode = ((_Initial0 - Initial1) -> (_Final0 - _Final1)),
|
|
Mode = (Initial1 -> Initial1),
|
|
lambda__uni_modes_to_modes(UniModes, Modes).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|