Did some work towards implementing implied modes.

modes.nl, mode_errors.nl:
	Did some work towards implementing implied modes.  We still
	don't implement them yet, but at least we know report an error if
	you try (and you also used --generate-code).
This commit is contained in:
Fergus Henderson
1994-09-09 23:43:21 +00:00
parent 143251f945
commit dbed5a2d3e
2 changed files with 231 additions and 64 deletions

View File

@@ -37,6 +37,12 @@
; mode_error_var_has_inst(var, inst, inst) ; mode_error_var_has_inst(var, inst, inst)
% call to a predicate with an insufficiently % call to a predicate with an insufficiently
% instantiated variable (for preds with one mode) % instantiated variable (for preds with one mode)
; mode_error_implied_mode(var, inst, inst)
% a call to a predicate with an overly
% instantiated variable would use an implied
% mode of the predicate. XXX This is temporary -
% once we've implemented implied modes we can
% get rid of it.
; mode_error_no_matching_mode(list(var), list(inst)) ; mode_error_no_matching_mode(list(var), list(inst))
% call to a predicate with an insufficiently % call to a predicate with an insufficiently
% instantiated variable (for preds with >1 mode) % instantiated variable (for preds with >1 mode)
@@ -99,6 +105,8 @@ report_mode_error(mode_error_disj(MergeContext, ErrorList), ModeInfo) -->
report_mode_error_disj(ModeInfo, MergeContext, ErrorList). report_mode_error_disj(ModeInfo, MergeContext, ErrorList).
report_mode_error(mode_error_var_has_inst(Var, InstA, InstB), ModeInfo) --> report_mode_error(mode_error_var_has_inst(Var, InstA, InstB), ModeInfo) -->
report_mode_error_var_has_inst(ModeInfo, Var, InstA, InstB). report_mode_error_var_has_inst(ModeInfo, Var, InstA, InstB).
report_mode_error(mode_error_implied_mode(Var, InstA, InstB), ModeInfo) -->
report_mode_error_implied_mode(ModeInfo, Var, InstA, InstB).
report_mode_error(mode_error_bind_var(Var, InstA, InstB), ModeInfo) --> report_mode_error(mode_error_bind_var(Var, InstA, InstB), ModeInfo) -->
report_mode_error_bind_var(ModeInfo, Var, InstA, InstB). report_mode_error_bind_var(ModeInfo, Var, InstA, InstB).
report_mode_error(mode_error_unify_var_var(VarA, VarB, InstA, InstB), report_mode_error(mode_error_unify_var_var(VarA, VarB, InstA, InstB),
@@ -331,6 +339,40 @@ report_mode_error_var_has_inst(ModeInfo, Var, VarInst, Inst) -->
mercury_output_inst(Inst, InstVarSet), mercury_output_inst(Inst, InstVarSet),
io__write_string("'.\n"). io__write_string("'.\n").
:- pred report_mode_error_implied_mode(mode_info, var, inst, inst,
io__state, io__state).
:- mode report_mode_error_implied_mode(in, in, in, in, di, uo) is det.
report_mode_error_implied_mode(ModeInfo, Var, VarInst, Inst) -->
%
% This "error" message is really a "sorry, not implemented"
% message. We only print the message if we are actually
% going to generating code.
%
globals__io_lookup_bool_option(generate_code, GenerateCode),
globals__io_lookup_bool_option(compile, Compile),
globals__io_lookup_bool_option(compile_to_c, CompileToC),
( { GenerateCode = yes ; Compile = yes ; CompileToC = yes } ->
{ mode_info_get_context(ModeInfo, Context) },
{ mode_info_get_varset(ModeInfo, VarSet) },
{ mode_info_get_instvarset(ModeInfo, InstVarSet) },
mode_info_write_context(ModeInfo),
prog_out__write_context(Context),
io__write_string(" sorry, implied modes not implemented.\n"),
prog_out__write_context(Context),
io__write_string(" Variable `"),
mercury_output_var(Var, VarSet),
io__write_string("' has instantiatedness `"),
mercury_output_inst(VarInst, InstVarSet),
io__write_string("',\n"),
prog_out__write_context(Context),
io__write_string(" expected instantiatedness was `"),
mercury_output_inst(Inst, InstVarSet),
io__write_string("'.\n")
;
[]
).
%-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------%
:- pred report_mode_error_unify_var_var(mode_info, var, var, inst, inst, :- pred report_mode_error_unify_var_var(mode_info, var, var, inst, inst,

View File

@@ -468,12 +468,21 @@ modecheck_goal_2(some(Vs, G0), _, some(Vs, G)) -->
modecheck_goal(G0, G), modecheck_goal(G0, G),
mode_checkpoint(exit, "some"). mode_checkpoint(exit, "some").
modecheck_goal_2(call(PredId, _, Args, Builtin, PredName, Follow), _, modecheck_goal_2(call(PredId, _, Args0, Builtin, PredName, Follow), _, Goal) -->
call(PredId, Mode, Args, Builtin, PredName, Follow)) -->
mode_checkpoint(enter, "call"), mode_checkpoint(enter, "call"),
{ list__length(Args, Arity) }, { list__length(Args0, Arity) },
mode_info_set_call_context(call(PredName/Arity)), mode_info_set_call_context(call(PredName/Arity)),
modecheck_call_pred(PredId, Args, Mode), modecheck_call_pred(PredId, Args0, Mode, Args, ExtraGoals),
{ Call = call(PredId, Mode, Args, Builtin, PredName, Follow) },
{ goal_info_init(GoalInfo) }, % XXX bug!
{ CallGoal = Call - GoalInfo },
{ ExtraGoals = BeforeGoals - AfterGoals },
{ list__append(BeforeGoals, [CallGoal | AfterGoals], GoalList) },
{ GoalList = [SingleGoal - _GoalInfo2] ->
Goal = SingleGoal
;
Goal = conj(GoalList)
},
mode_info_unset_call_context, mode_info_unset_call_context,
mode_checkpoint(exit, "call"). mode_checkpoint(exit, "call").
@@ -801,11 +810,14 @@ instmap_merge_var([InstMap | InstMaps], Var, ModuleInfo0,
%-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------%
:- pred modecheck_call_pred(pred_id, list(term), proc_id, mode_info, mode_info). :- pred modecheck_call_pred(pred_id, list(term), proc_id, list(term),
:- mode modecheck_call_pred(in, in, out, mode_info_di, mode_info_uo) is det. pair(list(hlds__goal)), mode_info, mode_info).
:- mode modecheck_call_pred(in, in, out, out, out,
mode_info_di, mode_info_uo) is det.
modecheck_call_pred(PredId, Args, TheProcId, ModeInfo0, ModeInfo) :- modecheck_call_pred(PredId, Args0, TheProcId, Args, ExtraGoals,
term__term_list_to_var_list(Args, ArgVars), ModeInfo0, ModeInfo) :-
term__term_list_to_var_list(Args0, ArgVars0),
% Get the list of different possible modes for the called % Get the list of different possible modes for the called
% predicate % predicate
@@ -826,18 +838,18 @@ modecheck_call_pred(PredId, Args, TheProcId, ModeInfo0, ModeInfo) :-
proc_info_argmodes(ProcInfo, ProcArgModes0), proc_info_argmodes(ProcInfo, ProcArgModes0),
/********************* /*********************
% propagate type info into modes % propagate type info into modes
mode_info_get_types_of_vars(ModeInfo0, ArgVars, ArgTypes), mode_info_get_types_of_vars(ModeInfo0, ArgVars0, ArgTypes),
propagate_type_info_mode_list(ArgTypes, ModuleInfo, propagate_type_info_mode_list(ArgTypes, ModuleInfo,
ProcArgModes0, ProcArgModes), ProcArgModes0, ProcArgModes),
*********************/ *********************/
ProcArgModes = ProcArgModes0, ProcArgModes = ProcArgModes0,
mode_list_get_initial_insts(ProcArgModes, ModuleInfo, mode_list_get_initial_insts(ProcArgModes, ModuleInfo,
InitialInsts), InitialInsts),
modecheck_var_has_inst_list(ArgVars, InitialInsts, modecheck_var_has_inst_list(ArgVars0, InitialInsts,
ModeInfo0, ModeInfo1), ModeInfo0, ModeInfo1),
mode_list_get_final_insts(ProcArgModes, ModuleInfo, FinalInsts), mode_list_get_final_insts(ProcArgModes, ModuleInfo, FinalInsts),
modecheck_set_var_inst_list(ArgVars, FinalInsts, modecheck_set_var_inst_list(ArgVars0, InitialInsts, FinalInsts,
ModeInfo1, ModeInfo2), ArgVars, ExtraGoals, ModeInfo1, ModeInfo2),
mode_info_never_succeeds(ModeInfo2, PredId, ProcId, Result), mode_info_never_succeeds(ModeInfo2, PredId, ProcId, Result),
( Result = yes -> ( Result = yes ->
mode_info_set_instmap(unreachable, ModeInfo2, ModeInfo) mode_info_set_instmap(unreachable, ModeInfo2, ModeInfo)
@@ -852,30 +864,33 @@ modecheck_call_pred(PredId, Args, TheProcId, ModeInfo0, ModeInfo) :-
mode_info_set_errors([], ModeInfo0, ModeInfo1), mode_info_set_errors([], ModeInfo0, ModeInfo1),
set__init(WaitingVars), set__init(WaitingVars),
modecheck_call_pred_2(ProcIds, PredId, Procs, ArgVars, modecheck_call_pred_2(ProcIds, PredId, Procs, ArgVars0,
WaitingVars, TheProcId, ModeInfo1, ModeInfo2), WaitingVars, TheProcId, ArgVars, ExtraGoals,
ModeInfo1, ModeInfo2),
% restore the error list, appending any new error(s) % restore the error list, appending any new error(s)
mode_info_get_errors(ModeInfo2, NewErrors), mode_info_get_errors(ModeInfo2, NewErrors),
list__append(OldErrors, NewErrors, Errors), list__append(OldErrors, NewErrors, Errors),
mode_info_set_errors(Errors, ModeInfo2, ModeInfo) mode_info_set_errors(Errors, ModeInfo2, ModeInfo)
). ),
term__var_list_to_term_list(ArgVars, Args).
:- pred modecheck_call_pred_2(list(proc_id), pred_id, proc_table, list(var), :- pred modecheck_call_pred_2(list(proc_id), pred_id, proc_table, list(var),
set(var), proc_id, mode_info, mode_info). set(var), proc_id, list(var), pair(list(hlds__goal)),
:- mode modecheck_call_pred_2(in, in, in, in, in, out, mode_info, mode_info).
mode_info_di, mode_info_uo) is det. :- mode modecheck_call_pred_2(in, in, in, in, in, out, out, out,
mode_info_di, mode_info_uo) is det.
modecheck_call_pred_2([], _PredId, _Procs, ArgVars, WaitingVars, 0, ModeInfo0, modecheck_call_pred_2([], _PredId, _Procs, ArgVars, WaitingVars,
ModeInfo) :- 0, ArgVars, [] - [], ModeInfo0, ModeInfo) :-
mode_info_get_instmap(ModeInfo0, InstMap), mode_info_get_instmap(ModeInfo0, InstMap),
get_var_insts(ArgVars, InstMap, ArgInsts), get_var_insts(ArgVars, InstMap, ArgInsts),
mode_info_error(WaitingVars, mode_info_error(WaitingVars,
mode_error_no_matching_mode(ArgVars, ArgInsts), mode_error_no_matching_mode(ArgVars, ArgInsts),
ModeInfo0, ModeInfo). ModeInfo0, ModeInfo).
modecheck_call_pred_2([ProcId | ProcIds], PredId, Procs, ArgVars, WaitingVars, modecheck_call_pred_2([ProcId | ProcIds], PredId, Procs, ArgVars0, WaitingVars,
TheProcId, ModeInfo0, ModeInfo) :- TheProcId, ArgVars, ExtraGoals, ModeInfo0, ModeInfo) :-
% find the initial insts for this mode of the called pred % find the initial insts for this mode of the called pred
map__lookup(Procs, ProcId, ProcInfo), map__lookup(Procs, ProcId, ProcInfo),
@@ -883,7 +898,7 @@ modecheck_call_pred_2([ProcId | ProcIds], PredId, Procs, ArgVars, WaitingVars,
mode_info_get_module_info(ModeInfo0, ModuleInfo), mode_info_get_module_info(ModeInfo0, ModuleInfo),
/************** /**************
% propagate the type information into the modes % propagate the type information into the modes
mode_info_get_types_of_vars(ModeInfo0, ArgVars, ArgTypes), mode_info_get_types_of_vars(ModeInfo0, ArgVars0, ArgTypes),
propagate_type_info_mode_list(ArgTypes, ModuleInfo, propagate_type_info_mode_list(ArgTypes, ModuleInfo,
ProcArgModes0, ProcArgModes), ProcArgModes0, ProcArgModes),
**************/ **************/
@@ -892,7 +907,7 @@ modecheck_call_pred_2([ProcId | ProcIds], PredId, Procs, ArgVars, WaitingVars,
% check whether the insts of the args matches their expected % check whether the insts of the args matches their expected
% initial insts % initial insts
modecheck_var_has_inst_list(ArgVars, InitialInsts, modecheck_var_has_inst_list(ArgVars0, InitialInsts,
ModeInfo0, ModeInfo1), ModeInfo0, ModeInfo1),
mode_info_get_errors(ModeInfo1, Errors), mode_info_get_errors(ModeInfo1, Errors),
( (
@@ -903,14 +918,15 @@ modecheck_call_pred_2([ProcId | ProcIds], PredId, Procs, ArgVars, WaitingVars,
FirstError = mode_error_info(WaitingVars2, _, _, _), FirstError = mode_error_info(WaitingVars2, _, _, _),
set__union(WaitingVars, WaitingVars2, WaitingVars3), set__union(WaitingVars, WaitingVars2, WaitingVars3),
modecheck_call_pred_2(ProcIds, PredId, Procs, ArgVars, modecheck_call_pred_2(ProcIds, PredId, Procs, ArgVars0,
WaitingVars3, TheProcId, ModeInfo0, ModeInfo) WaitingVars3, TheProcId, ArgVars, ExtraGoals,
ModeInfo0, ModeInfo)
; ;
% if there are no errors, then set their insts to the % if there are no errors, then set their insts to the
% final insts specified in the mode for the called pred % final insts specified in the mode for the called pred
mode_list_get_final_insts(ProcArgModes, ModuleInfo, FinalInsts), mode_list_get_final_insts(ProcArgModes, ModuleInfo, FinalInsts),
modecheck_set_var_inst_list(ArgVars, FinalInsts, ModeInfo1, modecheck_set_var_inst_list(ArgVars0, InitialInsts, FinalInsts,
ModeInfo2), ArgVars, ExtraGoals, ModeInfo1, ModeInfo2),
TheProcId = ProcId, TheProcId = ProcId,
mode_info_never_succeeds(ModeInfo2, PredId, ProcId, Result), mode_info_never_succeeds(ModeInfo2, PredId, ProcId, Result),
( Result = yes -> ( Result = yes ->
@@ -1092,40 +1108,140 @@ inst_expand(ModuleInfo, Inst0, Inst) :-
%-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------%
/*************** not used :- pred modecheck_set_var_inst_list(list(var), list(inst), list(inst),
:- pred modecheck_set_term_inst_list(list(term), list(inst), list(var), pair(list(hlds__goal)),
mode_info, mode_info). mode_info, mode_info).
:- mode modecheck_set_term_inst_list(in, in, mode_info_di, mode_info_uo) is det. :- mode modecheck_set_var_inst_list(in, in, in, out, out,
mode_info_di, mode_info_uo) is det.
modecheck_set_term_inst_list([], []) --> []. modecheck_set_var_inst_list(Vars0, InitialInsts, FinalInsts, Vars, Goals) -->
modecheck_set_term_inst_list([Arg | Args], [Inst | Insts]) --> (
{ Arg = term__variable(Var) }, modecheck_set_var_inst_list_2(Vars0, InitialInsts, FinalInsts,
modecheck_set_var_inst(Var, Inst), Vars1, Goals1)
modecheck_set_term_inst_list(Args, Insts). ->
***************/ { Vars = Vars1, Goals = Goals1 }
;
{ error("modecheck_set_var_inst_list: length mismatch") }
).
:- pred modecheck_set_var_inst_list(list(var), list(inst), :- pred modecheck_set_var_inst_list_2(list(var), list(inst), list(inst),
list(var), pair(list(hlds__goal)),
mode_info, mode_info). mode_info, mode_info).
:- mode modecheck_set_var_inst_list(in, in, mode_info_di, mode_info_uo) is det. :- mode modecheck_set_var_inst_list_2(in, in, in, out, out,
mode_info_di, mode_info_uo) is semidet.
modecheck_set_var_inst_list([_|_], []) --> modecheck_set_var_inst_list_2([], [], [], [], [] - []) --> [].
{ error("modecheck_set_var_inst_list: length mismatch") }. modecheck_set_var_inst_list_2([Var0 | Vars0], [InitialInst | InitialInsts],
modecheck_set_var_inst_list([], [_|_]) --> [FinalInst | FinalInsts], [Var | Vars], Goals) -->
{ error("modecheck_set_var_inst_list: length mismatch") }. modecheck_set_var_inst(Var0, InitialInst, FinalInst,
modecheck_set_var_inst_list([], []) --> []. Var, BeforeGoals0 - AfterGoals0),
modecheck_set_var_inst_list([Var | Vars], [Inst | Insts]) --> modecheck_set_var_inst_list_2(Vars0, InitialInsts, FinalInsts,
modecheck_set_var_inst(Var, Inst), Vars, BeforeGoals1 - AfterGoals1),
modecheck_set_var_inst_list(Vars, Insts). { list__append(BeforeGoals0, BeforeGoals1, BeforeGoals) },
{ list__append(AfterGoals0, AfterGoals1, AfterGoals) },
{ Goals = BeforeGoals - AfterGoals }.
:- pred modecheck_set_var_inst(var, inst, mode_info, mode_info). :- pred modecheck_set_var_inst(var, inst, inst, var, pair(list(hlds__goal)),
:- mode modecheck_set_var_inst(in, in, mode_info_di, mode_info_uo) is det. mode_info, mode_info).
:- mode modecheck_set_var_inst(in, in, in, out, out,
mode_info_di, mode_info_uo) is det.
modecheck_set_var_inst(Var, FinalInst, ModeInfo0, ModeInfo) :- modecheck_set_var_inst(Var0, InitialInst, FinalInst, Var, Goals,
ModeInfo0, ModeInfo) :-
mode_info_get_instmap(ModeInfo0, InstMap0), mode_info_get_instmap(ModeInfo0, InstMap0),
( InstMap0 = reachable(InstMapping0) -> ( InstMap0 = reachable(InstMapping0) ->
% The new inst must be computed by unifying the % The new inst must be computed by unifying the
% old inst and the proc's final inst % old inst and the proc's final inst
instmap_lookup_var(InstMap0, Var, Inst0), instmap_lookup_var(InstMap0, Var0, Inst0),
mode_info_get_module_info(ModeInfo0, ModuleInfo0),
(
abstractly_unify_inst(dead, Inst0, FinalInst,
ModuleInfo0, UnifyInst, ModuleInfo1)
->
ModuleInfo = ModuleInfo1,
Inst = UnifyInst
;
error("modecheck_set_var_inst: unify_inst failed")
),
mode_info_set_module_info(ModeInfo0, ModuleInfo, ModeInfo1),
(
% If we haven't added any information and
% we haven't bound any part of the var, then
% we haven't done anything.
inst_matches_initial(Inst0, Inst, ModuleInfo)
->
Var = Var0,
Goals = [] - [],
ModeInfo = ModeInfo1
;
% We must have either added some information,
% or bound part of the var. The call to
% inst_matches_final will fail iff we have
% bound part of a var.
inst_matches_final(Inst, Inst0, ModuleInfo)
->
% We've just added some information
Var = Var0,
Goals = [] - [],
map__set(InstMapping0, Var0, Inst, InstMapping),
InstMap = reachable(InstMapping),
mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2),
mode_info_get_delay_info(ModeInfo2, DelayInfo0),
delay_info__bind_var(DelayInfo0, Var0, DelayInfo),
mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo)
;
% We've bound part of the var. If the var was locked,
% then we need to report an error.
mode_info_var_is_locked(ModeInfo0, Var0)
->
Var = Var0,
Goals = [] - [],
set__singleton_set(WaitingVars, Var0),
mode_info_error(WaitingVars,
mode_error_bind_var(Var0, Inst0, Inst),
ModeInfo1, ModeInfo
)
;
% We've bound part of the var. If this was a call
% to an implied mode for that variable, then we
% need to introduce a fresh variable.
inst_matches_final(Inst0, InitialInst, ModuleInfo)
->
% XXX - implied modes not implemented
% we should introduce a fresh variable
Var = Var0,
Goals = [] - [],
set__singleton_set(WaitingVars, Var0),
mode_info_error(WaitingVars,
mode_error_implied_mode(Var0, Inst0, Inst),
ModeInfo1, ModeInfo
)
;
Var = Var0,
Goals = [] - [],
map__set(InstMapping0, Var0, Inst, InstMapping),
InstMap = reachable(InstMapping),
mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2),
mode_info_get_delay_info(ModeInfo2, DelayInfo0),
delay_info__bind_var(DelayInfo0, Var0, DelayInfo),
mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo)
)
;
Var = Var0,
Goals = [] - [],
ModeInfo = ModeInfo0
).
:- pred modecheck_set_var_inst(var, inst, mode_info, mode_info).
:- mode modecheck_set_var_inst(in, in, mode_info_di, mode_info_uo) is det.
modecheck_set_var_inst(Var0, FinalInst, ModeInfo0, ModeInfo) :-
mode_info_get_instmap(ModeInfo0, InstMap0),
( InstMap0 = reachable(InstMapping0) ->
% The new inst must be computed by unifying the
% old inst and the proc's final inst
instmap_lookup_var(InstMap0, Var0, Inst0),
mode_info_get_module_info(ModeInfo0, ModuleInfo0), mode_info_get_module_info(ModeInfo0, ModuleInfo0),
( (
abstractly_unify_inst(dead, Inst0, FinalInst, abstractly_unify_inst(dead, Inst0, FinalInst,
@@ -1149,23 +1265,32 @@ modecheck_set_var_inst(Var, FinalInst, ModeInfo0, ModeInfo) :-
% We must have either added some information, % We must have either added some information,
% or bound part of the var. The call to % or bound part of the var. The call to
% inst_matches_final will fail iff we have % inst_matches_final will fail iff we have
% bound part of a var. If the var was locked, % bound part of a var.
% then we need to report an error. inst_matches_final(Inst, Inst0, ModuleInfo)
\+ inst_matches_final(Inst, Inst0, ModuleInfo),
mode_info_var_is_locked(ModeInfo0, Var)
-> ->
set__singleton_set(WaitingVars, Var), % We've just added some information
mode_info_error(WaitingVars, map__set(InstMapping0, Var0, Inst, InstMapping),
mode_error_bind_var(Var, Inst0, Inst),
ModeInfo1, ModeInfo
)
;
map__set(InstMapping0, Var, Inst, InstMapping),
InstMap = reachable(InstMapping), InstMap = reachable(InstMapping),
mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2), mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2),
mode_info_get_delay_info(ModeInfo2, DelayInfo0), mode_info_get_delay_info(ModeInfo2, DelayInfo0),
delay_info__bind_var(DelayInfo0, Var, DelayInfo), delay_info__bind_var(DelayInfo0, Var0, DelayInfo),
mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo)
;
% We've bound part of the var. If the var was locked,
% then we need to report an error.
mode_info_var_is_locked(ModeInfo0, Var0)
->
set__singleton_set(WaitingVars, Var0),
mode_info_error(WaitingVars,
mode_error_bind_var(Var0, Inst0, Inst),
ModeInfo1, ModeInfo
)
;
map__set(InstMapping0, Var0, Inst, InstMapping),
InstMap = reachable(InstMapping),
mode_info_set_instmap(InstMap, ModeInfo1, ModeInfo2),
mode_info_get_delay_info(ModeInfo2, DelayInfo0),
delay_info__bind_var(DelayInfo0, Var0, DelayInfo),
mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo) mode_info_set_delay_info(DelayInfo, ModeInfo2, ModeInfo)
) )
; ;