fix: Yet another false positive invalid cast diagnostic
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index d3de86f..0670a4e 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -50,7 +50,7 @@
                     None
                 }
             }
-            TyKind::Raw(m, ty) => Some(Self::Ptr(table.resolve_ty_shallow(ty), *m)),
+            TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)),
             TyKind::Function(_) => Some(Self::FnPtr),
             _ => None,
         }
@@ -105,9 +105,8 @@
         F: FnMut(ExprId, Vec<Adjustment>),
         G: FnMut(ExprId),
     {
-        table.resolve_obligations_as_possible();
-        self.expr_ty = table.resolve_ty_shallow(&self.expr_ty);
-        self.cast_ty = table.resolve_ty_shallow(&self.cast_ty);
+        self.expr_ty = table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone());
+        self.cast_ty = table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone());
 
         if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() {
             return Ok(());
@@ -153,7 +152,7 @@
                 (None, Some(t_cast)) => match self.expr_ty.kind(Interner) {
                     TyKind::FnDef(..) => {
                         let sig = self.expr_ty.callable_sig(table.db).expect("FnDef had no sig");
-                        let sig = table.normalize_associated_types_in(sig);
+                        let sig = table.eagerly_normalize_and_resolve_shallow_in(sig);
                         let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
                         if let Ok((adj, _)) = table.coerce(&self.expr_ty, &fn_ptr, CoerceNever::Yes)
                         {
@@ -165,7 +164,6 @@
                         (CastTy::FnPtr, t_cast)
                     }
                     TyKind::Ref(mutbl, _, inner_ty) => {
-                        let inner_ty = table.resolve_ty_shallow(inner_ty);
                         return match t_cast {
                             CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) {
                                 TyKind::Scalar(
@@ -180,13 +178,13 @@
                             },
                             // array-ptr-cast
                             CastTy::Ptr(t, m) => {
-                                let t = table.resolve_ty_shallow(&t);
+                                let t = table.eagerly_normalize_and_resolve_shallow_in(t);
                                 if !table.is_sized(&t) {
                                     return Err(CastError::IllegalCast);
                                 }
                                 self.check_ref_cast(
                                     table,
-                                    &inner_ty,
+                                    inner_ty,
                                     *mutbl,
                                     &t,
                                     m,
@@ -359,7 +357,7 @@
     }
 }
 
-#[derive(PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 enum PointerKind {
     // thin pointer
     Thin,
@@ -373,8 +371,7 @@
 }
 
 fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<PointerKind>, ()> {
-    let ty = table.resolve_ty_shallow(ty);
-    let ty = table.normalize_associated_types_in(ty);
+    let ty = table.eagerly_normalize_and_resolve_shallow_in(ty.clone());
 
     if table.is_sized(&ty) {
         return Ok(Some(PointerKind::Thin));
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 903097e..67796b9 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -364,6 +364,64 @@
         )
     }
 
+    /// Works almost same as [`Self::normalize_associated_types_in`], but this also resolves shallow
+    /// the inference variables
+    pub(crate) fn eagerly_normalize_and_resolve_shallow_in<T>(&mut self, ty: T) -> T
+    where
+        T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
+    {
+        fn eagerly_resolve_ty<const N: usize>(
+            table: &mut InferenceTable<'_>,
+            ty: Ty,
+            mut tys: SmallVec<[Ty; N]>,
+        ) -> Ty {
+            if tys.contains(&ty) {
+                return ty;
+            }
+            tys.push(ty.clone());
+
+            match ty.kind(Interner) {
+                TyKind::Alias(AliasTy::Projection(proj_ty)) => {
+                    let ty = table.normalize_projection_ty(proj_ty.clone());
+                    eagerly_resolve_ty(table, ty, tys)
+                }
+                TyKind::InferenceVar(..) => {
+                    let ty = table.resolve_ty_shallow(&ty);
+                    eagerly_resolve_ty(table, ty, tys)
+                }
+                _ => ty,
+            }
+        }
+
+        fold_tys_and_consts(
+            ty,
+            |e, _| match e {
+                Either::Left(ty) => {
+                    Either::Left(eagerly_resolve_ty::<8>(self, ty, SmallVec::new()))
+                }
+                Either::Right(c) => Either::Right(match &c.data(Interner).value {
+                    chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
+                        crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
+                            // FIXME: same as `normalize_associated_types_in`
+                            if subst.len(Interner) == 0 {
+                                if let Ok(eval) = self.db.const_eval(*c_id, subst.clone(), None) {
+                                    eval
+                                } else {
+                                    unknown_const(c.data(Interner).ty.clone())
+                                }
+                            } else {
+                                unknown_const(c.data(Interner).ty.clone())
+                            }
+                        }
+                        _ => c,
+                    },
+                    _ => c,
+                }),
+            },
+            DebruijnIndex::INNERMOST,
+        )
+    }
+
     pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
         let var = self.new_type_var();
         let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
@@ -918,7 +976,26 @@
 
     /// Check if given type is `Sized` or not
     pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
+        fn short_circuit_trivial_tys(ty: &Ty) -> Option<bool> {
+            match ty.kind(Interner) {
+                TyKind::Scalar(..)
+                | TyKind::Ref(..)
+                | TyKind::Raw(..)
+                | TyKind::Never
+                | TyKind::FnDef(..)
+                | TyKind::Array(..)
+                | TyKind::Function(..) => Some(true),
+                TyKind::Slice(..) | TyKind::Str | TyKind::Dyn(..) => Some(false),
+                _ => None,
+            }
+        }
+
         let mut ty = ty.clone();
+        ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
+        if let Some(sized) = short_circuit_trivial_tys(&ty) {
+            return sized;
+        }
+
         {
             let mut structs = SmallVec::<[_; 8]>::new();
             // Must use a loop here and not recursion because otherwise users will conduct completely
@@ -937,26 +1014,16 @@
                     // Structs can have DST as its last field and such cases are not handled
                     // as unsized by the chalk, so we do this manually.
                     ty = last_field_ty;
+                    ty = self.eagerly_normalize_and_resolve_shallow_in(ty);
+                    if let Some(sized) = short_circuit_trivial_tys(&ty) {
+                        return sized;
+                    }
                 } else {
                     break;
                 };
             }
         }
 
