Support manual impl of fn traits in mir interpreter
This commit is contained in:
parent
3a4f9a1416
commit
99a4f2e983
@ -1550,6 +1550,30 @@ fn mult(&mut self, n: i32) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn manual_fn_trait_impl() {
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
//- minicore: fn, copy
|
||||||
|
struct S(i32);
|
||||||
|
|
||||||
|
impl FnOnce<(i32, i32)> for S {
|
||||||
|
type Output = i32;
|
||||||
|
|
||||||
|
extern "rust-call" fn call_once(self, arg: (i32, i32)) -> i32 {
|
||||||
|
arg.0 + arg.1 + self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const GOAL: i32 = {
|
||||||
|
let s = S(1);
|
||||||
|
s(2, 3)
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
6,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn closure_and_impl_fn() {
|
fn closure_and_impl_fn() {
|
||||||
check_number(
|
check_number(
|
||||||
|
@ -32,6 +32,7 @@ fn transmute() {
|
|||||||
fn const_eval_select() {
|
fn const_eval_select() {
|
||||||
check_number(
|
check_number(
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: fn
|
||||||
extern "rust-intrinsic" {
|
extern "rust-intrinsic" {
|
||||||
pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
|
pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
|
||||||
where
|
where
|
||||||
|
@ -1799,7 +1799,7 @@ fn exec_fn_def(
|
|||||||
match def {
|
match def {
|
||||||
CallableDefId::FunctionId(def) => {
|
CallableDefId::FunctionId(def) => {
|
||||||
if let Some(_) = self.detect_fn_trait(def) {
|
if let Some(_) = self.detect_fn_trait(def) {
|
||||||
self.exec_fn_trait(&args, destination, locals, span)?;
|
self.exec_fn_trait(def, args, generic_args, locals, destination, span)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?;
|
self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?;
|
||||||
@ -1921,9 +1921,11 @@ fn exec_looked_up_function(
|
|||||||
|
|
||||||
fn exec_fn_trait(
|
fn exec_fn_trait(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
def: FunctionId,
|
||||||
args: &[IntervalAndTy],
|
args: &[IntervalAndTy],
|
||||||
destination: Interval,
|
generic_args: Substitution,
|
||||||
locals: &Locals<'_>,
|
locals: &Locals<'_>,
|
||||||
|
destination: Interval,
|
||||||
span: MirSpan,
|
span: MirSpan,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?;
|
let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?;
|
||||||
@ -1958,7 +1960,38 @@ fn exec_fn_trait(
|
|||||||
span,
|
span,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
x => not_supported!("Call FnTrait methods with type {x:?}"),
|
_ => {
|
||||||
|
// try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
|
||||||
|
let arg0 = func;
|
||||||
|
let args = &args[1..];
|
||||||
|
let arg1 = {
|
||||||
|
let ty = TyKind::Tuple(
|
||||||
|
args.len(),
|
||||||
|
Substitution::from_iter(Interner, args.iter().map(|x| x.ty.clone())),
|
||||||
|
)
|
||||||
|
.intern(Interner);
|
||||||
|
let layout = self.layout(&ty)?;
|
||||||
|
let result = self.make_by_layout(
|
||||||
|
layout.size.bytes_usize(),
|
||||||
|
&layout,
|
||||||
|
None,
|
||||||
|
args.iter().map(|x| IntervalOrOwned::Borrowed(x.interval)),
|
||||||
|
)?;
|
||||||
|
// FIXME: there is some leak here
|
||||||
|
let size = layout.size.bytes_usize();
|
||||||
|
let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize);
|
||||||
|
self.write_memory(addr, &result)?;
|
||||||
|
IntervalAndTy { interval: Interval { addr, size }, ty }
|
||||||
|
};
|
||||||
|
return self.exec_fn_with_args(
|
||||||
|
def,
|
||||||
|
&[arg0.clone(), arg1],
|
||||||
|
generic_args,
|
||||||
|
locals,
|
||||||
|
destination,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -681,7 +681,23 @@ fn exec_intrinsic(
|
|||||||
let addr = tuple.interval.addr.offset(offset);
|
let addr = tuple.interval.addr.offset(offset);
|
||||||
args.push(IntervalAndTy::new(addr, field, self, locals)?);
|
args.push(IntervalAndTy::new(addr, field, self, locals)?);
|
||||||
}
|
}
|
||||||
self.exec_fn_trait(&args, destination, locals, span)
|
if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) {
|
||||||
|
if let Some(def) = target
|
||||||
|
.as_trait()
|
||||||
|
.and_then(|x| self.db.trait_data(x).method_by_name(&name![call_once]))
|
||||||
|
{
|
||||||
|
return self.exec_fn_trait(
|
||||||
|
def,
|
||||||
|
&args,
|
||||||
|
// FIXME: wrong for manual impls of `FnOnce`
|
||||||
|
Substitution::empty(Interner),
|
||||||
|
locals,
|
||||||
|
destination,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
not_supported!("FnOnce was not available for executing const_eval_select");
|
||||||
}
|
}
|
||||||
_ => not_supported!("unknown intrinsic {name}"),
|
_ => not_supported!("unknown intrinsic {name}"),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user