Skip to content

Commit 31c3093

Browse files
committed
Support closure in clone shim
1 parent b96e4f2 commit 31c3093

File tree

2 files changed

+73
-21
lines changed

2 files changed

+73
-21
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,30 @@ fn from_trait() {
14531453
);
14541454
}
14551455

1456+
#[test]
1457+
fn closure_clone() {
1458+
check_number(
1459+
r#"
1460+
//- minicore: clone, fn
1461+
struct S(u8);
1462+
1463+
impl Clone for S(u8) {
1464+
fn clone(&self) -> S {
1465+
S(self.0 + 5)
1466+
}
1467+
}
1468+
1469+
const GOAL: u8 = {
1470+
let s = S(3);
1471+
let cl = move || s;
1472+
let cl = cl.clone();
1473+
cl().0
1474+
}
1475+
"#,
1476+
8,
1477+
);
1478+
}
1479+
14561480
#[test]
14571481
fn builtin_derive_macro() {
14581482
check_number(

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

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ impl Evaluator<'_> {
136136
not_supported!("wrong generic arg kind for clone");
137137
};
138138
// Clone has special impls for tuples and function pointers
139-
if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
139+
if matches!(
140+
self_ty.kind(Interner),
141+
TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..)
142+
) {
140143
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
141144
return Ok(true);
142145
}
@@ -167,32 +170,26 @@ impl Evaluator<'_> {
167170
return destination
168171
.write_from_interval(self, Interval { addr, size: destination.size });
169172
}
173+
TyKind::Closure(id, subst) => {
174+
let [arg] = args else {
175+
not_supported!("wrong arg count for clone");
176+
};
177+
let addr = Address::from_bytes(arg.get(self)?)?;
178+
let (closure_owner, _) = self.db.lookup_intern_closure((*id).into());
179+
let infer = self.db.infer(closure_owner);
180+
let (captures, _) = infer.closure_info(id);
181+
let layout = self.layout(&self_ty)?;
182+
let ty_iter = captures.iter().map(|c| c.ty(subst));
183+
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
184+
}
170185
TyKind::Tuple(_, subst) => {
171186
let [arg] = args else {
172187
not_supported!("wrong arg count for clone");
173188
};
174189
let addr = Address::from_bytes(arg.get(self)?)?;
175190
let layout = self.layout(&self_ty)?;
176-
for (i, ty) in subst.iter(Interner).enumerate() {
177-
let ty = ty.assert_ty_ref(Interner);
178-
let size = self.layout(ty)?.size.bytes_usize();
179-
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
180-
let arg = IntervalAndTy {
181-
interval: Interval { addr: tmp, size: self.ptr_size() },
182-
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
183-
.intern(Interner),
184-
};
185-
let offset = layout.fields.offset(i).bytes_usize();
186-
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
187-
self.exec_clone(
188-
def,
189-
&[arg],
190-
ty.clone(),
191-
locals,
192-
destination.slice(offset..offset + size),
193-
span,
194-
)?;
195-
}
191+
let ty_iter = subst.iter(Interner).map(|ga| ga.assert_ty_ref(Interner).clone());
192+
self.exec_clone_for_fields(ty_iter, layout, addr, def, locals, destination, span)?;
196193
}
197194
_ => {
198195
self.exec_fn_with_args(
@@ -209,6 +206,37 @@ impl Evaluator<'_> {
209206
Ok(())
210207
}
211208

209+
fn exec_clone_for_fields(
210+
&mut self,
211+
ty_iter: impl Iterator<Item = Ty>,
212+
layout: Arc<Layout>,
213+
addr: Address,
214+
def: FunctionId,
215+
locals: &Locals,
216+
destination: Interval,
217+
span: MirSpan,
218+
) -> Result<()> {
219+
for (i, ty) in ty_iter.enumerate() {
220+
let size = self.layout(&ty)?.size.bytes_usize();
221+
let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
222+
let arg = IntervalAndTy {
223+
interval: Interval { addr: tmp, size: self.ptr_size() },
224+
ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone()).intern(Interner),
225+
};
226+
let offset = layout.fields.offset(i).bytes_usize();
227+
self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
228+
self.exec_clone(
229+
def,
230+
&[arg],
231+
ty,
232+
locals,
233+
destination.slice(offset..offset + size),
234+
span,
235+
)?;
236+
}
237+
Ok(())
238+
}
239+
212240
fn exec_alloc_fn(
213241
&mut self,
214242
alloc_fn: &str,

0 commit comments

Comments
 (0)