Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions crates/hir-ty/src/consteval/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,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(
Expand Down
1 change: 1 addition & 0 deletions crates/hir-ty/src/consteval/tests/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 36 additions & 3 deletions crates/hir-ty/src/mir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down Expand Up @@ -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"))?;
Expand Down Expand Up @@ -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(())
}
Expand Down
18 changes: 17 additions & 1 deletion crates/hir-ty/src/mir/eval/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}"),
}
Expand Down