| 1 | | % (c) 2009-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
| 2 | | % Heinrich Heine Universitaet Duesseldorf |
| 3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
| 4 | | |
| 5 | | :- module(delay,[delay_setof_wf/7, |
| 6 | | delay_setof_check_wf/9, |
| 7 | | delay_setof_list_wf/5, |
| 8 | | %delay_call/2, delay_call/3, |
| 9 | | %delay_not/3, compute_wait_variables/3 |
| 10 | | not_with_enum_warning/4 |
| 11 | | ]). |
| 12 | | |
| 13 | | % meta_predicate annotations should appear before loading any code: |
| 14 | | :- meta_predicate my_findall(-,0,-,-). |
| 15 | | :- meta_predicate my_findall_catch(-,0,-,-,-). |
| 16 | | :- meta_predicate my_findall_catch(-,0,-,-,-,-). |
| 17 | | :- meta_predicate my_findall_check(-,0,-,-,0,0,-,-). |
| 18 | | |
| 19 | | :- meta_predicate delay_setof_wf(-,0,-,-,-,-,-). |
| 20 | | %:- meta_predicate block_my_findall_catch_wf(-,-,0,-,-,-). |
| 21 | | |
| 22 | | :- meta_predicate delay_setof_check_wf(-,0,-,-,-,0,0,-,-). |
| 23 | | :- meta_predicate block_findall_check(-,-,0,-,0,0,-,-,-,-). |
| 24 | | |
| 25 | | :- meta_predicate delay_setof_list_wf(-,0,-,-,-). |
| 26 | | |
| 27 | | |
| 28 | | %:- meta_predicate delay_call(0,-,-). |
| 29 | | %:- meta_predicate delay_call(0,-). |
| 30 | | |
| 31 | | %:- meta_predicate delay_not(0,-,-). |
| 32 | | :- meta_predicate not_with_enum_warning(0,-,?,?). |
| 33 | | :- meta_predicate not_with_enum_warning2(0,-,-,-). |
| 34 | | |
| 35 | | % -------------- |
| 36 | | |
| 37 | | |
| 38 | | |
| 39 | | :- use_module(module_information,[module_info/2]). |
| 40 | | :- module_info(group,kernel). |
| 41 | | :- module_info(description,'Utilities to delay calls until sufficiently instantiated.'). |
| 42 | | |
| 43 | | %:- use_module(self_check). |
| 44 | | |
| 45 | | :- use_module(tools). |
| 46 | | :- use_module(debug). /* so that calls can call unqualified debug_prints */ |
| 47 | | |
| 48 | | :- use_module(error_manager). |
| 49 | | :- use_module(kernel_tools). |
| 50 | | :- use_module(kernel_waitflags,[add_wd_error_span_now/4, init_wait_flags/2,ground_wait_flags/1, |
| 51 | | pending_abort_error/1]). |
| 52 | | |
| 53 | | |
| 54 | | :- use_module(tools_printing,[print_term_summary/1]). |
| 55 | | :- load_files(library(system), [when(compile_time), imports([environ/2])]). |
| 56 | | :- use_module(tools_meta,[call_residue/2]). |
| 57 | | |
| 58 | | :- if(environ(prob_debug_watch_flag,true)). |
| 59 | | :- meta_predicate call_residue_check(0). |
| 60 | | call_residue_check(Call) :- call(Call). |
| 61 | | my_findall(X,P,L,_) :- |
| 62 | | statistics(runtime,[Start,_]), |
| 63 | | findall(X,P,L), |
| 64 | | statistics(runtime,[End,_]), |
| 65 | | Tot is End-Start, |
| 66 | | (Tot>50 -> nl, %nl,print(Call),nl, |
| 67 | | print('*** FINDALL: '),print_term_summary(P), |
| 68 | | print('*** exceeded limit: '), print(Tot), print(' ms'),nl, |
| 69 | | length(L,Len), |
| 70 | | print('*** SOLUTIONS: '), print(Len), nl |
| 71 | | ; true). |
| 72 | | :- elif(environ(prob_safe_mode,true)). % not enabled by default; performance impact seems small; except for test 469 |
| 73 | | % for test 469 we have a call like this: delay:custom_explicit_sets:test_closure_and_convert/5: [_zzzz_unary]: [integer]: PRED(disjunct/2,z_ : #3906:{1,3,...,3906,3907} or z_ : 3908 .. 19532): VARIABLE: _348117: no_wf_available |
| 74 | | % with 19531 solutions |
| 75 | | :- meta_predicate call_residue_check(0). |
| 76 | | call_residue_check(Call) :- % print_term_summary(Call),nl, |
| 77 | | call_residue(Call,Residue), |
| 78 | | (Residue = [] -> true |
| 79 | | ; add_internal_error('Call had residue: ',residue(Residue)/call(Call)), |
| 80 | | print_goal(Residue),nl |
| 81 | | ). |
| 82 | | my_findall(X,P,L,ExpectedFinalResult) :- |
| 83 | | (ExpectedFinalResult==[] |
| 84 | | -> \+(call_residue_check(P)), |
| 85 | | L=[] % we know the end result to be empty; not necessary to try and find all solutions; <--- we should probably treat this somewhere else to ensure that we do not throw all_solutions enumeration warnings |
| 86 | | ; findall(X,call_residue_check(P),L) |
| 87 | | ). |
| 88 | | :- else. |
| 89 | | my_findall(X,P,L,ExpectedFinalResult) :- |
| 90 | | (ExpectedFinalResult==[] |
| 91 | | -> \+(P),L=[] % we know the end result to be empty; not necessary to try and find all solutions; <--- we should probably treat this somewhere else to ensure that we do not throw all_solutions enumeration warnings |
| 92 | | ; findall(X,P,L)). |
| 93 | | %; findall(X,(P,print(sol(X)),nl,nl,trace),L)). |
| 94 | | :- endif. |
| 95 | | |
| 96 | | |
| 97 | | |
| 98 | | |
| 99 | | my_findall_catch(X,P,L,ExpectedFinalResult,Span) :- |
| 100 | | my_findall_catch(X,P,L,ExpectedFinalResult,EnumWarningWhichOcc,Span), |
| 101 | | (enum_warning_occ(EnumWarningWhichOcc) -> throw(EnumWarningWhichOcc) ; true). |
| 102 | | |
| 103 | | enum_warning_occ(EnumWarningWhichOcc) :- |
| 104 | | nonvar(EnumWarningWhichOcc),EnumWarningWhichOcc=enumeration_warning(_,_,_,_,_). |
| 105 | | |
| 106 | | my_findall_catch(X,P,L,ExpectedFinalResult,EnumWarningWhichOcc,Span) :- |
| 107 | | enter_new_error_scope(Level,my_findall_catch), |
| 108 | | throw_enumeration_warnings_in_scope(Level,critical,Span), % critical enumeration warnings are thrown straight away |
| 109 | | call_cleanup( |
| 110 | | my_findall(X,P,L,ExpectedFinalResult), |
| 111 | | (event_occurred_in_error_scope(enumeration_warning(A,B,C,D,E)) |
| 112 | | -> exit_error_scope(Level,_,my_findall_catch_error), |
| 113 | | % do we need to throw the enumeration warning ? |
| 114 | | EnumWarningWhichOcc=enumeration_warning(A,B,C,D,E), |
| 115 | | debug_println(9,my_findall_catch(enumeration_warning(A,B,C,D,E))), |
| 116 | | true %throw(enumeration_warning(A,B,C,D,E)) |
| 117 | | ; exit_error_scope(Level,_,my_findall_catch_no_error), |
| 118 | | EnumWarningWhichOcc=false)). |
| 119 | | |
| 120 | | :- use_module(runtime_profiler,[observe_runtime_wf/4]). |
| 121 | | my_findall_check(X,P,L,ExpectedFinalResult,TimeOutCode,VirtualTimeOutCode,WF,Span) :- |
| 122 | | statistics(runtime,[Start,_]), |
| 123 | | statistics(walltime,[WStart,_]), Timer = [Start,WStart], |
| 124 | | get_total_number_of_errors(Nr1), % now also does count stored wd errors, see WD_SetCompr_Error |
| 125 | | %format('Start closure expansion at ~w ms~n',[Start]),print_message_span(Span),nl, |
| 126 | | call_cleanup((my_findall_catch(X,P,L,ExpectedFinalResult,EnumWarningWhichOcc,Span),Ok=true), |
| 127 | | (Ok==true,EnumWarningWhichOcc==false |
| 128 | | -> get_total_number_of_errors(Nr2), |
| 129 | | (Nr2>Nr1 -> add_set_compr_err(Nr1,Nr2,Span,WF), |
| 130 | | %TODO: this message is probably less useful / redundant now due to call stack info display |
| 131 | | fail % TO DO: see comment below in delay_setof_wf |
| 132 | | ; observe_runtime_wf(Timer,'==PERF-MESSAGE==> Long closure expansion: ',Span,WF) %, print(done),nl |
| 133 | | %,statistics(runtime,[End,_]), Tot is End-Start, |
| 134 | | %(Tot>10 -> length(L,Len),add_message(delay,'Long closure expansion:',ms_sols(Tot,Len),Span) ; true) |
| 135 | | ) |
| 136 | | ; /* failure or time-out; --> time-out as findall should never fail */ |
| 137 | | statistics(runtime,[End,_]), Tot is End-Start, |
| 138 | | (enum_warning_occ(EnumWarningWhichOcc) |
| 139 | | -> (VirtualTimeOutCode = _:true -> true |
| 140 | | ; print('### VIRTUAL TIME-OUT after: '), print(Tot), print(' ms'),nl, |
| 141 | | call(VirtualTimeOutCode) |
| 142 | | ), %print(throw(EnumWarningWhichOcc)),nl, |
| 143 | | throw(EnumWarningWhichOcc) % ??? this is a set-comprehension expression; failure would mean not-well-defined |
| 144 | | ; Tot>1000 -> % TO DO: could also be CTRL-C ! we could use catch_interrupt_assertion_call(my_findall_catch) or catch(my_finall_catch,user_interrupt_signal) |
| 145 | | call(TimeOutCode), % Warning: this call is also called if an outer-time-out is triggered ! |
| 146 | | format('Runtime for set comprehension expansion until TIME-OUT: ~w ms~n',[Tot]) |
| 147 | | % WHY DON'T WE FAIL HERE ---> because exception is passed on to outer calls after call_cleanup |
| 148 | | ; true) % check if the findall is probably responsible for the time-out |
| 149 | | )). |
| 150 | | |
| 151 | | add_set_compr_err(Nr1,Nr2,Span,WF) :- |
| 152 | | NrErrs is Nr2-Nr1, |
| 153 | | (NrErrs=1 -> Msg= 'Error occurred during expansion of set comprehension' |
| 154 | | ; ajoin(['Errors (',NrErrs,') occurred during expansion of set comprehension'],Msg) |
| 155 | | ), |
| 156 | | add_wd_error_span_now(Msg,'',Span,WF). |
| 157 | | % add_error_wf(well_definedness_error,Msg,'',Span,WF). |
| 158 | | |
| 159 | | /* ----------------------------------------- */ |
| 160 | | |
| 161 | | /* Below is a findall that delays until all |
| 162 | | non-output variables have become ground. |
| 163 | | Ideally, one would want a delay_findall that |
| 164 | | figures out by itself when it has all the answers |
| 165 | | (by looking at call_residue) and that may |
| 166 | | even progressively instantiate the output list |
| 167 | | such as in: |
| 168 | | delay_findall(X,delay_member(X,[a|T]),R), delay_member(Z,R) |
| 169 | | But this will require more involved machinery. |
| 170 | | */ |
| 171 | | |
| 172 | | |
| 173 | | :- use_module(kernel_objects,[equal_object_wf/4]). |
| 174 | | :- use_module(kernel_tools,[ground_value_check/2]). |
| 175 | | :- use_module(kernel_waitflags,[start_attach_inner_abort_errors/2, re_attach_pending_inner_abort_errors/3]). |
| 176 | | |
| 177 | | % the following is called by expand_normal_closure_direct |
| 178 | | % which uses ground_inner_wait_flags_in_context, which registers pending WD errors |
| 179 | | % these are re-attached to the outer WF by re_attach_pending_inner_abort_errors |
| 180 | | delay_setof_wf(V,G,FullSetResult,WVars,Done,WF,Span) :- %print(delay_set_of(V)),nl, |
| 181 | | ground_value_check(WVars,GW), |
| 182 | | block_my_findall_catch_wf2(GW,V,G,FullSetResult,Done,WF,Span). |
| 183 | | % comment in to perform idling to allow outer co-routines to run; useful when WD condition attached to Body G |
| 184 | | %:- use_module(kernel_waitflags,[get_idle_wait_flag/3]). |
| 185 | | %:- block block_my_findall_catch_wf(-,?,?,?,?,?). |
| 186 | | %block_my_findall_catch_wf(_,V,G,FullSetResult,Done,WF) :- |
| 187 | | % get_idle_wait_flag(delay_setof_wf,WF,LWF), |
| 188 | | % print(idling(WF,LWF)),nl, |
| 189 | | % block_my_findall_catch_wf2(LWF,V,G,FullSetResult,Done,WF,Span). |
| 190 | | :- block block_my_findall_catch_wf2(-,?,?,?,?,?,?). |
| 191 | | block_my_findall_catch_wf2(_,V,G,FullSetResult,Done,WF,Span) :- |
| 192 | | get_total_number_of_errors(Nr1), |
| 193 | | start_attach_inner_abort_errors(Level,block_my_findall_catch_wf2), |
| 194 | | call_cleanup(my_findall_catch(V,G,RRes,FullSetResult,Span), |
| 195 | | re_attach_pending_inner_abort_errors(Level,WF,Pending)), |
| 196 | | transform_result_into_set(RRes,SetRes), |
| 197 | | get_total_number_of_errors(Nr2), %print(f(Nr1,Nr2)),nl, |
| 198 | | (Nr2>Nr1 |
| 199 | | -> add_set_compr_err(Nr1,Nr2,Span,WF), % should we use add_wd_error_span('...: ','@compr'(..),Span,WF) |
| 200 | | fail |
| 201 | | % TO DO?: we could add_abort error here instead of adding a real error |
| 202 | | % for this, however, the inner abort_errors should only be recorded, not yet raised for the user |
| 203 | | ; true), |
| 204 | ? | eq_object_findall_result(SetRes,FullSetResult,Pending,WF), |
| 205 | | Done=true. |
| 206 | | |
| 207 | | eq_object_findall_result(SetRes,FullSetResult,_Pending,WF) :- |
| 208 | ? | equal_object_wf(SetRes,FullSetResult,delay_setof_wf,WF). |
| 209 | | % TODO: activate the following: see test 2459 and test 1921 |
| 210 | | %eq_object_findall_result(SetRes,FullSetResult,Pending,WF) :- |
| 211 | | % (Pending=pending_abort_errors, \+ get_preference(find_abort_values,false) |
| 212 | | % -> true, write(wd_error),nl % avoid instantiating result to avoid failing on result value (which is not wd anyway) |
| 213 | | % ; equal_object_wf(SetRes,FullSetResult,delay_setof_wf,WF) |
| 214 | | % ). |
| 215 | | |
| 216 | | % called by expand_normal_closure2, calling b_test_closure |
| 217 | | % which uses ground_inner_wait_flags_in_context, which registers pending WD errors |
| 218 | | % these are re-attached to the outer WF by re_attach_pending_inner_abort_errors |
| 219 | | delay_setof_check_wf(V,G,FullSetResult,WVars,Done,TimeOutCode,VirtualTimeOutCode,WF,Span) :- %print(delay_set_of(V)),nl, |
| 220 | | %% print(wait_vars(WVars,G)),nl, %% |
| 221 | | ground_value_check(WVars,GW), |
| 222 | | block_findall_check(GW,V,G,FullSetResult,TimeOutCode,VirtualTimeOutCode,Done,FullSetResult,WF,Span). |
| 223 | | |
| 224 | | :- block block_findall_check(-,?,?,?,?,?,?,?,?,?). |
| 225 | | block_findall_check(_,V,G,FullSetResult,TimeOutCode,VirtualTimeOutCode,Done,FullSetResult,WF,Span) :- |
| 226 | | start_attach_inner_abort_errors(Level,block_findall_check), |
| 227 | | call_cleanup(my_findall_check(V,G,RRes,FullSetResult,TimeOutCode,VirtualTimeOutCode,WF,Span), |
| 228 | | re_attach_pending_inner_abort_errors(Level,WF,Pending)), |
| 229 | | transform_result_into_set(RRes,SetRes), % will generate AVL tree |
| 230 | | % print(delay_setof_result(SetRes,FullSetResult)),nl, translate:print_bvalue(SetRes),nl, |
| 231 | ? | eq_object_findall_result(SetRes,FullSetResult,Pending,WF), |
| 232 | | Done=true. |
| 233 | | |
| 234 | | :- use_module(tools_printing,[print_term_summary/1]). |
| 235 | | :- use_module(custom_explicit_sets,[convert_to_avl/2]). |
| 236 | | :- use_module(closures,[is_symbolic_closure/1]). |
| 237 | ? | transform_result_into_set([ONE],SetRes) :- is_symbolic_closure(ONE),!, |
| 238 | | debug_println(9,not_expanding_singleton_delay_result), |
| 239 | | % do not convert_to_avl; would lead to enumeration warning (see test 2157) |
| 240 | | SetRes = [ONE]. |
| 241 | | transform_result_into_set(RRes,SetRes) :- % print(transform_result_into_set(RRes,SetRes)), |
| 242 | ? | (convert_to_avl(RRes,SetRes) % we are sure that RRes is ground !!?? |
| 243 | | -> true |
| 244 | | ; print_term_summary(convert_to_avl_failed(RRes,SetRes)), |
| 245 | | convert_list_of_expressions_into_set(RRes,SetRes)). |
| 246 | | |
| 247 | | :- use_module(b_interpreter,[convert_list_of_expressions_into_set_wf/4]). |
| 248 | | convert_list_of_expressions_into_set(List,Set) :- |
| 249 | | init_wait_flags(WF,[convert_list_of_expressions_into_set]), |
| 250 | | convert_list_of_expressions_into_set_wf(List,Set,set(any),WF), |
| 251 | | ground_wait_flags(WF). |
| 252 | | |
| 253 | | /* same as above but Result is a list of elements; */ |
| 254 | | /* the list should not be interpreted as a set, but each element is a value for a parameter */ |
| 255 | | /* There is a very small chance that the same value is represented twice in the list (e.g., once as closure once as explicit list) */ |
| 256 | | % last argument is simple waitflag |
| 257 | | % used for forall-domain |
| 258 | | |
| 259 | | :- block delay_setof_list_wf(?,?,?,-,?). |
| 260 | | delay_setof_list_wf(V,G,FullSetResult,_BodyGround,WF) :- |
| 261 | | start_attach_inner_abort_errors(Level,delay_setof_list_wf), |
| 262 | | call_cleanup(my_findall(V,G,RRes,FullSetResult), |
| 263 | | re_attach_pending_inner_abort_errors(Level,WF,_Pending)), |
| 264 | | ll_norm(RRes,NormRRes), |
| 265 | | sort(NormRRes,SNormRRes), % removes duplicates |
| 266 | | FullSetResult=SNormRRes. % Note: we instantiate even if Pending=pending_abort_errors |
| 267 | | |
| 268 | | |
| 269 | | % normalise a list of list of values; the inner lists are not sets but values for parameters |
| 270 | | ll_norm([],[]). |
| 271 | | ll_norm([El1|T1],[El2|T2]) :- l_check_norm_required(El1,El2,NormRequired), |
| 272 | | (var(NormRequired) -> T1=T2 % no normalisation required: simply copy rest of list |
| 273 | | % TO DO: we could also statically determine based on parameter types whether normalising is required |
| 274 | | ; ll_norm2(T1,T2)). |
| 275 | | |
| 276 | | :- use_module(store,[l_normalise_values/2]). |
| 277 | | ll_norm2([],[]). |
| 278 | | ll_norm2([El1|T1],[El2|T2]) :- l_normalise_values(El1,El2), ll_norm2(T1,T2). |
| 279 | | |
| 280 | | % normalise a value and return norm_required in last argument if it is needed |
| 281 | | l_check_norm_required([],[],_). |
| 282 | | l_check_norm_required([H|T],[NH|NT],NormRequired) :- |
| 283 | | check_norm_required(H,NH,NormRequired), |
| 284 | | l_check_norm_required(T,NT,NormRequired). |
| 285 | | |
| 286 | | check_norm_required(pred_true,R,_) :- !, R=pred_true. |
| 287 | | check_norm_required(pred_false,R,_) :- !, R=pred_false. |
| 288 | | check_norm_required(int(S),R,_) :- !, R=int(S). |
| 289 | | check_norm_required(fd(X,T),R,_) :- !, R=fd(X,T). |
| 290 | | check_norm_required(string(S),R,_) :- !, R=string(S). |
| 291 | | check_norm_required((A,B),(NA,NB),NormRequired) :- !, |
| 292 | | check_norm_required(A,NA,NormRequired), check_norm_required(B,NB,NormRequired). |
| 293 | | % to do: add record and freeval |
| 294 | | check_norm_required(V,NV,norm_required) :- |
| 295 | | store:normalise_value(V,NV). % does not normalise closure/3 values |
| 296 | | |
| 297 | | |
| 298 | | |
| 299 | | |
| 300 | | |
| 301 | | %:- use_module(tools,[remove_variables/3]). |
| 302 | | %compute_wait_variables(WaitTerm,OutputVars,WaitVars) :- |
| 303 | | % term_variables(WaitTerm,Vars), |
| 304 | | % term_variables(OutputVars,RealOutputVars), |
| 305 | | % remove_variables(Vars,RealOutputVars,WaitVars). |
| 306 | | |
| 307 | | |
| 308 | | %delay_call(Call,WaitTerm,OutputVars) :- |
| 309 | | % compute_wait_variables(WaitTerm,OutputVars,WaitVars), |
| 310 | | %print_message(delay(Call,WaitVars)), |
| 311 | | % when(ground(WaitVars),Call). |
| 312 | | |
| 313 | | %delay_call(Call,OutputVars) :- |
| 314 | | % delay_call(Call,Call,OutputVars). |
| 315 | | |
| 316 | | % LocalWF: created by create_inner_wait_flags; enumeration finished waitflag should not be grounded here |
| 317 | | %delay_not(Call,OutputVars, LocalWF) :- % print_message(informational,delay_not(Call,OutputVars,LocalWF)), |
| 318 | | % delay_call( not_with_enum_warning(Call, LocalWF) , OutputVars). |
| 319 | | |
| 320 | | :- use_module(probsrc(kernel_waitflags),[add_message_wf/5]). |
| 321 | | not_with_enum_warning(Call, LocalWF, PP, Span) :- |
| 322 | | %% print_term_summary(neg_call(Call, LocalWF)), %% |
| 323 | | enter_new_clean_error_scope(Level), |
| 324 | | call_cleanup((not_with_enum_warning2(Call,Level,LocalWF,Span) -> Ok=true ; Ok=false), |
| 325 | | ((var(Ok), silent_mode(off) |
| 326 | | -> add_message_wf(delay,'TIME OUT or Exception inside: ',PP,Span,LocalWF) |
| 327 | | ; true), |
| 328 | | exit_error_scope(Level,_ErrOccured,not_with_enum_warn))), |
| 329 | | Ok==true. |
| 330 | | |
| 331 | | :- use_module(tools_printing,[print_goal/1]). |
| 332 | | :- use_module(preferences,[get_preference/2]). |
| 333 | | :- use_module(kernel_waitflags,[add_error_wf/5, add_warning_wf/5]). |
| 334 | | not_with_enum_warning2(Call,Level,LocalWF,Span) :- |
| 335 | | (pending_abort_error(LocalWF) |
| 336 | | -> add_warning_wf(not_with_enum_warning,'Abort error pending before call:',Level,Span,LocalWF),nl |
| 337 | | ; true), |
| 338 | ? | (call_residue(Call,Residue) -> |
| 339 | | % Call has succeeded, negation thus fails |
| 340 | | (pending_abort_error(LocalWF) |
| 341 | | -> debug_println(4,pending_abort_error(LocalWF)), |
| 342 | | PENDING_ABORT = true |
| 343 | | % we do not fail in this case, so that abort errors can be raised |
| 344 | | % relevant for test 1966 or predicate f={1|->2} & not(#s.(s:1..2 & f(s)=3)) with -p TRY_FIND_ABORT TRUE |
| 345 | | ; Residue \= [] -> |
| 346 | | (get_preference(use_chr_solver,true) |
| 347 | | -> add_warning_wf(not_with_enum_warning,'Call (in negation) had residue (possibly due to use of CHR making call_residue imprecise): ',residue(Residue)/call(Call),Span,LocalWF) |
| 348 | | ; add_error_wf(not_with_enum_warning, |
| 349 | | 'Call (in negation) had residue: ',residue(Residue)/call(Call),Span,LocalWF), |
| 350 | | print_goal(Residue),nl |
| 351 | | ), |
| 352 | | fail |
| 353 | | ; clear_enumeration_warning_in_error_scope(Level), fail |
| 354 | | % call has succeeded without pending abort errors |
| 355 | | ) |
| 356 | | ; true |
| 357 | | ), |
| 358 | | % Note: everything else is ground; so Call should not trigger any other co-routines/enumeration ?! |
| 359 | | Event = enumeration_warning(_,_,_,_,_), |
| 360 | ? | (event_occurred_in_error_scope(Event) % critical ? only at this level ? or also below ? |
| 361 | | -> PENDING_ABORT==true, %print(grd(LocalWF)),nl, kernel_waitflags:portray_waitflags(LocalWF),nl, |
| 362 | | ground_wait_flags(LocalWF), % raise any potential abort errors |
| 363 | | debug_println(19,grounded_wait_flag_for_pending_abort_error), % THIS print is important due to issue SPRM-20473 in SICStus Prolog which will otherwise *not* activate the pending co-routines attached to LocalWF ! |
| 364 | | fail |
| 365 | | %, print_message(throwing(Event)), throw(Event) % or simply re-post enum warning ? |
| 366 | | % we could also simply fail and raise an enumeration warning; meaning we havent explored all possibilities |
| 367 | | % Note: at the moment the error is copied into the outer scope by copy_error_scope_events |
| 368 | | ; true |
| 369 | | ). |
| 370 | | |
| 371 | | |
| 372 | | |