mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
Estimated hours taken: 16 This check-in combines several changes. * Change mercury_compile.pp so that it continues as far as possible after errors. * Split the parts of mercury_compile.pp which handle module imports and exports into a new module called `modules.m'. * Move the polymorphism.m pass after determinism analysis and unique mode checking. This is because unique_modes.m may change the mode in which a unification predicate is called; as a result, we need to do mode checking, determinism analysis, and unique mode checking for new modes of unification predicates which are requested only after unique mode checking. That won't work if we have done polymorphism.m in between mode checking and determinism analysis, since unification predicates are created without type_info arguments, and polymorphism.m cannot be run on just one predicate at a time. (NB. I haven't changed unique_modes.m to actually do this yet.) I also had to move lambda.m after polymorphism.m, since polymorphism.m doesn't handle higher-order pred constants. * Fix determinism analyis of simple_test unifications. The compiler would think that a unification of an inst such as `bound(foo)' with itself could fail. The problem is that there is no `can_fail' field for simple_test unifications, so determinism.m just assumes that they can all fail. I fixed this by changing modes.m to optimize away simple_tests that cannot fail. * Fix determinism analyis of complicated_unifications. Again, determinism analysis just assumed that all complicated_unifications were semidet, because unify_proc.m always declared the out-of-line unification predicates to be semidet. The fix was to pass the determinism inferred during mode analysis to unify_proc__request_unify. However, the '='(in, in) mode still needs to be semidet - its address is taken and put into the type_infos, and so it needs to have the right interface. To handle det '='(in, in) unifications, the determinism also needs to be passed to unify_proc__search_mode_num, which will select the '='(in, in) mode only if the determinism is semidet. (It would of course be better to optimize det '='(in, in) unifications to `true', but they are unlikely to occur much in real code anyway, so that is a low priority.) * Compute the instmap deltas for all variables, not just the non-local variables of a goal, because variables which are not present in a goal can become nondet live if the goal is e.g. a nondet call. mercury_compile.pp: - Rearrange the order of the passes as described above. - Add code to call check_undef_types and check_undef_modes directly rather than via typecheck.m/modes.m. Stop only if we get an undef error; if we get any other sort of type/mode error, we can keep going. - Move lots of code to modules.m. modules.m: New file, containing code moved from mercury_compile.pp. polymorphism.m: Make sure that the goals that we generate have the correct determinism annotations. Handle switches. Put back the call to lambda__transform_lambda. lambda.m: Put back the stuff that allowed lambda.m to be called from polymorphism.m. modes.m, unify_proc.m, call_gen.m, polymorphism.m, Pass the determinism of the unification to unify_proc__request_unify, so that it can declare the right determinism for the unification predicate. (Previously it just assumed that all complicated unifications were `semidet'.) Also pass the determinism to unify_proc__search_mode_num, so that it will generate a new unification pred for deterministic '='(in,in) unifications rather than calling the existing semidet one. modes.m, typecheck.m: Remove the calls to check_undefined_types and check_undefined_modes. They are now instead called directly from mercury_compile.pp. modes.m: Don't call lambda__transform_lambda. Optimize away simple_tests that cannot fail. modes.m, unique_modes.m: Call mode_info_get_instmap/2 rather than mode_info_get_vars_instmap/3. mode_info.m: Delete the predicate mode_info_get_vars_instmap/3.
362 lines
13 KiB
Mathematica
362 lines
13 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995 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).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module (lambda).
|
|
:- interface.
|
|
:- import_module hlds.
|
|
:- import_module list, set, map.
|
|
:- import_module varset, term.
|
|
:- import_module prog_io.
|
|
|
|
:- pred lambda__process_pred(pred_id, module_info, module_info).
|
|
:- mode lambda__process_pred(in, in, out) is det.
|
|
|
|
:- pred lambda__transform_lambda(list(var), list(mode), determinism,
|
|
set(var), hlds__goal, unification,
|
|
varset, map(var, type), tvarset, module_info,
|
|
unify_rhs, unification, module_info).
|
|
:- mode lambda__transform_lambda(in, in, in, in, in, in, in, in, in, in,
|
|
out, out, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module string, std_util, require.
|
|
:- import_module make_hlds.
|
|
|
|
:- type lambda_info --->
|
|
lambda_info(
|
|
varset, % from the proc_info
|
|
map(var, type), % from the proc_info
|
|
tvarset, % from the proc_info
|
|
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__set(ProcTable1, ProcId, ProcInfo, ProcTable),
|
|
pred_info_set_procedures(PredInfo1, ProcTable, PredInfo),
|
|
module_info_preds(ModuleInfo1, PredTable1),
|
|
map__set(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_typevarset(PredInfo0, TypeVarSet0),
|
|
proc_info_variables(ProcInfo0, VarSet0),
|
|
proc_info_vartypes(ProcInfo0, VarTypes0),
|
|
proc_info_goal(ProcInfo0, Goal0),
|
|
|
|
% process the goal
|
|
Info0 = lambda_info(VarSet0, VarTypes0, TypeVarSet0, ModuleInfo0),
|
|
lambda__process_goal(Goal0, Goal, Info0, Info),
|
|
Info = lambda_info(VarSet, VarTypes, TypeVarSet, ModuleInfo),
|
|
|
|
% set the new values of the fields in proc_info and pred_info
|
|
proc_info_set_goal(ProcInfo0, Goal, ProcInfo1),
|
|
proc_info_set_variables(ProcInfo1, VarSet, ProcInfo2),
|
|
proc_info_set_vartypes(ProcInfo2, VarTypes, ProcInfo),
|
|
pred_info_set_typevarset(PredInfo0, TypeVarSet, 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(Vars, Modes, Det, LambdaGoal0) } ->
|
|
% for lambda expressions, we must convert the lambda expression
|
|
% into a new predicate
|
|
{ LambdaGoal0 = _ - GoalInfo0 },
|
|
{ goal_info_get_nonlocals(GoalInfo0, NonLocals0) },
|
|
lambda__process_lambda(Vars, Modes, Det, NonLocals0,
|
|
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(disj(Goals0), GoalInfo, disj(Goals) - 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), GoalInfo,
|
|
switch(Var, CanFail, Cases) - 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), GoalInfo,
|
|
if_then_else(Vars, A, B, C) - GoalInfo) -->
|
|
lambda__process_goal(A0, A),
|
|
lambda__process_goal(B0, B),
|
|
lambda__process_goal(C0, C).
|
|
lambda__process_goal_2(call(A,B,C,D,E,F,G), GoalInfo,
|
|
call(A,B,C,D,E,F,G) - GoalInfo) -->
|
|
[].
|
|
lambda__process_goal_2(pragma_c_code(A,B,C,D,E), GoalInfo,
|
|
pragma_c_code(A,B,C,D,E) - 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(list(var), list(mode), determinism,
|
|
set(var), hlds__goal, unification, unify_rhs, unification,
|
|
lambda_info, lambda_info).
|
|
:- mode lambda__process_lambda(in, in, in, in, in, in, out, out,
|
|
in, out) is det.
|
|
|
|
lambda__process_lambda(Vars, Modes, Det, OrigNonLocals0, LambdaGoal,
|
|
Unification0, Functor, Unification, LambdaInfo0, LambdaInfo) :-
|
|
LambdaInfo0 = lambda_info(VarSet, VarTypes, TVarSet, ModuleInfo0),
|
|
lambda__transform_lambda(Vars, Modes, Det, OrigNonLocals0, LambdaGoal,
|
|
Unification0, VarSet, VarTypes, TVarSet, ModuleInfo0,
|
|
Functor, Unification, ModuleInfo),
|
|
LambdaInfo = lambda_info(VarSet, VarTypes, TVarSet, ModuleInfo).
|
|
|
|
lambda__transform_lambda(Vars, Modes, Det, OrigNonLocals0, LambdaGoal,
|
|
Unification0, VarSet, VarTypes, TVarSet, ModuleInfo0,
|
|
Functor, Unification, ModuleInfo) :-
|
|
(
|
|
Unification0 = construct(Var0, _, _, UniModes0)
|
|
->
|
|
Var = Var0,
|
|
UniModes = UniModes0
|
|
;
|
|
error("polymorphism__transform_lambda: wierd unification")
|
|
),
|
|
|
|
%
|
|
% Optimize a special case: replace
|
|
% `lambda([Y1, Y2, ...] is Det, p(X1, X2, ..., Y1, Y2, ...))'
|
|
% where `p' has determinism `Det' with
|
|
% `p(X1, X2, ...)'
|
|
%
|
|
% XXX This optimization is only valid if the modes of the Xi are
|
|
% input, since only input arguments can be curried.
|
|
% Until this check is added, this optimization is incorrect,
|
|
% so I have disabled it - fjh.
|
|
|
|
LambdaGoal = _ - LambdaGoalInfo,
|
|
goal_info_get_nonlocals(LambdaGoalInfo, NonLocals0),
|
|
set__delete_list(NonLocals0, Vars, NonLocals),
|
|
set__to_sorted_list(NonLocals, ArgVars1),
|
|
(
|
|
/****************
|
|
XXX this optimization temporarily disabled, see comment above
|
|
|
|
LambdaGoal = call(PredId0, ModeId0, CallVars, _, _, PredName, _)
|
|
- _,
|
|
list__remove_suffix(CallVars, Vars, InitialVars),
|
|
|
|
module_info_pred_proc_info(ModuleInfo0, PredId0, ModeId0, _,
|
|
Call_ProcInfo),
|
|
proc_info_interface_code_model(Call_ProcInfo, Call_CodeModel),
|
|
determinism_to_code_model(Det, 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
|
|
)
|
|
->
|
|
ArgVars = InitialVars,
|
|
PredId = PredId0,
|
|
ModeId = ModeId0,
|
|
unqualify_name(PredName, PName),
|
|
ModuleInfo = ModuleInfo0
|
|
;
|
|
****************/
|
|
% 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),
|
|
string__int_to_string(LambdaCount, LambdaCountStr),
|
|
string__append("__LambdaGoal__", LambdaCountStr, PName0),
|
|
string__append(ModuleName, PName0, PName),
|
|
PredName = unqualified(PName),
|
|
list__length(AllArgVars, Arity),
|
|
map__apply_to_list(AllArgVars, VarTypes, ArgTypes),
|
|
Cond = true,
|
|
goal_info_context(LambdaGoalInfo, LambdaContext),
|
|
Status = local,
|
|
MaybeDet = yes(Det),
|
|
% the TVarSet is a superset of what it really ought be,
|
|
% but that shouldn't matter
|
|
lambda__uni_modes_to_modes(UniModes, 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 `UniModes'.
|
|
% For the lambda var arguments at the end,
|
|
% we use the mode in the lambda expression.
|
|
|
|
list__length(ArgVars, NumArgVars),
|
|
In = user_defined_mode(unqualified("in"), []),
|
|
list__duplicate(NumArgVars, In, InModes),
|
|
map__from_corresponding_lists(ArgVars, InModes,
|
|
ArgModesMap),
|
|
|
|
set__delete_list(OrigNonLocals0, Vars, OrigNonLocals),
|
|
set__to_sorted_list(OrigNonLocals, OrigArgVars),
|
|
map__from_corresponding_lists(OrigArgVars, OrigArgModes,
|
|
OrigArgModesMap),
|
|
map__overlay(ArgModesMap, OrigArgModesMap, ArgModesMap1),
|
|
map__values(ArgModesMap1, ArgModes1),
|
|
|
|
list__append(ArgModes1, Modes, AllArgModes),
|
|
|
|
%
|
|
% Now construct the pred_info for the new predicate, using
|
|
% the information computed above
|
|
%
|
|
clauses_info_init(Arity, ClausesInfo),
|
|
pred_info_init(ModuleName, PredName, Arity, TVarSet,
|
|
ArgTypes, Cond, LambdaContext, ClausesInfo, Status,
|
|
no, none, PredInfo0),
|
|
|
|
%
|
|
% Create a single mode for the new predicate, and insert
|
|
% the lambda goal as the body of that procedure.
|
|
%
|
|
pred_info_procedures(PredInfo0, Procs0),
|
|
next_mode_id(Procs0, MaybeDet, ModeId),
|
|
proc_info_init(Arity, AllArgModes, MaybeDet, LambdaContext,
|
|
ProcInfo0),
|
|
proc_info_set_body(ProcInfo0, VarSet, VarTypes, AllArgVars,
|
|
LambdaGoal, ProcInfo),
|
|
map__set(Procs0, ModeId, ProcInfo, Procs),
|
|
pred_info_set_procedures(PredInfo0, Procs, 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(term_atom(PName), ArgVars),
|
|
ConsId = pred_const(PredId, ModeId),
|
|
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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|