Add manual implementation of clone for tuples in mir interpreter
This commit is contained in:
parent
17cc813e92
commit
bd2a8ca507
@ -1428,14 +1428,14 @@ struct X(i32, Z, i64)
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Y {
|
struct Y {
|
||||||
field1: i32,
|
field1: i32,
|
||||||
field2: u8,
|
field2: ((i32, u8), i64),
|
||||||
}
|
}
|
||||||
|
|
||||||
const GOAL: u8 = {
|
const GOAL: u8 = {
|
||||||
let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8);
|
let x = X(2, Z::Foo(Y { field1: 4, field2: ((32, 5), 12) }), 8);
|
||||||
let x = x.clone();
|
let x = x.clone();
|
||||||
let Z::Foo(t) = x.1;
|
let Z::Foo(t) = x.1;
|
||||||
t.field2
|
t.field2.0 .1
|
||||||
};
|
};
|
||||||
"#,
|
"#,
|
||||||
5,
|
5,
|
||||||
@ -1632,6 +1632,34 @@ extern "rust-call" fn call_once(self, arg: (i32, i32)) -> i32 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closure_capture_unsized_type() {
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
//- minicore: fn, copy, slice, index, coerce_unsized
|
||||||
|
fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty {
|
||||||
|
let c = || &*x;
|
||||||
|
c()
|
||||||
|
}
|
||||||
|
|
||||||
|
trait A {
|
||||||
|
type Ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A for i32 {
|
||||||
|
type Ty = [u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
const GOAL: u8 = {
|
||||||
|
let k: &[u8] = &[1, 2, 3];
|
||||||
|
let k = f::<i32>(k);
|
||||||
|
k[0] + k[1] + k[2]
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
6,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn closure_and_impl_fn() {
|
fn closure_and_impl_fn() {
|
||||||
check_number(
|
check_number(
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
|
consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
|
||||||
utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty,
|
utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
@ -279,7 +279,15 @@ pub fn layout_of_ty_query(
|
|||||||
// return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
|
// return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
|
let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
|
||||||
|
if let TyKind::AssociatedType(id, subst) = unsized_part.kind(Interner) {
|
||||||
|
unsized_part = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
|
||||||
|
associated_ty_id: *id,
|
||||||
|
substitution: subst.clone(),
|
||||||
|
}))
|
||||||
|
.intern(Interner);
|
||||||
|
}
|
||||||
|
unsized_part = normalize(db, trait_env.clone(), unsized_part);
|
||||||
let metadata = match unsized_part.kind(Interner) {
|
let metadata = match unsized_part.kind(Interner) {
|
||||||
TyKind::Slice(_) | TyKind::Str => {
|
TyKind::Slice(_) | TyKind::Str => {
|
||||||
scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
|
scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
|
||||||
@ -362,8 +370,16 @@ pub fn layout_of_ty_query(
|
|||||||
return Err(LayoutError::NotImplemented)
|
return Err(LayoutError::NotImplemented)
|
||||||
}
|
}
|
||||||
TyKind::Error => return Err(LayoutError::HasErrorType),
|
TyKind::Error => return Err(LayoutError::HasErrorType),
|
||||||
TyKind::AssociatedType(_, _)
|
TyKind::AssociatedType(id, subst) => {
|
||||||
| TyKind::Alias(_)
|
// Try again with `TyKind::Alias` to normalize the associated type.
|
||||||
|
let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
|
||||||
|
associated_ty_id: *id,
|
||||||
|
substitution: subst.clone(),
|
||||||
|
}))
|
||||||
|
.intern(Interner);
|
||||||
|
return db.layout_of_ty(ty, trait_env);
|
||||||
|
}
|
||||||
|
TyKind::Alias(_)
|
||||||
| TyKind::Placeholder(_)
|
| TyKind::Placeholder(_)
|
||||||
| TyKind::BoundVar(_)
|
| TyKind::BoundVar(_)
|
||||||
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
|
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
|
||||||
|
@ -313,6 +313,7 @@ pub enum MirEvalError {
|
|||||||
InvalidVTableId(usize),
|
InvalidVTableId(usize),
|
||||||
CoerceUnsizedError(Ty),
|
CoerceUnsizedError(Ty),
|
||||||
LangItemNotFound(LangItem),
|
LangItemNotFound(LangItem),
|
||||||
|
BrokenLayout(Layout),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirEvalError {
|
impl MirEvalError {
|
||||||
@ -399,6 +400,7 @@ pub fn pretty_print(
|
|||||||
| MirEvalError::TargetDataLayoutNotAvailable
|
| MirEvalError::TargetDataLayoutNotAvailable
|
||||||
| MirEvalError::CoerceUnsizedError(_)
|
| MirEvalError::CoerceUnsizedError(_)
|
||||||
| MirEvalError::LangItemNotFound(_)
|
| MirEvalError::LangItemNotFound(_)
|
||||||
|
| MirEvalError::BrokenLayout(_)
|
||||||
| MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
|
| MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -433,6 +435,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|||||||
Self::CoerceUnsizedError(arg0) => {
|
Self::CoerceUnsizedError(arg0) => {
|
||||||
f.debug_tuple("CoerceUnsizedError").field(arg0).finish()
|
f.debug_tuple("CoerceUnsizedError").field(arg0).finish()
|
||||||
}
|
}
|
||||||
|
Self::BrokenLayout(arg0) => f.debug_tuple("BrokenLayout").field(arg0).finish(),
|
||||||
Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),
|
Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),
|
||||||
Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
|
Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
|
||||||
Self::InvalidConst(arg0) => {
|
Self::InvalidConst(arg0) => {
|
||||||
@ -1541,12 +1544,18 @@ fn make_by_layout(
|
|||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
let mut result = vec![0; size];
|
let mut result = vec![0; size];
|
||||||
if let Some((offset, size, value)) = tag {
|
if let Some((offset, size, value)) = tag {
|
||||||
result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]);
|
match result.get_mut(offset..offset + size) {
|
||||||
|
Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
|
||||||
|
None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (i, op) in values.enumerate() {
|
for (i, op) in values.enumerate() {
|
||||||
let offset = variant_layout.fields.offset(i).bytes_usize();
|
let offset = variant_layout.fields.offset(i).bytes_usize();
|
||||||
let op = op.get(&self)?;
|
let op = op.get(&self)?;
|
||||||
result[offset..offset + op.len()].copy_from_slice(op);
|
match result.get_mut(offset..offset + op.len()) {
|
||||||
|
Some(it) => it.copy_from_slice(op),
|
||||||
|
None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -124,9 +124,85 @@ pub(super) fn detect_and_exec_special_function(
|
|||||||
destination.write_from_bytes(self, &result)?;
|
destination.write_from_bytes(self, &result)?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container {
|
||||||
|
if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
|
||||||
|
let [self_ty] = generic_args.as_slice(Interner) else {
|
||||||
|
not_supported!("wrong generic arg count for clone");
|
||||||
|
};
|
||||||
|
let Some(self_ty) = self_ty.ty(Interner) else {
|
||||||
|
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(..)) {
|
||||||
|
self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clone has special impls for tuples and function pointers
|
||||||
|
fn exec_clone(
|
||||||
|
&mut self,
|
||||||
|
def: FunctionId,
|
||||||
|
args: &[IntervalAndTy],
|
||||||
|
self_ty: Ty,
|
||||||
|
locals: &Locals,
|
||||||
|
destination: Interval,
|
||||||
|
span: MirSpan,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self_ty.kind(Interner) {
|
||||||
|
TyKind::Function(_) => {
|
||||||
|
let [arg] = args else {
|
||||||
|
not_supported!("wrong arg count for clone");
|
||||||
|
};
|
||||||
|
let addr = Address::from_bytes(arg.get(self)?)?;
|
||||||
|
return destination
|
||||||
|
.write_from_interval(self, Interval { addr, size: destination.size });
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.exec_fn_with_args(
|
||||||
|
def,
|
||||||
|
args,
|
||||||
|
Substitution::from1(Interner, self_ty),
|
||||||
|
locals,
|
||||||
|
destination,
|
||||||
|
None,
|
||||||
|
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