Skip to content

Commit 403433a

Browse files
committed
Auto merge of rust-lang#15112 - HKalbasi:mir, r=HKalbasi
Support manual impl of fn traits in mir interpreter Increases passed tests from 48 to 49 :)
2 parents 3a4f9a1 + 99a4f2e commit 403433a

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

crates/hir-ty/src/consteval/tests.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,30 @@ fn closures() {
15501550
);
15511551
}
15521552

1553+
#[test]
1554+
fn manual_fn_trait_impl() {
1555+
check_number(
1556+
r#"
1557+
//- minicore: fn, copy
1558+
struct S(i32);
1559+
1560+
impl FnOnce<(i32, i32)> for S {
1561+
type Output = i32;
1562+
1563+
extern "rust-call" fn call_once(self, arg: (i32, i32)) -> i32 {
1564+
arg.0 + arg.1 + self.0
1565+
}
1566+
}
1567+
1568+
const GOAL: i32 = {
1569+
let s = S(1);
1570+
s(2, 3)
1571+
};
1572+
"#,
1573+
6,
1574+
);
1575+
}
1576+
15531577
#[test]
15541578
fn closure_and_impl_fn() {
15551579
check_number(

crates/hir-ty/src/consteval/tests/intrinsics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fn transmute() {
3232
fn const_eval_select() {
3333
check_number(
3434
r#"
35+
//- minicore: fn
3536
extern "rust-intrinsic" {
3637
pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
3738
where

crates/hir-ty/src/mir/eval.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,7 @@ impl Evaluator<'_> {
17991799
match def {
18001800
CallableDefId::FunctionId(def) => {
18011801
if let Some(_) = self.detect_fn_trait(def) {
1802-
self.exec_fn_trait(&args, destination, locals, span)?;
1802+
self.exec_fn_trait(def, args, generic_args, locals, destination, span)?;
18031803
return Ok(());
18041804
}
18051805
self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?;
@@ -1921,9 +1921,11 @@ impl Evaluator<'_> {
19211921

19221922
fn exec_fn_trait(
19231923
&mut self,
1924+
def: FunctionId,
19241925
args: &[IntervalAndTy],
1925-
destination: Interval,
1926+
generic_args: Substitution,
19261927
locals: &Locals<'_>,
1928+
destination: Interval,
19271929
span: MirSpan,
19281930
) -> Result<()> {
19291931
let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?;
@@ -1958,7 +1960,38 @@ impl Evaluator<'_> {
19581960
span,
19591961
)?;
19601962
}
1961-
x => not_supported!("Call FnTrait methods with type {x:?}"),
1963+
_ => {
1964+
// try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
1965+
let arg0 = func;
1966+
let args = &args[1..];
1967+
let arg1 = {
1968+
let ty = TyKind::Tuple(
1969+
args.len(),
1970+
Substitution::from_iter(Interner, args.iter().map(|x| x.ty.clone())),
1971+
)
1972+
.intern(Interner);
1973+
let layout = self.layout(&ty)?;
1974+
let result = self.make_by_layout(
1975+
layout.size.bytes_usize(),
1976+
&layout,
1977+
None,
1978+
args.iter().map(|x| IntervalOrOwned::Borrowed(x.interval)),
1979+
)?;
1980+
// FIXME: there is some leak here
1981+
let size = layout.size.bytes_usize();
1982+
let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize);
1983+
self.write_memory(addr, &result)?;
1984+
IntervalAndTy { interval: Interval { addr, size }, ty }
1985+
};
1986+
return self.exec_fn_with_args(
1987+
def,
1988+
&[arg0.clone(), arg1],
1989+
generic_args,
1990+
locals,
1991+
destination,
1992+
span,
1993+
);
1994+
}
19621995
}
19631996
Ok(())
19641997
}

crates/hir-ty/src/mir/eval/shim.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,23 @@ impl Evaluator<'_> {
681681
let addr = tuple.interval.addr.offset(offset);
682682
args.push(IntervalAndTy::new(addr, field, self, locals)?);
683683
}
684-
self.exec_fn_trait(&args, destination, locals, span)
684+
if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) {
685+
if let Some(def) = target
686+
.as_trait()
687+
.and_then(|x| self.db.trait_data(x).method_by_name(&name![call_once]))
688+
{
689+
return self.exec_fn_trait(
690+
def,
691+
&args,
692+
// FIXME: wrong for manual impls of `FnOnce`
693+
Substitution::empty(Interner),
694+
locals,
695+
destination,
696+
span,
697+
);
698+
}
699+
}
700+
not_supported!("FnOnce was not available for executing const_eval_select");
685701
}
686702
_ => not_supported!("unknown intrinsic {name}"),
687703
}

0 commit comments

Comments
 (0)