Support closure in clone shim
This commit is contained in:
parent
b96e4f2f4a
commit
31c30933cf
@ -1453,6 +1453,30 @@ fn from(E1(x): E1) -> Self {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closure_clone() {
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: clone, fn
|
||||
struct S(u8);
|
||||
|
||||
impl Clone for S(u8) {
|
||||
fn clone(&self) -> S {
|
||||
S(self.0 + 5)
|
||||
}
|
||||
}
|
||||
|
||||
const GOAL: u8 = {
|
||||
let s = S(3);
|
||||
let cl = move || s;
|
||||
let cl = cl.clone();
|
||||
cl().0
|
||||
}
|
||||
"#,
|
||||
8,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_derive_macro() {
|
||||
check_number(
|
||||
|
@ -136,7 +136,10 @@ pub(super) fn detect_and_exec_special_function(
|
||||
not_supported!("wrong generic arg kind for clone");
|
||||
};
|
||||
// Clone has special impls for tuples and function pointers
|
||||
if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
|
||||
if matches!(
|
||||
self_ty.kind(Interner),
|
||||
TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
|
||||
) {
|
||||
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||
return Ok(true);
|
||||
}
|
||||
@ -167,32 +170,26 @@ fn exec_clone(
|
||||
return destination
|
||||
.write_from_interval(self, Interval { addr, size: destination.size });
|
||||
}
|
||||
TyKind::Closure(id, subst) => {
|
||||
let [arg] = args else {
|
||||
not_supported!("wrong arg count for clone");
|
||||
};
|
||||
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||
let (closure_owner, _) = self.db.lookup_intern_closure((*id).into());
|
||||
let infer = self.db.infer(closure_owner);
|
||||
let (captures, _) = infer.closure_info(id);
|
||||
let layout = self.layout(&self_ty)?;
|
||||
let ty_iter = captures.iter().map(|c| c.ty(subst));
|
||||
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
|
||||
}
|
||||
TyKind::Tuple(_, subst) => {
|
||||
let [arg] = args else {
|
||||
not_supported!("wrong arg count for clone");
|
||||
};
|
||||
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||
let layout = self.layout(&self_ty)?;
|
||||
for (i, ty) in subst.iter(Interner).enumerate() {
|
||||
let ty = ty.assert_ty_ref(Interner);
|
||||
let size = self.layout(ty)?.size.bytes_usize();
|
||||
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
|
||||
let arg = IntervalAndTy {
|
||||
interval: Interval { addr: tmp, size: self.ptr_size() },
|
||||
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
|
||||
.intern(Interner),
|
||||
};
|
||||
let offset = layout.fields.offset(i).bytes_usize();
|
||||
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
|
||||
self.exec_clone(
|
||||
def,
|
||||
&[arg],
|
||||
ty.clone(),
|
||||
locals,
|
||||
destination.slice(offset..offset + size),
|
||||
span,
|
||||
)?;
|
||||
}
|
||||
let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
|
||||
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
|
||||
}
|
||||
_ => {
|
||||
self.exec_fn_with_args(
|
||||
@ -209,6 +206,37 @@ fn exec_clone(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exec_clone_for_fields(
|
||||
&mut self,
|
||||
ty_iter: impl Iterator<Item = Ty>,
|
||||
layout: Arc<Layout>,
|
||||
addr: Address,
|
||||
def: FunctionId,
|
||||
locals: &Locals,
|
||||
destination: Interval,
|
||||
span: MirSpan,
|
||||
) -> Result<()> {
|
||||
for (i, ty) in ty_iter.enumerate() {
|
||||
let size = self.layout(&ty)?.size.bytes_usize();
|
||||
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
|
||||
let arg = IntervalAndTy {
|
||||
interval: Interval { addr: tmp, size: self.ptr_size() },
|
||||
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone()).intern(Interner),
|
||||
};
|
||||
let offset = layout.fields.offset(i).bytes_usize();
|
||||
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
|
||||
self.exec_clone(
|
||||
def,
|
||||
&[arg],
|
||||
ty,
|
||||
locals,
|
||||
destination.slice(offset..offset + size),
|
||||
span,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exec_alloc_fn(
|
||||
&mut self,
|
||||
alloc_fn: &str,
|
||||
|
Loading…
Reference in New Issue
Block a user