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]
|
#[test]
|
||||||
fn builtin_derive_macro() {
|
fn builtin_derive_macro() {
|
||||||
check_number(
|
check_number(
|
||||||
|
@ -136,7 +136,10 @@ pub(super) fn detect_and_exec_special_function(
|
|||||||
not_supported!("wrong generic arg kind for clone");
|
not_supported!("wrong generic arg kind for clone");
|
||||||
};
|
};
|
||||||
// Clone has special impls for tuples and function pointers
|
// 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)?;
|
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -167,32 +170,26 @@ fn exec_clone(
|
|||||||
return destination
|
return destination
|
||||||
.write_from_interval(self, Interval { addr, size: destination.size });
|
.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) => {
|
TyKind::Tuple(_, subst) => {
|
||||||
let [arg] = args else {
|
let [arg] = args else {
|
||||||
not_supported!("wrong arg count for clone");
|
not_supported!("wrong arg count for clone");
|
||||||
};
|
};
|
||||||
let addr = Address::from_bytes(arg.get(self)?)?;
|
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||||
let layout = self.layout(&self_ty)?;
|
let layout = self.layout(&self_ty)?;
|
||||||
for (i, ty) in subst.iter(Interner).enumerate() {
|
let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
|
||||||
let ty = ty.assert_ty_ref(Interner);
|
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
|
||||||
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,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.exec_fn_with_args(
|
self.exec_fn_with_args(
|
||||||
@ -209,6 +206,37 @@ fn exec_clone(
|
|||||||
Ok(())
|
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(
|
fn exec_alloc_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
alloc_fn: &str,
|
alloc_fn: &str,
|
||||||
|
Loading…
Reference in New Issue
Block a user