about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-07-28 18:52:01 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-07-28 18:52:01 +0330
commitbd2a8ca507daddca13bb30e2ba93a02e238801cf (patch)
tree37c47a388d59b2ccfa6af287a5b11b28e07ace60
parent17cc813e92e4770f91f9f1e03e3ceffd2fb6c0b3 (diff)
downloadrust-bd2a8ca507daddca13bb30e2ba93a02e238801cf.tar.gz
rust-bd2a8ca507daddca13bb30e2ba93a02e238801cf.zip
Add manual implementation of clone for tuples in mir interpreter
-rw-r--r--crates/hir-ty/src/consteval/tests.rs34
-rw-r--r--crates/hir-ty/src/layout.rs24
-rw-r--r--crates/hir-ty/src/mir/eval.rs13
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs76
4 files changed, 138 insertions, 9 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 3d73a55a351..43792994988 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1428,14 +1428,14 @@ fn builtin_derive_macro() {
     #[derive(Clone)]
     struct Y {
         field1: i32,
-        field2: u8,
+        field2: ((i32, u8), i64),
     }
 
     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 Z::Foo(t) = x.1;
-        t.field2
+        t.field2.0 .1
     };
     "#,
         5,
@@ -1633,6 +1633,34 @@ const GOAL: 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]
 fn closure_and_impl_fn() {
     check_number(
         r#"
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index ffc7a6f2ebd..b15339d4434 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -14,7 +14,7 @@ use triomphe::Arc;
 
 use crate::{
     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::{
@@ -279,7 +279,15 @@ pub fn layout_of_ty_query(
             //     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) {
                 TyKind::Slice(_) | TyKind::Str => {
                     scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
@@ -362,8 +370,16 @@ pub fn layout_of_ty_query(
             return Err(LayoutError::NotImplemented)
         }
         TyKind::Error => return Err(LayoutError::HasErrorType),
-        TyKind::AssociatedType(_, _)
-        | TyKind::Alias(_)
+        TyKind::AssociatedType(id, subst) => {
+            // 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::BoundVar(_)
         | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index be66464864f..2d5d7c7b1f7 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -313,6 +313,7 @@ pub enum MirEvalError {
     InvalidVTableId(usize),
     CoerceUnsizedError(Ty),
     LangItemNotFound(LangItem),
+    BrokenLayout(Layout),
 }
 
 impl MirEvalError {
@@ -399,6 +400,7 @@ impl MirEvalError {
             | MirEvalError::TargetDataLayoutNotAvailable
             | MirEvalError::CoerceUnsizedError(_)
             | MirEvalError::LangItemNotFound(_)
+            | MirEvalError::BrokenLayout(_)
             | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
         }
         Ok(())
@@ -433,6 +435,7 @@ impl std::fmt::Debug for MirEvalError {
             Self::CoerceUnsizedError(arg0) => {
                 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::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
             Self::InvalidConst(arg0) => {
@@ -1541,12 +1544,18 @@ impl Evaluator<'_> {
     ) -> Result<Vec<u8>> {
         let mut result = vec![0; size];
         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() {
             let offset = variant_layout.fields.offset(i).bytes_usize();
             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)
     }
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index d21b05c6120..356bf70a5fb 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -124,9 +124,85 @@ impl Evaluator<'_> {
             destination.write_from_bytes(self, &result)?;
             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)
     }
 
+    /// 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(
         &mut self,
         alloc_fn: &str,