Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15112 - HKalbasi:mir, r=HKalbasi
Support manual impl of fn traits in mir interpreter Increases passed tests from 48 to 49 :)
bors 2023-06-23
parent 3a4f9a1 · parent 99a4f2e · commit 403433a
-rw-r--r--crates/hir-ty/src/consteval/tests.rs24
-rw-r--r--crates/hir-ty/src/consteval/tests/intrinsics.rs1
-rw-r--r--crates/hir-ty/src/mir/eval.rs39
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs18
4 files changed, 78 insertions, 4 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 1e241500c2..b487d7d049 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1551,6 +1551,30 @@ fn closures() {
}
#[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]
fn closure_and_impl_fn() {
check_number(
r#"
diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs
index e05d824dba..24a463d714 100644
--- a/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -32,6 +32,7 @@ fn transmute() {
fn const_eval_select() {
check_number(
r#"
+ //- minicore: fn
extern "rust-intrinsic" {
pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
where
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 28b6066c19..0c7669cd54 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1799,7 +1799,7 @@ impl Evaluator<'_> {
match def {
CallableDefId::FunctionId(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(());
}
self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?;
@@ -1921,9 +1921,11 @@ impl Evaluator<'_> {
fn exec_fn_trait(
&mut self,
+ def: FunctionId,
args: &[IntervalAndTy],
- destination: Interval,
+ generic_args: Substitution,
locals: &Locals<'_>,
+ destination: Interval,
span: MirSpan,
) -> Result<()> {
let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?;
@@ -1958,7 +1960,38 @@ impl Evaluator<'_> {
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(())
}
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 3b9ef03c36..3ed26d0e9b 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -681,7 +681,23 @@ impl Evaluator<'_> {
let addr = tuple.interval.addr.offset(offset);
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}"),
}