-        // Early return for some obvious types
-        if matches!(
-            ty.kind(Interner),
-            TyKind::Scalar(..)
-                | TyKind::Ref(..)
-                | TyKind::Raw(..)
-                | TyKind::Never
-                | TyKind::FnDef(..)
-                | TyKind::Array(..)
-                | TyKind::Function(_)
-        ) {
-            return true;
-        }
-
         let Some(sized) = self
             .db
             .lang_item(self.trait_env.krate, LangItem::Sized)
diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 82cd1f2..b56255b 100644
--- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -440,8 +440,9 @@
     q as *const [i32];
   //^^^^^^^^^^^^^^^^^ error: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]`
 
+    // FIXME: This should emit diagnostics but disabled to prevent many false positives
     let t: *mut (dyn Trait + 'static) = 0 as *mut _;
-                                      //^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*mut _`
+
     let mut fail: *const str = 0 as *const str;
                              //^^^^^^^^^^^^^^^ error: cannot cast `usize` to a fat pointer `*const str`
     let mut fail2: *const str = 0isize as *const str;
@@ -1164,4 +1165,47 @@
 "#,
         );
     }
+
+    #[test]
+    fn regression_19431() {
+        check_diagnostics(
+            r#"
+//- minicore: coerce_unsized
+struct Dst([u8]);
+
+struct Struct {
+    body: Dst,
+}
+
+trait Field {
+    type Type: ?Sized;
+}
+
+impl Field for Struct {
+    type Type = Dst;
+}
+
+trait KnownLayout {
+    type MaybeUninit: ?Sized;
+    type PointerMetadata;
+}
+
+impl<T> KnownLayout for [T] {
+    type MaybeUninit = [T];
+    type PointerMetadata = usize;
+}
+
+impl KnownLayout for Dst {
+    type MaybeUninit = Dst;
+    type PointerMetadata = <[u8] as KnownLayout>::PointerMetadata;
+}
+
+struct ZerocopyKnownLayoutMaybeUninit(<<Struct as Field>::Type as KnownLayout>::MaybeUninit);
+
+fn test(ptr: *mut ZerocopyKnownLayoutMaybeUninit) -> *mut <<Struct as Field>::Type as KnownLayout>::MaybeUninit {
+    ptr as *mut _
+}
+"#,
+        );
+    }
 }