[m-dev.] diff: improve handling of top-down calls in Aditi
Simon Taylor
stayl at cs.mu.OZ.AU
Wed Aug 4 13:25:06 AEST 1999
Estimated hours taken: 4
compiler/rl_exprn.m:
Improve the error messages for unsupported top-down
calls from Aditi predicates.
Add the ability to call library predicates for
which bytecodes exist in Aditi.
Fix bugs in the handling of arguments of closures passed
to aditi__aggregate which caused registers to be overwritten.
Fix incorrect types used in assign instructions in aditi__aggregate.
doc/reference_manual.texi:
Document which library predicates can be called from Aditi.
Index: compiler/rl_exprn.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/rl_exprn.m,v
retrieving revision 1.9
diff -u -u -r1.9 rl_exprn.m
--- rl_exprn.m 1999/07/13 08:53:27 1.9
+++ rl_exprn.m 1999/08/03 02:31:47
@@ -82,7 +82,7 @@
:- import_module code_util, hlds_pred, hlds_data, inst_match.
:- import_module instmap, mode_util, tree, type_util, prog_out.
-:- import_module rl_out, inlining, hlds_goal, prog_util.
+:- import_module rl_out, inlining, hlds_goal, prog_util, error_util.
% Note: the reason that we need to import llds and builtin_ops here is that
% we generate code for builtins by first converting the builtin to LLDS
@@ -698,23 +698,71 @@
hlds_goal_info::in, byte_tree::in, byte_tree::out,
rl_exprn_info::in, rl_exprn_info::out) is det.
-rl_exprn__call(PredId, ProcId, Vars, _GoalInfo, Fail, Code) -->
+rl_exprn__call(PredId, ProcId, Vars, GoalInfo, Fail, Code) -->
rl_exprn_info_get_module_info(ModuleInfo),
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
PredInfo, ProcInfo) },
{ proc_info_inferred_determinism(ProcInfo, Detism) },
- ( { determinism_components(Detism, _, at_most_many) } ->
- { error("Sorry, not yet implemented - nondeterministic Mercury calls in Aditi procedures") }
+ rl_exprn_info_get_parent_pred_proc_ids(Parents0),
+ (
+ % XXX Nondet top-down calls are not yet implemented.
+ { determinism_components(Detism, _, at_most_many) }
+ ->
+ { goal_info_get_context(GoalInfo, Context) },
+ { rl_exprn__call_not_implemented_error(Context,
+ ModuleInfo, PredId, ProcId,
+ "nondeterministic Mercury calls in Aditi procedures") }
;
+ % XXX Top-down calls to imported predicates
+ % are not yet implemented.
{ pred_info_is_imported(PredInfo) },
- { \+ code_util__predinfo_is_builtin(PredInfo) }
+
+ % Calls to `unify/2' and `compare/3' will have been
+ % transformed into the type-specific versions
+ % by polymorphism.m. Polymorphic types are not allowed
+ % in Aditi predicates so the types must be known.
+ \+ {
+ % `index/2' doesn't work in Aditi.
+ code_util__compiler_generated(PredInfo),
+ \+ pred_info_name(PredInfo, "__Index__")
+ },
+ { \+ code_util__predinfo_is_builtin(PredInfo) },
+ { \+ rl_exprn__is_simple_extra_aditi_builtin(PredInfo,
+ ProcId, _) }
+ ->
+ { goal_info_get_context(GoalInfo, Context) },
+ { rl_exprn__call_not_implemented_error(Context,
+ ModuleInfo, PredId, ProcId,
+ "calls to imported Mercury procedures from Aditi") }
+ ;
+ % XXX Recursive top-down calls are not yet implemented.
+ { set__member(proc(PredId, ProcId), Parents0) }
->
- { error("Sorry, not yet implemented - calls to imported Mercury procedures from Aditi") }
+ { goal_info_get_context(GoalInfo, Context) },
+ { rl_exprn__call_not_implemented_error(Context,
+ ModuleInfo, PredId, ProcId,
+ "recursive Mercury calls in Aditi procedures") }
;
rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo,
Fail, Vars, Code)
).
+:- pred rl_exprn__call_not_implemented_error(prog_context::in, module_info::in,
+ pred_id::in, proc_id::in, string::in) is erroneous.
+
+rl_exprn__call_not_implemented_error(Context,
+ ModuleInfo, PredId, ProcId, ErrorDescr) :-
+ error_util__describe_one_proc_name(ModuleInfo,
+ proc(PredId, ProcId), ProcName),
+ prog_out__context_to_string(Context, ContextStr),
+ string__append_list(
+ [
+ ContextStr, "in call to ", ProcName, ":\n",
+ "sorry, not yet implemented - ", ErrorDescr
+ ],
+ Msg),
+ error(Msg).
+
:- pred rl_exprn__call_body(pred_id::in, proc_id::in, pred_info::in,
proc_info::in, byte_tree::in, list(prog_var)::in, byte_tree::out,
rl_exprn_info::in, rl_exprn_info::out) is det.
@@ -722,10 +770,18 @@
rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo, Fail, Args, Code) -->
{ pred_info_name(PredInfo, PredName) },
{ pred_info_arity(PredInfo, Arity) },
- ( { code_util__predinfo_is_builtin(PredInfo) } ->
+ (
+ { code_util__predinfo_is_builtin(PredInfo) }
+ ->
rl_exprn__generate_builtin_call(PredId, ProcId, PredInfo,
Args, Fail, Code)
;
+ { rl_exprn__is_simple_extra_aditi_builtin(PredInfo,
+ ProcId, Bytecode) }
+ ->
+ rl_exprn__generate_extra_aditi_builtin(Bytecode,
+ Args, Code)
+ ;
% Handle unify/2 specially, since it is possibly recursive,
% which will cause the code below to fall over. Also, magic.m
% doesn't add type_info arguments yet.
@@ -789,15 +845,8 @@
;
% XXX temporary hack until we allow Mercury calls from Aditi -
% generate the goal of the called procedure, not a call to
- % the called procedure, checking first that the call is not
- % recursive.
-
+ % the called procedure.
rl_exprn_info_get_parent_pred_proc_ids(Parents0),
- ( { set__member(proc(PredId, ProcId), Parents0) } ->
- { error("sorry, recursive Mercury calls in Aditi-RL code are not yet implemented") }
- ;
- []
- ),
{ set__insert(Parents0, proc(PredId, ProcId), Parents) },
rl_exprn_info_set_parent_pred_proc_ids(Parents),
rl_exprn__inline_call(PredId, ProcId,
@@ -1388,6 +1437,119 @@
rl_exprn__binop_bytecode(float_ge, rl_EXP_flt_ge).
%-----------------------------------------------------------------------------%
+
+ % Generate code for deterministic library predicates and functions
+ % for which all arguments except the last are input.
+ % This is not an exhaustive list, it's just the ones that
+ % Aditi happens to have bytecodes for.
+ % This is only needed until Aditi can call arbitrary Mercury code.
+:- pred rl_exprn__generate_extra_aditi_builtin(bytecode::in,
+ list(prog_var)::in, byte_tree::out,
+ rl_exprn_info::in, rl_exprn_info::out) is det.
+
+rl_exprn__generate_extra_aditi_builtin(Bytecode, Args, Code) -->
+ % The extra aditi builtins are not all functions, but
+ % this does the right thing.
+ { pred_args_to_func_args(Args, InArgs, OutArg) },
+
+ rl_exprn__push_builtin_args(InArgs, empty, PushCode),
+
+ rl_exprn_info_lookup_var(OutArg, OutReg),
+ rl_exprn_info_lookup_var_type(OutArg, OutVarType),
+ rl_exprn__generate_pop(reg(OutReg), OutVarType, PopCode),
+
+ { Code =
+ tree(PushCode,
+ tree(node([Bytecode]),
+ PopCode
+ )) }.
+
+:- pred rl_exprn__push_builtin_args(list(prog_var)::in, byte_tree::in,
+ byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
+
+rl_exprn__push_builtin_args([], Code, Code) --> [].
+rl_exprn__push_builtin_args([Var | Vars], Code0, Code) -->
+ rl_exprn_info_lookup_var(Var, VarReg),
+ rl_exprn_info_lookup_var_type(Var, VarType),
+ rl_exprn__generate_push(reg(VarReg), VarType, Code1),
+ rl_exprn__push_builtin_args(Vars, tree(Code0, Code1), Code).
+
+:- pred rl_exprn__is_simple_extra_aditi_builtin(pred_info::in, proc_id::in,
+ bytecode::out) is semidet.
+
+rl_exprn__is_simple_extra_aditi_builtin(PredInfo, ProcId, Bytecode) :-
+ pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
+ pred_info_module(PredInfo, PredModule),
+ PredModule = unqualified(PredModuleName),
+ pred_info_name(PredInfo, PredName),
+ pred_info_arity(PredInfo, PredArity0),
+ hlds_pred__proc_id_to_int(ProcId, ProcInt),
+ adjust_func_arity(PredOrFunc, PredArity, PredArity0),
+ rl_exprn__simple_extra_builtin(PredOrFunc, PredModuleName,
+ PredName, PredArity, ProcInt, Bytecode).
+
+:- pred rl_exprn__simple_extra_builtin(pred_or_func::in, string::in,
+ string::in, int::in, int::in, bytecode::in) is semidet.
+:- mode rl_exprn__simple_extra_builtin(in, in, in, in, out, out) is semidet.
+
+rl_exprn__simple_extra_builtin(predicate, "int", "to_float", 2, 0,
+ rl_EXP_int_toflt).
+rl_exprn__simple_extra_builtin(predicate, "int", "max", 3, 0, rl_EXP_int_max).
+rl_exprn__simple_extra_builtin(predicate, "int", "min", 3, 0, rl_EXP_int_min).
+rl_exprn__simple_extra_builtin(predicate, "int", "abs", 2, 0, rl_EXP_int_abs).
+
+rl_exprn__simple_extra_builtin(function, "float", "float", 1, 0,
+ rl_EXP_int_toflt).
+rl_exprn__simple_extra_builtin(function, "float",
+ "truncate_to_int", 1, 0, rl_EXP_flt_toint).
+rl_exprn__simple_extra_builtin(function, "float", "pow", 2, 0, rl_EXP_flt_pow).
+rl_exprn__simple_extra_builtin(predicate, "float", "pow", 3, 0,
+ rl_EXP_flt_pow).
+rl_exprn__simple_extra_builtin(function, "float", "abs", 1, 0, rl_EXP_flt_abs).
+rl_exprn__simple_extra_builtin(predicate, "float", "abs", 2, 0,
+ rl_EXP_flt_abs).
+rl_exprn__simple_extra_builtin(function, "float", "max", 2, 0, rl_EXP_flt_max).
+rl_exprn__simple_extra_builtin(predicate, "float", "max", 3, 0,
+ rl_EXP_flt_max).
+rl_exprn__simple_extra_builtin(function, "float", "min", 2, 0, rl_EXP_flt_min).
+rl_exprn__simple_extra_builtin(predicate, "float", "min", 3, 0,
+ rl_EXP_flt_min).
+
+rl_exprn__simple_extra_builtin(function, "math", "ceiling", 1, 0,
+ rl_EXP_flt_ceil).
+rl_exprn__simple_extra_builtin(function, "math", "floor", 1, 0,
+ rl_EXP_flt_floor).
+rl_exprn__simple_extra_builtin(function, "math", "round", 1, 0,
+ rl_EXP_flt_round).
+rl_exprn__simple_extra_builtin(function, "math", "sqrt", 1, 0,
+ rl_EXP_flt_sqrt).
+rl_exprn__simple_extra_builtin(function, "math", "pow", 2, 0, rl_EXP_flt_pow).
+rl_exprn__simple_extra_builtin(function, "math", "exp", 1, 0, rl_EXP_flt_exp).
+rl_exprn__simple_extra_builtin(function, "math", "ln", 1, 0, rl_EXP_flt_log).
+rl_exprn__simple_extra_builtin(function, "math", "log10", 1, 0,
+ rl_EXP_flt_log10).
+rl_exprn__simple_extra_builtin(function, "math", "log2", 1, 0,
+ rl_EXP_flt_log2).
+rl_exprn__simple_extra_builtin(function, "math", "sin", 1, 0, rl_EXP_flt_sin).
+rl_exprn__simple_extra_builtin(function, "math", "cos", 1, 0, rl_EXP_flt_cos).
+rl_exprn__simple_extra_builtin(function, "math", "tan", 1, 0, rl_EXP_flt_tan).
+rl_exprn__simple_extra_builtin(function, "math", "asin", 1, 0,
+ rl_EXP_flt_asin).
+rl_exprn__simple_extra_builtin(function, "math", "acos", 1, 0,
+ rl_EXP_flt_acos).
+rl_exprn__simple_extra_builtin(function, "math", "atan", 1, 0,
+ rl_EXP_flt_atan).
+rl_exprn__simple_extra_builtin(function, "math", "sinh", 1, 0,
+ rl_EXP_flt_sinh).
+rl_exprn__simple_extra_builtin(function, "math", "cosh", 1, 0,
+ rl_EXP_flt_cosh).
+rl_exprn__simple_extra_builtin(function, "math", "tanh", 1, 0,
+ rl_EXP_flt_tanh).
+
+rl_exprn__simple_extra_builtin(predicate, "string", "length", 2, 0,
+ rl_EXP_str_length).
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
rl_exprn__aggregate(ModuleInfo, ComputeInitial, UpdateAcc, GrpByType,
@@ -1462,7 +1624,7 @@
rl_exprn_info_get_free_reg(NonGrpByType, NonGrpByReg),
rl_exprn__assign(reg(NonGrpByReg), input_field(one, 1),
- GrpByType, NonGrpByAssign),
+ NonGrpByType, NonGrpByAssign),
rl_exprn_info_get_free_reg(AccType, InitialAccReg),
@@ -1471,7 +1633,8 @@
% the group, and assign it to a register.
%
{ Args = [GrpByReg, NonGrpByReg, InitialAccReg] },
- rl_exprn__closure(ComputeClosure, Args, IsConst, AccCode0),
+ { ArgTypes = [GrpByType, NonGrpByType, AccType] },
+ rl_exprn__closure(ComputeClosure, Args, ArgTypes, IsConst, AccCode0),
% Restore the initial value of the accumulator at the start
% of a new group.
@@ -1510,13 +1673,14 @@
NonGrpByType, NonGrpByCode),
% Allocate a location to collect the new accumulator.
- rl_exprn_info_get_free_reg(GrpByType, OutputAccReg),
+ rl_exprn_info_get_free_reg(AccType, OutputAccReg),
rl_exprn__assign(reg(AccReg), reg(OutputAccReg),
AccType, AccAssignCode),
{ Args = [GrpByReg, NonGrpByReg, AccReg, OutputAccReg] },
+ { ArgTypes = [GrpByType, NonGrpByType, AccType, AccType] },
- rl_exprn__closure(UpdateClosure, Args, _, UpdateCode),
+ rl_exprn__closure(UpdateClosure, Args, ArgTypes, _, UpdateCode),
{ Code =
tree(NonGrpByCode,
tree(UpdateCode,
@@ -1530,27 +1694,32 @@
% Return whether the input arguments are actually used in
% constructing the outputs. If not, the closure is constant
% and can be evaluated once, instead of once per group.
-:- pred rl_exprn__closure(pred_proc_id::in, list(reg_id)::in, bool::out,
- byte_tree::out, rl_exprn_info::in, rl_exprn_info::out) is det.
+:- pred rl_exprn__closure(pred_proc_id::in, list(reg_id)::in, list(type)::in,
+ bool::out, byte_tree::out,
+ rl_exprn_info::in, rl_exprn_info::out) is det.
-rl_exprn__closure(proc(PredId, ProcId), ArgLocs, IsConst, Code) -->
+rl_exprn__closure(proc(PredId, ProcId), ArgLocs, ArgTypes, IsConst, Code) -->
rl_exprn_info_get_module_info(ModuleInfo),
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
PredInfo, ProcInfo) },
- { proc_info_vartypes(ProcInfo, VarTypes) },
- { proc_info_varset(ProcInfo, VarSet) },
- rl_exprn_info_set_vartypes(VarTypes),
+
+ % Create dummy variables for the arguments of the procedure.
+ rl_exprn_info_get_varset(VarSet0),
+ rl_exprn_info_get_vartypes(VarTypes0),
+ { list__length(ArgTypes, NumVars) },
+ { varset__new_vars(VarSet0, NumVars, ArgVars, VarSet) },
+ { map__det_insert_from_corresponding_lists(VarTypes0,
+ ArgVars, ArgTypes, VarTypes) },
rl_exprn_info_set_varset(VarSet),
+ rl_exprn_info_set_vartypes(VarTypes),
- { proc_info_headvars(ProcInfo, HeadVars) },
- { map__from_corresponding_lists(HeadVars, ArgLocs, VarLocs) },
- { list__length(HeadVars, NextVar) },
- rl_exprn_info_set_vars(VarLocs - NextVar),
+ rl_exprn_info_set_var_locs(ArgVars, ArgLocs),
% Check if the closure depends on the input arguments.
{ proc_info_goal(ProcInfo, Goal) },
{ Goal = _ - GoalInfo },
{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
+ { proc_info_headvars(ProcInfo, HeadVars) },
{ proc_info_argmodes(ProcInfo, ArgModes) },
{ partition_args(ModuleInfo, ArgModes, HeadVars, InputArgs, _) },
{ set__list_to_set(InputArgs, InputArgSet) },
@@ -1563,7 +1732,7 @@
{ Fail = node([rl_EXP_return_false]) },
rl_exprn__call_body(PredId, ProcId, PredInfo, ProcInfo,
- Fail, HeadVars, Code).
+ Fail, ArgVars, Code).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
@@ -1828,6 +1997,9 @@
:- pred rl_exprn_info_set_varset(prog_varset, rl_exprn_info, rl_exprn_info).
:- mode rl_exprn_info_set_varset(in, in, out) is det.
+:- pred rl_exprn_info_get_vars(id_map(prog_var), rl_exprn_info, rl_exprn_info).
+:- mode rl_exprn_info_get_vars(out, in, out) is det.
+
:- pred rl_exprn_info_set_vars(id_map(prog_var), rl_exprn_info, rl_exprn_info).
:- mode rl_exprn_info_set_vars(in, in, out) is det.
@@ -1870,6 +2042,14 @@
rl_exprn_info, rl_exprn_info).
:- mode rl_exprn_info_lookup_var_type(in, out, in, out) is det.
+:- pred rl_exprn_info_set_var_locs(list(prog_var), list(reg_id),
+ rl_exprn_info, rl_exprn_info).
+:- mode rl_exprn_info_set_var_locs(in, in, in, out) is det.
+
+:- pred rl_exprn_info_set_var_loc(prog_var, reg_id,
+ rl_exprn_info, rl_exprn_info).
+:- mode rl_exprn_info_set_var_loc(in, in, in, out) is det.
+
:- pred rl_exprn_info_get_decls(list(type), rl_exprn_info, rl_exprn_info).
:- mode rl_exprn_info_get_decls(out, in, out) is det.
@@ -1956,6 +2136,8 @@
Info = rl_exprn_info(_,_,C,_,_,_,_,_,_,_).
rl_exprn_info_get_varset(D, Info, Info) :-
Info = rl_exprn_info(_,_,_,D,_,_,_,_,_,_).
+rl_exprn_info_get_vars(E, Info, Info) :-
+ Info = rl_exprn_info(_,_,_,_,E,_,_,_,_,_).
rl_exprn_info_get_consts(G, Info, Info) :-
Info = rl_exprn_info(_,_,_,_,_,_,G,_,_,_).
rl_exprn_info_get_rules(H, Info, Info) :-
@@ -2014,6 +2196,20 @@
rl_exprn_info_lookup_var_type(Var, Type) -->
rl_exprn_info_get_vartypes(VarTypes),
{ map__lookup(VarTypes, Var, Type) }.
+
+rl_exprn_info_set_var_locs([], []) --> [].
+rl_exprn_info_set_var_locs([_|_], []) -->
+ { error("rl_exprn_info_set_var_locs") }.
+rl_exprn_info_set_var_locs([], [_|_]) -->
+ { error("rl_exprn_info_set_var_locs") }.
+rl_exprn_info_set_var_locs([Var | Vars], [Loc | Locs]) -->
+ rl_exprn_info_set_var_loc(Var, Loc),
+ rl_exprn_info_set_var_locs(Vars, Locs).
+
+rl_exprn_info_set_var_loc(Var, Loc) -->
+ rl_exprn_info_get_vars(VarMap0 - NextVar),
+ { map__det_insert(VarMap0, Var, Loc, VarMap) },
+ rl_exprn_info_set_vars(VarMap - NextVar).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/reference_manual.texi,v
retrieving revision 1.147
diff -u -u -r1.147 reference_manual.texi
--- reference_manual.texi 1999/07/15 06:25:06 1.147
+++ reference_manual.texi 1999/08/04 03:18:23
@@ -5521,6 +5521,75 @@
Some useful predicates are defined in @file{extras/aditi/aditi.m} in the
@samp{mercury-extras} distribution.
+The Aditi interface currently has the major restriction that recursive or
+imported top-down Mercury predicates or functions cannot be called from
+predicates with @samp{pragma aditi} declarations.
+The following predicates and functions from the standard library
+can be called from Aditi:
+
+ at samp{builtin__compare/3},
+
+ at samp{int:'<'/2},
+ at samp{int:'>'/2},
+ at samp{int:'=<'/2},
+ at samp{int:'>='/2},
+ at samp{int__abs/2},
+ at samp{int__max/3},
+ at samp{int__min/3},
+ at samp{int__to_float/2},
+ at samp{int__pow/2},
+ at samp{int__log2/2},
+ at samp{int:'+'/2},
+ at samp{int:'+'/1},
+ at samp{int:'-'/2},
+ at samp{int:'-'/1},
+ at samp{int:'*'/2},
+ at samp{int:'//'/2},
+ at samp{int__rem/2},
+
+ at samp{float:'<'/2},
+ at samp{float:'>'/2},
+ at samp{float:'>='/2},
+ at samp{float:'=<'/2},
+ at samp{float__abs/1},
+ at samp{float__abs/2},
+ at samp{float__max/2},
+ at samp{float__max/3},
+ at samp{float__min/2},
+ at samp{float__min/3},
+ at samp{float__pow/2},
+ at samp{float__log2/2},
+ at samp{float__float/1},
+ at samp{float__truncate_to_int/1},
+ at samp{float__truncate_to_int/2},
+ at samp{float:'+'/2},
+ at samp{float:'+'/1},
+ at samp{float:'-'/2},
+ at samp{float:'-'/1},
+ at samp{float:'*'/2},
+ at samp{float:'/'/2},
+
+ at samp{math__ceiling/1},
+ at samp{math__round/1},
+ at samp{math__floor/1},
+ at samp{math__sqrt/1},
+ at samp{math__pow/2},
+ at samp{math__exp/1},
+ at samp{math__ln/1},
+ at samp{math__log10/1},
+ at samp{math__log2/1},
+ at samp{math__sin/1},
+ at samp{math__cos/1},
+ at samp{math__tan/1},
+ at samp{math__asin/1},
+ at samp{math__acos/1},
+ at samp{math__atan/1},
+ at samp{math__sinh/1},
+ at samp{math__cosh/1},
+ at samp{math__tanh/1},
+
+ at samp{string__length/2}.
+
@node Aditi pragma declarations
@subsubsection Aditi pragma declarations
@@ -5588,14 +5657,13 @@
@c generated by the Aditi system, so this documentation should disappear
@c eventually.
@example
-:- pragma aditi_index(@var{Name}/@var{Arity},
- @var{IndexType}, @var{Attributes}).
+:- pragma aditi_index(@var{Name}/@var{Arity}, @var{IndexType}, @var{Attributes}).
@end example
The base relation has the given B-tree index. B-tree indexes allow efficient
retrieval of a tuple or range of tuples from a base relation.
- at var{IndexType} must be one of @samp{unique_B_tree} or
- at samp{non_unique_B_tree}. @var{Attributes} is a list of argument
+ at samp{@var{IndexType}} must be one of @samp{unique_B_tree} or
+ at samp{non_unique_B_tree}. @samp{@var{Attributes}} is a list of argument
numbers (argument numbers are counted from one).
@node Aditi update syntax
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list