refine is/2 compilation so errors are thrown when expected without needlessly allocating (#1974, #1984)

This commit is contained in:
Mark
2023-08-29 16:42:23 -06:00
parent 53a1be78cc
commit 66f6399b8a
3 changed files with 69 additions and 12 deletions

View File

@@ -99,6 +99,8 @@ enum BuiltInClauseType {
Ground, Ground,
#[strum_discriminants(strum(props(Arity = "2", Name = "is")))] #[strum_discriminants(strum(props(Arity = "2", Name = "is")))]
Is(RegType, ArithmeticTerm), Is(RegType, ArithmeticTerm),
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_number")))]
GetNumber(ArithmeticTerm),
#[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))] #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))]
KeySort, KeySort,
#[strum_discriminants(strum(props(Arity = "2", Name = "sort")))] #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))]
@@ -1553,7 +1555,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallFunctor | &Instruction::CallFunctor |
&Instruction::CallGround | &Instruction::CallGround |
&Instruction::CallKeySort | &Instruction::CallKeySort |
&Instruction::CallSort => { &Instruction::CallSort |
&Instruction::CallGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)]) functor!(atom!("call"), [atom(name), fixnum(arity)])
} }
@@ -1578,7 +1581,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteGround | &Instruction::ExecuteGround |
&Instruction::ExecuteIs(..) | &Instruction::ExecuteIs(..) |
&Instruction::ExecuteKeySort | &Instruction::ExecuteKeySort |
&Instruction::ExecuteSort => { &Instruction::ExecuteSort |
&Instruction::ExecuteGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)]) functor!(atom!("execute"), [atom(name), fixnum(arity)])
} }
@@ -1603,7 +1607,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultCallGround | &Instruction::DefaultCallGround |
&Instruction::DefaultCallIs(..) | &Instruction::DefaultCallIs(..) |
&Instruction::DefaultCallKeySort | &Instruction::DefaultCallKeySort |
&Instruction::DefaultCallSort => { &Instruction::DefaultCallSort |
&Instruction::DefaultCallGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("call_default"), [atom(name), fixnum(arity)]) functor!(atom!("call_default"), [atom(name), fixnum(arity)])
} }
@@ -1628,7 +1633,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultExecuteGround | &Instruction::DefaultExecuteGround |
&Instruction::DefaultExecuteIs(..) | &Instruction::DefaultExecuteIs(..) |
&Instruction::DefaultExecuteKeySort | &Instruction::DefaultExecuteKeySort |
&Instruction::DefaultExecuteSort => { &Instruction::DefaultExecuteSort |
&Instruction::DefaultExecuteGetNumber(_) => {
let (name, arity) = self.to_name_and_arity(); let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
} }

View File

@@ -814,19 +814,34 @@ impl<'b> CodeGenerator<'b> {
); );
self.marker.mark_safe_var_unconditionally(var_num); self.marker.mark_safe_var_unconditionally(var_num);
compile_expr!(self, &terms[1], term_loc, code)
} else { } else {
if self.marker.in_tail_position { if let Term::Var(ref vr, ref var) = &terms[1] {
if self.marker.var_data.allocates { let var_num = var.to_var_num().unwrap();
code.push_back(instr!("deallocate"));
}
code.push_back(instr!("proceed")); // if var is an anonymous variable, insert
// is/2 call so that an instantiation error is
// thrown when the predicate is run.
if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker.mark_var::<QueryInstruction>(
var_num,
Level::Shallow,
vr,
term_loc,
code,
);
self.marker.mark_safe_var_unconditionally(var_num);
let at = ArithmeticTerm::Reg(vr.get().norm());
self.add_call(code, instr!("$get_number", at), call_policy);
return Ok(());
}
} }
return Ok(()); compile_expr!(self, &terms[1], term_loc, code)
} }
compile_expr!(self, &terms[1], term_loc, code)
} }
&Term::Literal(_, c @ Literal::Integer(_) | &Term::Literal(_, c @ Literal::Integer(_) |
c @ Literal::Float(_) | c @ Literal::Float(_) |

View File

@@ -1497,6 +1497,14 @@ impl Machine {
try_or_throw!(self.machine_st, self.machine_st.is(r, at)); try_or_throw!(self.machine_st, self.machine_st.is(r, at));
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
Instruction::DefaultCallGetNumber(at) => {
try_or_throw!(self.machine_st, self.machine_st.get_number(at));
step_or_fail!(self, self.machine_st.p += 1);
}
Instruction::DefaultExecuteGetNumber(at) => {
try_or_throw!(self.machine_st, self.machine_st.get_number(at));
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallAcyclicTerm => { &Instruction::CallAcyclicTerm => {
let addr = self.machine_st.registers[1]; let addr = self.machine_st.registers[1];
@@ -1965,6 +1973,34 @@ impl Machine {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
} }
Instruction::CallGetNumber(at) => {
try_or_throw!(self.machine_st, self.machine_st.get_number(at));
if self.machine_st.fail {
self.machine_st.backtrack();
} else {
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
self.machine_st.p += 1;
}
}
Instruction::ExecuteGetNumber(at) => {
try_or_throw!(self.machine_st, self.machine_st.get_number(at));
if self.machine_st.fail {
self.machine_st.backtrack();
} else {
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
self.machine_st.p = self.machine_st.cp;
}
}
&Instruction::CallN(arity) => { &Instruction::CallN(arity) => {
let pred = self.machine_st.registers[1]; let pred = self.machine_st.registers[1];