PathCanonical,
#[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
FileTime,
- #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_non_head")))]
- DeleteAttribute,
- #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_head")))]
- DeleteHeadAttribute,
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
DynamicModuleResolution(usize),
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
PrepareCallClause(usize),
- #[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
- EnqueueAttributedVar,
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
FetchGlobalVar,
#[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
GetClauseP,
#[strum_discriminants(strum(props(Arity = "6", Name = "$invoke_clause_at_p")))]
InvokeClauseAtP,
- #[strum_discriminants(strum(props(Arity = "2", Name = "$get_from_attr_list")))]
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$get_from_attr_list")))]
GetFromAttributedVarList,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$put_to_attr_list")))]
+ PutToAttributedVarList,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$del_from_attr_list")))]
+ DeleteFromAttributedVarList,
REPL(REPLCodePtr),
}
&Instruction::CallDeleteDirectory(_) |
&Instruction::CallPathCanonical(_) |
&Instruction::CallFileTime(_) |
- &Instruction::CallDeleteAttribute(_) |
- &Instruction::CallDeleteHeadAttribute(_) |
&Instruction::CallDynamicModuleResolution(..) |
&Instruction::CallPrepareCallClause(..) |
&Instruction::CallCompileInlineOrExpandedGoal(..) |
&Instruction::CallGetClauseP(_) |
&Instruction::CallInvokeClauseAtP(_) |
&Instruction::CallGetFromAttributedVarList(_) |
- &Instruction::CallEnqueueAttributedVar(_) |
+ &Instruction::CallPutToAttributedVarList(_) |
+ &Instruction::CallDeleteFromAttributedVarList(_) |
&Instruction::CallFetchGlobalVar(_) |
&Instruction::CallFirstStream(_) |
&Instruction::CallFlushOutput(_) |
&Instruction::ExecuteDeleteDirectory(_) |
&Instruction::ExecutePathCanonical(_) |
&Instruction::ExecuteFileTime(_) |
- &Instruction::ExecuteDeleteAttribute(_) |
- &Instruction::ExecuteDeleteHeadAttribute(_) |
&Instruction::ExecuteDynamicModuleResolution(..) |
&Instruction::ExecutePrepareCallClause(..) |
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
&Instruction::ExecuteGetClauseP(_) |
&Instruction::ExecuteInvokeClauseAtP(_) |
&Instruction::ExecuteGetFromAttributedVarList(_) |
- &Instruction::ExecuteEnqueueAttributedVar(_) |
+ &Instruction::ExecutePutToAttributedVarList(_) |
+ &Instruction::ExecuteDeleteFromAttributedVarList(_) |
&Instruction::ExecuteFetchGlobalVar(_) |
&Instruction::ExecuteFirstStream(_) |
&Instruction::ExecuteFlushOutput(_) |
'$default_attr_list'(PGs, Module, AttrVar).
'$default_attr_list'([], _, _) --> [].
-'$absent_attr'(V, Attr) :-
- '$get_attr_list'(V, Ls),
- '$absent_from_list'(Ls, Attr).
-
-'$absent_from_list'(X, Attr) :-
- ( var(X) ->
- true
- ; X = [L|Ls],
- L \= Attr ->
- '$absent_from_list'(Ls, Attr)
- ).
-
-'$get_attr'(V, Attr) :-
- '$get_attr_list'(V, Ls),
- nonvar(Ls),
- '$get_from_attr_list'(Ls, Attr).
-
-/*
-'$get_from_list'([L|Ls], V, Attr) :-
- nonvar(L),
- ( L \= Attr ->
- nonvar(Ls),
- '$get_from_list'(Ls, V, Attr)
- ; L = Attr
- ).
-*/
-
-'$put_attr'(V, Attr) :-
- '$get_attr_list'(V, Ls),
- '$add_to_list'(Ls, V, Attr).
-
-'$add_to_list'(Ls, V, Attr) :-
- ( var(Ls) ->
- Ls = [Attr | _],
- '$enqueue_attr_var'(V)
- ; Ls = [_ | Ls0],
- '$add_to_list'(Ls0, V, Attr)
- ).
-
-'$del_attr'(Ls0, _, _) :-
- var(Ls0),
- !.
-'$del_attr'(Ls0, V, Attr) :-
- Ls0 = [Att | Ls1],
- nonvar(Att),
- ( Att \= Attr ->
- '$del_attr_buried'(Ls0, Ls1, V, Attr)
- ; '$del_attr_head'(V),
- '$del_attr'(Ls1, V, Attr)
- ).
-
-'$del_attr_step'(Ls1, V, Attr) :-
- ( nonvar(Ls1) ->
- Ls1 = [_ | Ls2],
- '$del_attr_buried'(Ls1, Ls2, V, Attr)
+'$absent_attr'(V, Module, Attr) :-
+ ( '$get_from_attr_list'(V, Module, Attr) ->
+ false
; true
).
-%% assumptions: Ls0 is a list, Ls1 is its tail;
-%% the head of Ls0 can be ignored.
-'$del_attr_buried'(Ls0, Ls1, V, Attr) :-
- ( var(Ls1) -> true
- ; Ls1 = [Att | Ls2] ->
- ( Att \= Attr ->
- '$del_attr_buried'(Ls1, Ls2, V, Attr)
- ; '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
- '$del_attr_step'(Ls1, V, Attr)
- )
- ).
-
'$copy_attr_list'(L, _Module, []) :- var(L), !.
'$copy_attr_list'([Module0:Att|Atts], Module, CopiedAtts) :-
( Module0 == Module ->
{ functor(Attr, Name, Arity) },
[(put_atts(V, +Attr) :-
!,
- functor(Attr, Head, Arity),
- functor(AttrForm, Head, Arity),
- '$get_attr_list'(V, Ls),
- atts:'$del_attr'(Ls, V, Module:AttrForm),
- atts:'$put_attr'(V, Module:Attr)),
- (put_atts(V, Attr) :-
+ '$put_to_attr_list'(V, Module, Attr)),
+ (put_atts(V, Attr) :-
!,
- functor(Attr, Head, Arity),
- functor(AttrForm, Head, Arity),
- '$get_attr_list'(V, Ls),
- atts:'$del_attr'(Ls, V, Module:AttrForm),
- atts:'$put_attr'(V, Module:Attr)),
+ '$put_to_attr_list'(V, Module, Attr)),
(put_atts(V, -Attr) :-
!,
- functor(Attr, _, _),
- '$get_attr_list'(V, Ls),
- atts:'$del_attr'(Ls, V, Module:Attr))].
+ '$del_from_attr_list'(V, Module, Attr))].
get_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity) },
[(get_atts(V, +Attr) :-
!,
functor(Attr, _, _),
- atts:'$get_attr'(V, Module:Attr)),
+ atts:'$get_from_attr_list'(V, Module, Attr)),
(get_atts(V, Attr) :-
!,
functor(Attr, _, _),
- atts:'$get_attr'(V, Module:Attr)),
+ atts:'$get_from_attr_list'(V, Module, Attr)),
(get_atts(V, -Attr) :-
!,
functor(Attr, _, _),
- atts:'$absent_attr'(V, Module:Attr))].
+ atts:'$absent_attr'(V, Module, Attr))].
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
nonvar(Term),
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
}
+ debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::AttrVar);
self.attr_var_init.bindings.push((h, addr));
}
.map(|(ref h, _)| attr_var_as_cell!(*h));
let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
-
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
-
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
+
(var_list_addr, value_list_addr)
}
self.file_time();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
- &Instruction::CallDeleteAttribute(_) => {
- self.delete_attribute();
- self.machine_st.p += 1;
- }
- &Instruction::ExecuteDeleteAttribute(_) => {
- self.delete_attribute();
- self.machine_st.p = self.machine_st.cp;
- }
- &Instruction::CallDeleteHeadAttribute(_) => {
- self.delete_head_attribute();
- self.machine_st.p += 1;
- }
- &Instruction::ExecuteDeleteHeadAttribute(_) => {
- self.delete_head_attribute();
- self.machine_st.p = self.machine_st.cp;
- }
&Instruction::CallDynamicModuleResolution(arity, _) => {
let (module_name, key) = try_or_throw!(
self.machine_st,
self.machine_st.backtrack();
}
}
- &Instruction::CallEnqueueAttributedVar(_) => {
- self.enqueue_attributed_var();
- self.machine_st.p += 1;
- }
- &Instruction::ExecuteEnqueueAttributedVar(_) => {
- self.enqueue_attributed_var();
- self.machine_st.p = self.machine_st.cp;
- }
&Instruction::CallFetchGlobalVar(_) => {
self.fetch_global_var();
step_or_fail!(self, self.machine_st.p += 1);
self.get_from_attributed_variable_list();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
+ &Instruction::CallPutToAttributedVarList(_) => {
+ self.put_to_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePutToAttributedVarList(_) => {
+ self.put_to_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDeleteFromAttributedVarList(_) => {
+ self.delete_from_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDeleteFromAttributedVarList(_) => {
+ self.delete_from_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
}
}
let l = self.machine_st.trail[i + 1].get_value() as usize;
if l < self.machine_st.hb {
- self.machine_st.heap[h] = list_loc_as_cell!(l);
+ if h == l {
+ self.machine_st.heap[h] = heap_loc_as_cell!(h);
+ } else {
+ read_heap_cell!(self.machine_st.heap[l],
+ (HeapCellValueTag::Var) => {
+ self.machine_st.heap[h] = list_loc_as_cell!(l);
+ }
+ _ => {
+ self.machine_st.heap[h] = heap_loc_as_cell!(l);
+ }
+ );
+ }
} else {
self.machine_st.heap[h] = heap_loc_as_cell!(h);
}
}
}
+#[derive(Debug)]
+enum MatchSite {
+ NoMatchVarTail(usize), // no match, we refer to the location of the uninstantiated tail instead.
+ Match(usize), // a match
+}
+
+#[derive(Debug)]
+struct AttrListMatch {
+ match_site: MatchSite,
+ prev_tail: Option<usize>,
+}
+
impl MachineState {
+ pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Option<usize> {
+ read_heap_cell!(attr_var,
+ (HeapCellValueTag::AttrVar, h) => {
+ Some(h + 1)
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ // create an AttrVar in the heap.
+ let h = self.heap.len();
+
+ self.heap.push(attr_var_as_cell!(h));
+ self.heap.push(heap_loc_as_cell!(h+1));
+
+ self.bind(Ref::attr_var(h), attr_var);
+
+ Some(h + 1)
+ }
+ _ => {
+ None
+ }
+ )
+ }
+
pub(crate) fn name_and_arity_from_heap(&self, cell: HeapCellValue) -> Option<PredicateKey> {
read_heap_cell!(self.store(self.deref(cell)),
(HeapCellValueTag::Str, s) => {
let attr_var = self.deref_register(1);
let attr_var_list = read_heap_cell!(attr_var,
(HeapCellValueTag::AttrVar, h) => {
- h + 1
+ h+1
}
- (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
- // create an AttrVar in the heap.
- let h = self.machine_st.heap.len();
-
- self.machine_st.heap.push(attr_var_as_cell!(h));
- self.machine_st.heap.push(heap_loc_as_cell!(h+1));
-
- self.machine_st.bind(Ref::attr_var(h), attr_var);
- h + 1
+ (HeapCellValueTag::Var, h) => {
+ h
}
_ => {
self.machine_st.fail = true;
#[inline(always)]
pub(crate) fn get_from_attributed_variable_list(&mut self) {
- let mut attrs_list = self.deref_register(1);
- let attr = self.deref_register(2);
-
- let (name, arity) = match self.machine_st.name_and_arity_from_heap(attr) {
- Some(key) => key,
- None => {
+ let attr_var = self.deref_register(1);
+ let attr = self.deref_register(3);
+ let attr_var_list = read_heap_cell!(attr_var,
+ (HeapCellValueTag::AttrVar, h) => {
+ self.machine_st.heap[h+1]
+ }
+ _ => {
self.machine_st.fail = true;
return;
}
- };
-
- while let HeapCellValueTag::Lis = attrs_list.get_tag() {
- let mut list_head = self.machine_st.heap[attrs_list.get_value()];
-
- loop {
- read_heap_cell!(list_head,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if list_head != self.machine_st.heap[h] {
- list_head = self.machine_st.heap[h];
- } else {
- self.machine_st.fail = true;
- return;
- }
- }
- (HeapCellValueTag::Str | HeapCellValueTag::Atom) => {
- let (t_name, t_arity) = self.machine_st
- .name_and_arity_from_heap(list_head)
- .unwrap();
-
- if name == t_name && arity == t_arity {
- let old_tr = self.machine_st.tr;
-
- unify!(self.machine_st, list_head, attr);
+ );
- if self.machine_st.fail {
- let curr_tr = self.machine_st.trail.len();
+ let module = self.deref_register(2);
- self.unwind_trail(old_tr, curr_tr);
- self.machine_st.tr = old_tr;
+ match self.match_attribute(attr_var_list, module, attr) {
+ Some(AttrListMatch { match_site: MatchSite::Match(match_site), .. }) => {
+ let list_head = self.machine_st.heap[match_site];
- self.machine_st.pdl.clear();
- self.machine_st.fail = false;
- } else {
- return;
- }
- }
+ if list_head.get_value() == match_site {
+ // at the end of the list, no match found in this case.
+ self.machine_st.fail = true;
+ } else {
+ let (_, qualified_goal) = self.machine_st.strip_module(
+ list_head,
+ empty_list_as_cell!(),
+ );
- break;
- }
- _ => {
- break;
- }
- );
+ unify!(self.machine_st, qualified_goal, attr);
+ }
+ }
+ _ => {
+ self.machine_st.fail = true;
}
-
- attrs_list = self.machine_st.store(
- self.machine_st.deref(self.machine_st.heap[attrs_list.get_value()+1])
- );
}
-
- self.machine_st.fail = true;
}
#[inline(always)]
}
#[inline(always)]
- pub(crate) fn enqueue_attributed_var(&mut self) {
- let addr = self.deref_register(1);
-
- read_heap_cell!(addr,
+ pub(crate) fn delete_from_attributed_variable_list(&mut self) {
+ let attr_var = self.deref_register(1);
+ let attr = self.deref_register(3);
+ let attr_var_list = read_heap_cell!(attr_var,
(HeapCellValueTag::AttrVar, h) => {
- self.machine_st.attr_var_init.attr_var_queue.push(h);
+ h + 1
}
_ => {
+ return;
}
);
+
+ let module = self.deref_register(2);
+
+ match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
+ Some(AttrListMatch { prev_tail, match_site: MatchSite::Match(match_site) }) => {
+ let prev_tail = if let Some(prev_tail) = prev_tail {
+ // not at the head.
+ prev_tail
+ } else {
+ if self.machine_st.heap[match_site + 1].is_var() {
+ let h = attr_var.get_value();
+
+ self.machine_st.heap[h] = heap_loc_as_cell!(h);
+ self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
+ }
+
+ // at the head.
+ attr_var_list
+ };
+
+ if self.machine_st.heap[match_site + 1].get_tag() == HeapCellValueTag::Lis {
+ let prev_tail_value = self.machine_st.heap[match_site + 1].get_value();
+ self.machine_st.heap[prev_tail].set_value(prev_tail_value);
+ } else {
+ self.machine_st.heap[prev_tail] = heap_loc_as_cell!(prev_tail);
+ }
+
+ self.machine_st.trail(TrailRef::AttrVarListLink(prev_tail, match_site));
+ }
+ _ => {
+ }
+ }
}
#[inline(always)]
- pub(crate) fn delete_attribute(&mut self) {
- let ls0 = self.deref_register(1);
+ pub(crate) fn put_to_attributed_variable_list(&mut self) {
+ let attr_var = self.deref_register(1);
+ let attr = self.deref_register(3);
+ let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) {
+ Some(h) => h,
+ None => {
+ self.machine_st.fail = true;
+ return;
+ }
+ };
- if let HeapCellValueTag::Lis = ls0.get_tag() {
- let l1 = ls0.get_value();
- let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
+ let module = self.deref_register(2);
+
+ /*
+ * How to handle attribute trailing using just AttrVarListLink (which
+ * should be re-named to something more general) in unwind_trail:
+ *
+ * Given AttrVarListLink(h, l):
+ *
+ * 1. Check cell at offset l.
+ * 2. If h == l, set heap[h] = heap_loc_as_cell!(h).
+ * 3. If cell is a Var, set heap[h] = list_loc_as_cell!(l).
+ * 4. Otherwise, cell points to an element of the list which is therefore
+ * an atom or str. Set heap[h] accordingly.
+ *
+ * For this to work, all elements of attributed variable lists must be
+ * heap cell locs pointing to later elements in the heap, either atoms (0-arity)
+ * or str cells (> 0-arity).
+ */
- if let HeapCellValueTag::Lis = ls1.get_tag() {
- let l2 = ls1.get_value();
+ let h = self.machine_st.heap.len();
- let old_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l1+1]));
- let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
+ self.machine_st.heap.push(str_loc_as_cell!(h+1));
+ self.machine_st.heap.extend(functor!(atom!(":"), [cell(module), cell(attr)]));
- let tail = if tail.is_var() {
- heap_loc_as_cell!(l1 + 1)
- } else {
- tail
- };
+ match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
+ Some(AttrListMatch { match_site, .. }) => {
+ let (match_site, l) = match match_site {
+ MatchSite::NoMatchVarTail(match_site) => {
+ let l = self.machine_st.heap[match_site].get_value();
- let trail_ref = read_heap_cell!(old_addr,
- (HeapCellValueTag::Var, h) => {
- TrailRef::AttrVarHeapLink(h)
- }
- (HeapCellValueTag::Lis, l) => {
- TrailRef::AttrVarListLink(l1 + 1, l)
+ // at the end of the (non-empty) list here.
+ self.machine_st.heap[match_site] = list_loc_as_cell!(h+4);
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ self.machine_st.heap.push(heap_loc_as_cell!(h+5));
+
+ (match_site, l)
}
- _ => {
- unreachable!()
+ MatchSite::Match(match_site) => {
+ let l = self.machine_st.heap[match_site].get_value();
+ self.machine_st.heap[match_site].set_value(h);
+
+ (match_site, l)
}
- );
+ };
+
+ self.machine_st.trail(TrailRef::AttrVarListLink(match_site, l));
+ }
+ None => {
+ // the list is empty.
+ self.machine_st.heap[attr_var_list] = list_loc_as_cell!(h+4);
+ self.machine_st.heap.push(heap_loc_as_cell!(h));
+ self.machine_st.heap.push(heap_loc_as_cell!(h+5));
- self.machine_st.heap[l1 + 1] = tail;
- self.machine_st.trail(trail_ref);
+ self.machine_st.attr_var_init.attr_var_queue.push(attr_var_list - 1);
+ self.machine_st.trail(TrailRef::AttrVarListLink(attr_var_list, attr_var_list));
}
}
}
- #[inline(always)]
- pub(crate) fn delete_head_attribute(&mut self) {
- let addr = self.deref_register(1);
+ fn match_attribute(
+ &self,
+ mut attrs_list: HeapCellValue,
+ module: HeapCellValue,
+ attr: HeapCellValue,
+ ) -> Option<AttrListMatch> {
+ let (name, arity) = match self.machine_st.name_and_arity_from_heap(attr) {
+ Some(key) => key,
+ None => {
+ return None;
+ }
+ };
- debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
+ let mut prev_tail = None;
- let h = addr.get_value();
- let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
+ while let HeapCellValueTag::Lis = attrs_list.get_tag() {
+ let mut list_head = self.machine_st.heap[attrs_list.get_value()];
- debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
+ loop {
+ read_heap_cell!(list_head,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ debug_assert!(list_head != self.machine_st.heap[h]);
+ list_head = self.machine_st.heap[h];
+ }
+ (HeapCellValueTag::Str | HeapCellValueTag::Atom) => {
+ let (module_loc, qualified_goal) = self.machine_st.strip_module(
+ list_head,
+ empty_list_as_cell!(),
+ );
- let l = addr.get_value();
- let tail = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l + 1]));
+ let (t_name, t_arity) = self.machine_st
+ .name_and_arity_from_heap(qualified_goal)
+ .unwrap();
- let tail = if tail.is_var() {
- self.machine_st.heap[h] = heap_loc_as_cell!(h);
- self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
+ if module == module_loc && name == t_name && arity == t_arity {
+ return Some(AttrListMatch {
+ match_site: MatchSite::Match(attrs_list.get_value()),
+ prev_tail,
+ });
+ }
- heap_loc_as_cell!(h + 1)
- } else {
- tail
- };
+ break;
+ }
+ _ => {
+ break;
+ }
+ );
+ }
+
+ let tail_loc = attrs_list.get_value() + 1;
+ prev_tail = Some(tail_loc);
+
+ // do the work of self.store(self.deref(...)) but inline it
+ // for speed and simplify it.
+ let mut list_tail = self.machine_st.heap[tail_loc];
+
+ loop {
+ read_heap_cell!(list_tail,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if list_tail != self.machine_st.heap[h] {
+ list_tail = self.machine_st.heap[h];
+ } else {
+ return Some(AttrListMatch {
+ match_site: MatchSite::NoMatchVarTail(h),
+ prev_tail,
+ });
+ }
+ }
+ (HeapCellValueTag::Lis) => {
+ attrs_list = list_tail;
+ break;
+ }
+ _ => {
+ unreachable!()
+ }
+ );
+ }
+ }
- self.machine_st.heap[h + 1] = tail;
- self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
+ None
}
#[inline(always)]