Repository: rust-lang/rust-analyzer
Pull request #15140 (2023-06-26 08:06:35)

Add the comment why `HasSource::source()` returns `Option`
Fix https://github.com/rust-lang/rust-analyzer/issues/15088


Patch:
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 01295a9fc3..78961e1982 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1263,81 +1263,50 @@ impl Evaluator<'_> {
         current_ty: &Ty,
         target_ty: &Ty,
     ) -> Result<IntervalOrOwned> {
+        use IntervalOrOwned::*;
         fn for_ptr(x: &TyKind) -> Option<Ty> {
             match x {
                 TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => Some(ty.clone()),
                 _ => None,
             }
         }
-        let target_ty = self.coerce_unsized_look_through_fields(target_ty, for_ptr)?;
-        let current_ty = self.coerce_unsized_look_through_fields(current_ty, for_ptr)?;
-
-        self.unsizing_ptr_from_addr(target_ty, current_ty, addr)
-    }
-
-    /// Adds metadata to the address and create the fat pointer result of the unsizing operation.
-    fn unsizing_ptr_from_addr(
-        &mut self,
-        target_ty: Ty,
-        current_ty: Ty,
-        addr: Interval,
-    ) -> Result<IntervalOrOwned> {
-        use IntervalOrOwned::*;
-        Ok(match &target_ty.data(Interner).kind {
-            TyKind::Slice(_) => match &current_ty.data(Interner).kind {
-                TyKind::Array(_, size) => {
-                    let len = match try_const_usize(self.db, size) {
-                        None => {
-                            not_supported!("unevaluatble len of array in coerce unsized")
-                        }
-                        Some(x) => x as usize,
-                    };
-                    let mut r = Vec::with_capacity(16);
-                    let addr = addr.get(self)?;
-                    r.extend(addr.iter().copied());
-                    r.extend(len.to_le_bytes().into_iter());
-                    Owned(r)
-                }
-                t => {
-                    not_supported!("slice unsizing from non array type {t:?}")
-                }
-            },
-            TyKind::Dyn(_) => {
-                let vtable = self.vtable_map.id(current_ty.clone());
-                let mut r = Vec::with_capacity(16);
-                let addr = addr.get(self)?;
-                r.extend(addr.iter().copied());
-                r.extend(vtable.to_le_bytes().into_iter());
-                Owned(r)
-            }
-            TyKind::Adt(id, target_subst) => match &current_ty.data(Interner).kind {
-                TyKind::Adt(current_id, current_subst) => {
-                    if id != current_id {
-                        not_supported!("unsizing struct with different type");
+        Ok(match self.coerce_unsized_look_through_fields(target_ty, for_ptr)? {
+            ty => match &ty.data(Interner).kind {
+                TyKind::Slice(_) => {
+                    match self.coerce_unsized_look_through_fields(current_ty, for_ptr)? {
+                        ty => match &ty.data(Interner).kind {
+                            TyKind::Array(_, size) => {
+                                let len = match try_const_usize(self.db, size) {
+                                    None => not_supported!(
+                                        "unevaluatble len of array in coerce unsized"
+                                    ),
+                                    Some(x) => x as usize,
+                                };
+                                let mut r = Vec::with_capacity(16);
+                                let addr = addr.get(self)?;
+                                r.extend(addr.iter().copied());
+                                r.extend(len.to_le_bytes().into_iter());
+                                Owned(r)
+                            }
+                            t => {
+                                not_supported!("slice unsizing from non array type {t:?}")
+                            }
+                        },
                     }
-                    let id = match id.0 {
-                        AdtId::StructId(s) => s,
-                        AdtId::UnionId(_) => not_supported!("unsizing unions"),
-                        AdtId::EnumId(_) => not_supported!("unsizing enums"),
-                    };
-                    let Some((last_field, _)) = self.db.struct_data(id).variant_data.fields().iter().rev().next() else {
-                        not_supported!("unsizing struct without field");
-                    };
-                    let target_last_field = self.db.field_types(id.into())[last_field]
-                        .clone()
-                        .substitute(Interner, target_subst);
-                    let current_last_field = self.db.field_types(id.into())[last_field]
-                        .clone()
-                        .substitute(Interner, current_subst);
-                    return self.unsizing_ptr_from_addr(
-                        target_last_field,
-                        current_last_field,
-                        addr,
-                    );
                 }
-                _ => not_supported!("unsizing struct with non adt type"),
+                TyKind::Dyn(_) => match &current_ty.data(Interner).kind {
+                    TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => {
+                        let vtable = self.vtable_map.id(ty.clone());
+                        let mut r = Vec::with_capacity(16);
+                        let addr = addr.get(self)?;
+                        r.extend(addr.iter().copied());
+                        r.extend(vtable.to_le_bytes().into_iter());
+                        Owned(r)
+                    }
+                    _ => not_supported!("dyn unsizing from non pointers"),
+                },
+                _ => not_supported!("unknown unsized cast"),
             },
-            _ => not_supported!("unknown unsized cast"),
         })
     }
 
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 800e490e9a..2cb29b4ab9 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1742,17 +1742,17 @@ fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> {
         (TyKind::Raw(_, a) | TyKind::Ref(_, _, a), TyKind::Raw(_, b) | TyKind::Ref(_, _, b)) => {
             CastKind::Pointer(if a == b {
                 PointerCast::MutToConstPointer
-            } else if matches!(b.kind(Interner), TyKind::Slice(_))
-                && matches!(a.kind(Interner), TyKind::Array(_, _))
-                || matches!(b.kind(Interner), TyKind::Dyn(_))
+            } else if matches!(a.kind(Interner), TyKind::Slice(_) | TyKind::Str)
+                && matches!(b.kind(Interner), TyKind::Slice(_) | TyKind::Str)
             {
+                // slice to slice cast is no-op (metadata is not touched), so we use this
+                PointerCast::MutToConstPointer
+            } else if matches!(b.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) {
                 PointerCast::Unsize
             } else if matches!(a.kind(Interner), TyKind::Slice(s) if s == b) {
                 PointerCast::ArrayToPointer
             } else {
-                // cast between two sized pointer, like *const i32 to *const i8, or two unsized pointer, like
-                // slice to slice, slice to str, ... . These are no-ops (even in the unsized case, no metadata
-                // will be touched) but there is no specific variant
+                // cast between two sized pointer, like *const i32 to *const i8. There is no specific variant
                 // for it in `PointerCast` so we use `MutToConstPointer`
                 PointerCast::MutToConstPointer
             })
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 63d11155c6..b46a3856d4 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -21,6 +21,10 @@ pub trait HasSource {
     /// Fetches the definition's source node.
     /// Using [`crate::Semantics::source`] is preferred when working with [`crate::Semantics`],
     /// as that caches the parsed file in the semantics' cache.
+    ///
+    /// The current some implementations can return `InFile` instead of `Option<InFile>`.
+    /// But we made this method `Option` to support rlib in the future
+    /// by https://github.com/rust-lang/rust-analyzer/issues/6913
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
 }
 


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index de3a947f35..b487d7d049 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -166,21 +166,14 @@ fn casts() {
     check_number(
         r#"
     //- minicore: coerce_unsized, index, slice
-    struct X {
-        unsize_field: [u8],
-    }
-
     const GOAL: usize = {
         let a = [10, 20, 3, 15];
         let x: &[i32] = &a;
-        let x: *const [i32] = x;
-        let x = x as *const [u8]; // slice fat pointer cast don't touch metadata
-        let x = x as *const str;
-        let x = x as *const X;
-        let x = x as *const [i16];
-        let x = x as *const X;
-        let x = x as *const [u8];
-        let w = unsafe { &*x };
+        let y: *const [i32] = x;
+        let z = y as *const [u8]; // slice fat pointer cast don't touch metadata
+        let q = z as *const str;
+        let p = q as *const [u8];
+        let w = unsafe { &*z };
         w.len()
     };
         "#,
@@ -1880,38 +1873,6 @@ fn dyn_trait() {
     );
 }
 
-#[test]
-fn coerce_unsized() {
-    check_number(
-        r#"
-//- minicore: coerce_unsized, deref_mut, slice, index, transmute, non_null
-use core::ops::{Deref, DerefMut, CoerceUnsized};
-use core::{marker::Unsize, mem::transmute, ptr::NonNull};
-
-struct ArcInner<T: ?Sized> {
-    strong: usize,
-    weak: usize,
-    data: T,
-}
-
-pub struct Arc<T: ?Sized> {
-    inner: NonNull<ArcInner<T>>,
-}
-
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
-
-const GOAL: usize = {
-    let x = transmute::<usize, Arc<[i32; 3]>>(12);
-    let y: Arc<[i32]> = x;
-    let z = transmute::<Arc<[i32]>, (usize, usize)>(y);
-    z.1
-};
-
-        "#,
-        3,
-    );
-}
-
 #[test]
 fn boxes() {
     check_number(
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index b75f213df2..0ff8c532d4 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -369,11 +369,11 @@ fn tuple() {
 }
 
 #[test]
-fn non_zero_and_non_null() {
+fn non_zero() {
     size_and_align! {
-        minicore: non_zero, non_null, option;
-        use core::{num::NonZeroU8, ptr::NonNull};
-        struct Goal(Option<NonZeroU8>, Option<NonNull<i32>>);
+        minicore: non_zero, option;
+        use core::num::NonZeroU8;
+        struct Goal(Option<NonZeroU8>);
     }
 }
 
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index d7201f996d..0d6e4b98d8 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -37,7 +37,6 @@
 //!     iterator: option
 //!     iterators: iterator, fn
 //!     manually_drop: drop
-//!     non_null:
 //!     non_zero:
 //!     option: panic
 //!     ord: eq, option
@@ -387,19 +386,6 @@ pub mod ptr {
         type Metadata;
     }
     // endregion:pointee
-    // region:non_null
-    #[rustc_layout_scalar_valid_range_start(1)]
-    #[rustc_nonnull_optimization_guaranteed]
-    pub struct NonNull<T: ?Sized> {
-        pointer: *const T,
-    }
-    // region:coerce_unsized
-    impl<T: ?Sized, U: ?Sized> crate::ops::CoerceUnsized<NonNull<U>> for NonNull<T> where
-        T: crate::marker::Unsize<U>
-    {
-    }
-    // endregion:coerce_unsized
-    // endregion:non_null
 }
 
 pub mod ops {