Repository: rust-lang/rust-analyzer
Pull request #15316 (2023-07-20 09:18:00)

Pass `TraitEnvironment` into `layout_ty` and `const_eval`
We need to do either this or get rid of trait environment in `normalize_ty`. Let's go with this for now.

HKalbasi: @bors r+
bors: :pushpin: Commit 1e631ca13d064a46f75188480ac63b0bb4eb8329 has been approved by `HKalbasi`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust-analyzer) for this repository.

<!-- @bors r=HKalbasi 1e631ca13d064a46f75188480ac63b0bb4eb8329 -->
<!-- homu: {"type":"Approved","sha":"1e631ca13d064a46f75188480ac63b0bb4eb8329","approver":"HKalbasi","queue":"https://bors.rust-lang.org/homu/queue/rust-analyzer"} -->
bors: :hourglass: Testing commit 1e631ca13d064a46f75188480ac63b0bb4eb8329 with merge 3ce7311b459be954b78b852ff4fa5105e02e7079...
<!-- homu: {"type":"BuildStarted","head_sha":"1e631ca13d064a46f75188480ac63b0bb4eb8329","merge_sha":"3ce7311b459be954b78b852ff4fa5105e02e7079"} -->
bors: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang/rust-analyzer/actions/runs/5609183806/jobs/10262678241)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang/rust-analyzer/actions/runs/5609183806/jobs/10262678241","builder_name":"checks-actions"} -->

Patch:
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 4de90d40a7..1c0f7b08da 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -16,7 +16,8 @@ use triomphe::Arc;
 use crate::{
     db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode,
     mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData,
-    ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder,
+    ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
+    TyBuilder,
 };
 
 use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -135,7 +136,7 @@ pub fn intern_const_ref(
     ty: Ty,
     krate: CrateId,
 ) -> Const {
-    let layout = db.layout_of_ty(ty.clone(), krate);
+    let layout = db.layout_of_ty(ty.clone(), Arc::new(TraitEnvironment::empty(krate)));
     let bytes = match value {
         LiteralConstRef::Int(i) => {
             // FIXME: We should handle failure of layout better.
@@ -173,7 +174,7 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
         chalk_ir::ConstValue::Concrete(c) => match &c.interned {
             ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(&it, false))),
             ConstScalar::UnevaluatedConst(c, subst) => {
-                let ec = db.const_eval(*c, subst.clone()).ok()?;
+                let ec = db.const_eval(*c, subst.clone(), None).ok()?;
                 try_const_usize(db, &ec)
             }
             _ => None,
@@ -186,6 +187,7 @@ pub(crate) fn const_eval_recover(
     _: &[String],
     _: &GeneralConstId,
     _: &Substitution,
+    _: &Option<Arc<TraitEnvironment>>,
 ) -> Result<Const, ConstEvalError> {
     Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
 }
@@ -210,6 +212,7 @@ pub(crate) fn const_eval_query(
     db: &dyn HirDatabase,
     def: GeneralConstId,
     subst: Substitution,
+    trait_env: Option<Arc<TraitEnvironment>>,
 ) -> Result<Const, ConstEvalError> {
     let body = match def {
         GeneralConstId::ConstId(c) => {
@@ -228,7 +231,7 @@ pub(crate) fn const_eval_query(
         }
         GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
     };
-    let c = interpret_mir(db, body, false).0?;
+    let c = interpret_mir(db, body, false, trait_env).0?;
     Ok(c)
 }
 
@@ -241,7 +244,7 @@ pub(crate) fn const_eval_static_query(
         Substitution::empty(Interner),
         db.trait_environment_for_body(def.into()),
     )?;
-    let c = interpret_mir(db, body, false).0?;
+    let c = interpret_mir(db, body, false, None).0?;
     Ok(c)
 }
 
@@ -268,7 +271,7 @@ pub(crate) fn const_eval_discriminant_variant(
         Substitution::empty(Interner),
         db.trait_environment_for_body(def),
     )?;
-    let c = interpret_mir(db, mir_body, false).0?;
+    let c = interpret_mir(db, mir_body, false, None).0?;
     let c = try_const_usize(db, &c).unwrap() as i128;
     Ok(c)
 }
@@ -293,7 +296,7 @@ pub(crate) fn eval_to_const(
     }
     let infer = ctx.clone().resolve_all();
     if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) {
-        if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 {
+        if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true, None).0 {
             return result;
         }
     }
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 14b719ea41..9c96b5ab8d 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -77,8 +77,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
 
     #[salsa::invoke(crate::consteval::const_eval_query)]
     #[salsa::cycle(crate::consteval::const_eval_recover)]
-    fn const_eval(&self, def: GeneralConstId, subst: Substitution)
-        -> Result<Const, ConstEvalError>;
+    fn const_eval(
+        &self,
+        def: GeneralConstId,
+        subst: Substitution,
+        trait_env: Option<Arc<crate::TraitEnvironment>>,
+    ) -> Result<Const, ConstEvalError>;
 
     #[salsa::invoke(crate::consteval::const_eval_static_query)]
     #[salsa::cycle(crate::consteval::const_eval_static_recover)]
@@ -100,12 +104,16 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         &self,
         def: AdtId,
         subst: Substitution,
-        krate: CrateId,
+        env: Arc<crate::TraitEnvironment>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
     #[salsa::invoke(crate::layout::layout_of_ty_query)]
     #[salsa::cycle(crate::layout::layout_of_ty_recover)]
-    fn layout_of_ty(&self, ty: Ty, krate: CrateId) -> Result<Arc<Layout>, LayoutError>;
+    fn layout_of_ty(
+        &self,
+        ty: Ty,
+        env: Arc<crate::TraitEnvironment>,
+    ) -> Result<Arc<Layout>, LayoutError>;
 
     #[salsa::invoke(crate::layout::target_data_layout_query)]
     fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 8cffdef289..96787959e1 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -29,6 +29,7 @@ use itertools::Itertools;
 use la_arena::ArenaMap;
 use smallvec::SmallVec;
 use stdx::never;
+use triomphe::Arc;
 
 use crate::{
     consteval::try_const_usize,
@@ -43,7 +44,7 @@ use crate::{
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue,
     DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives,
     MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar,
-    Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
+    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
 };
 
 pub trait HirWrite: fmt::Write {
@@ -454,7 +455,9 @@ fn render_const_scalar(
 ) -> Result<(), HirDisplayError> {
     // FIXME: We need to get krate from the final callers of the hir display
     // infrastructure and have it here as a field on `f`.
-    let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap();
+    let trait_env = Arc::new(TraitEnvironment::empty(
+        *f.db.crate_graph().crates_in_topological_order().last().unwrap(),
+    ));
     match ty.kind(Interner) {
         TyKind::Scalar(s) => match s {
             Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
@@ -497,7 +500,7 @@ fn render_const_scalar(
             TyKind::Slice(ty) => {
                 let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
                 let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
-                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
                     return f.write_str("<layout-error>");
                 };
                 let size_one = layout.size.bytes_usize();
@@ -523,7 +526,7 @@ fn render_const_scalar(
                 let Ok(t) = memory_map.vtable.ty(ty_id) else {
                     return f.write_str("<ty-missing-in-vtable-map>");
                 };
-                let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
+                let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
                     return f.write_str("<layout-error>");
                 };
                 let size = layout.size.bytes_usize();
@@ -555,7 +558,7 @@ fn render_const_scalar(
                         return f.write_str("<layout-error>");
                     }
                 });
-                let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
+                let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
                     return f.write_str("<layout-error>");
                 };
                 let size = layout.size.bytes_usize();
@@ -567,7 +570,7 @@ fn render_const_scalar(
             }
         },
         TyKind::Tuple(_, subst) => {
-            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+            let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
                 return f.write_str("<layout-error>");
             };
             f.write_str("(")?;
@@ -580,7 +583,7 @@ fn render_const_scalar(
                 }
                 let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
                 let offset = layout.fields.offset(id).bytes_usize();
-                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
                     f.write_str("<layout-error>")?;
                     continue;
                 };
@@ -590,7 +593,7 @@ fn render_const_scalar(
             f.write_str(")")
         }
         TyKind::Adt(adt, subst) => {
-            let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
+            let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), trait_env.clone()) else {
                 return f.write_str("<layout-error>");
             };
             match adt.0 {
@@ -602,7 +605,7 @@ fn render_const_scalar(
                         &data.variant_data,
                         f,
                         &field_types,
-                        adt.0.module(f.db.upcast()).krate(),
+                        f.db.trait_environment(adt.0.into()),
                         &layout,
                         subst,
                         b,
@@ -614,7 +617,7 @@ fn render_const_scalar(
                 }
                 hir_def::AdtId::EnumId(e) => {
                     let Some((var_id, var_layout)) =
-                        detect_variant_from_bytes(&layout, f.db, krate, b, e)
+                        detect_variant_from_bytes(&layout, f.db, trait_env.clone(), b, e)
                     else {
                         return f.write_str("<failed-to-detect-variant>");
                     };
@@ -626,7 +629,7 @@ fn render_const_scalar(
                         &data.variant_data,
                         f,
                         &field_types,
-                        adt.0.module(f.db.upcast()).krate(),
+                        f.db.trait_environment(adt.0.into()),
                         &var_layout,
                         subst,
                         b,
@@ -645,7 +648,7 @@ fn render_const_scalar(
             let Some(len) = try_const_usize(f.db, len) else {
                 return f.write_str("<unknown-array-len>");
             };
-            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+            let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
                 return f.write_str("<layout-error>");
             };
             let size_one = layout.size.bytes_usize();
@@ -684,7 +687,7 @@ fn render_variant_after_name(
     data: &VariantData,
     f: &mut HirFormatter<'_>,
     field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
-    krate: CrateId,
+    trait_env: Arc<TraitEnvironment>,
     layout: &Layout,
     subst: &Substitution,
     b: &[u8],
@@ -695,7 +698,7 @@ fn render_variant_after_name(
             let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
                 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
                 let ty = field_types[id].clone().substitute(Interner, subst);
-                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
                     return f.write_str("<layout-error>");
                 };
                 let size = layout.size.bytes_usize();
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 385f39f537..0fb71135b4 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -252,7 +252,8 @@ impl<'a> InferenceTable<'a> {
                             // and registering an obligation. But it needs chalk support, so we handle the most basic
                             // case (a non associated const without generic parameters) manually.
                             if subst.len(Interner) == 0 {
-                                if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
+                                if let Ok(eval) =
+                                    self.db.const_eval((*c_id).into(), subst.clone(), None)
                                 {
                                     eval
                                 } else {
@@ -785,7 +786,7 @@ impl<'a> InferenceTable<'a> {
                 crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()),
                 // try to evaluate unevaluated const. Replace with new var if const eval failed.
                 crate::ConstScalar::UnevaluatedConst(id, subst) => {
-                    if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
+                    if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
                         eval
                     } else {
                         self.new_const_var(data.ty.clone())
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index 72e2bcc555..ffc7a6f2eb 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -1,6 +1,5 @@
 //! Compute the binary representation of a type
 
-use base_db::CrateId;
 use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
 use hir_def::{
     layout::{
@@ -61,7 +60,6 @@ pub enum LayoutError {
 }
 
 struct LayoutCx<'a> {
-    krate: CrateId,
     target: &'a TargetDataLayout,
 }
 
@@ -82,7 +80,7 @@ fn layout_of_simd_ty(
     db: &dyn HirDatabase,
     id: StructId,
     subst: &Substitution,
-    krate: CrateId,
+    env: Arc<TraitEnvironment>,
     dl: &TargetDataLayout,
 ) -> Result<Arc<Layout>, LayoutError> {
     let fields = db.field_types(id.into());
@@ -111,7 +109,7 @@ fn layout_of_simd_ty(
     // * the homogeneous field type and the number of fields.
     let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) {
         // Extract the number of elements from the layout of the array field:
-        let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), krate)?.fields else {
+        let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields else {
             user_error!("Array with non array layout");
         };
 
@@ -122,7 +120,7 @@ fn layout_of_simd_ty(
     };
 
     // Compute the ABI of the element type:
-    let e_ly = db.layout_of_ty(e_ty, krate)?;
+    let e_ly = db.layout_of_ty(e_ty, env.clone())?;
     let Abi::Scalar(e_abi) = e_ly.abi else {
         user_error!("simd type with inner non scalar type");
     };
@@ -152,25 +150,25 @@ fn layout_of_simd_ty(
 pub fn layout_of_ty_query(
     db: &dyn HirDatabase,
     ty: Ty,
-    krate: CrateId,
+    trait_env: Arc<TraitEnvironment>,
 ) -> Result<Arc<Layout>, LayoutError> {
+    let krate = trait_env.krate;
     let Some(target) = db.target_data_layout(krate) else {
         return Err(LayoutError::TargetLayoutNotAvailable);
     };
-    let cx = LayoutCx { krate, target: &target };
+    let cx = LayoutCx { target: &target };
     let dl = &*cx.current_data_layout();
-    let trait_env = Arc::new(TraitEnvironment::empty(krate));
-    let ty = normalize(db, trait_env, ty.clone());
+    let ty = normalize(db, trait_env.clone(), ty.clone());
     let result = match ty.kind(Interner) {
         TyKind::Adt(AdtId(def), subst) => {
             if let hir_def::AdtId::StructId(s) = def {
                 let data = db.struct_data(*s);
                 let repr = data.repr.unwrap_or_default();
                 if repr.simd() {
-                    return layout_of_simd_ty(db, *s, subst, krate, &target);
+                    return layout_of_simd_ty(db, *s, subst, trait_env.clone(), &target);
                 }
             };
-            return db.layout_of_adt(*def, subst.clone(), krate);
+            return db.layout_of_adt(*def, subst.clone(), trait_env.clone());
         }
         TyKind::Scalar(s) => match s {
             chalk_ir::Scalar::Bool => Layout::scalar(
@@ -228,7 +226,7 @@ pub fn layout_of_ty_query(
 
             let fields = tys
                 .iter(Interner)
-                .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate))
+                .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone()))
                 .collect::<Result<Vec<_>, _>>()?;
             let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
             let fields = fields.iter().collect::<Vec<_>>();
@@ -238,7 +236,7 @@ pub fn layout_of_ty_query(
             let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(
                 "unevaluated or mistyped const generic parameter".to_string(),
             ))? as u64;
-            let element = db.layout_of_ty(element.clone(), krate)?;
+            let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
             let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
 
             let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
@@ -259,7 +257,7 @@ pub fn layout_of_ty_query(
             }
         }
         TyKind::Slice(element) => {
-            let element = db.layout_of_ty(element.clone(), krate)?;
+            let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
             Layout {
                 variants: Variants::Single { index: struct_variant_idx() },
                 fields: FieldsShape::Array { stride: element.size, count: 0 },
@@ -335,7 +333,7 @@ pub fn layout_of_ty_query(
             match impl_trait_id {
                 crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
                     let infer = db.infer(func.into());
-                    return db.layout_of_ty(infer.type_of_rpit[idx].clone(), krate);
+                    return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env.clone());
                 }
                 crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
                     return Err(LayoutError::NotImplemented)
@@ -351,7 +349,7 @@ pub fn layout_of_ty_query(
                 .map(|it| {
                     db.layout_of_ty(
                         it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()),
-                        krate,
+                        trait_env.clone(),
                     )
                 })
                 .collect::<Result<Vec<_>, _>>()?;
@@ -377,7 +375,7 @@ pub fn layout_of_ty_recover(
     _: &dyn HirDatabase,
     _: &[String],
     _: &Ty,
-    _: &CrateId,
+    _: &Arc<TraitEnvironment>,
 ) -> Result<Arc<Layout>, LayoutError> {
     user_error!("infinite sized recursive type");
 }
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index 19d5e98e73..1c92e80f33 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -2,7 +2,6 @@
 
 use std::{cmp, ops::Bound};
 
-use base_db::CrateId;
 use hir_def::{
     data::adt::VariantData,
     layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
@@ -16,7 +15,7 @@ use crate::{
     db::HirDatabase,
     lang_items::is_unsafe_cell,
     layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
-    Substitution,
+    Substitution, TraitEnvironment,
 };
 
 use super::LayoutCx;
@@ -29,17 +28,18 @@ pub fn layout_of_adt_query(
     db: &dyn HirDatabase,
     def: AdtId,
     subst: Substitution,
-    krate: CrateId,
+    trait_env: Arc<TraitEnvironment>,
 ) -> Result<Arc<Layout>, LayoutError> {
+    let krate = trait_env.krate;
     let Some(target) = db.target_data_layout(krate) else {
         return Err(LayoutError::TargetLayoutNotAvailable);
     };
-    let cx = LayoutCx { krate, target: &target };
+    let cx = LayoutCx { target: &target };
     let dl = cx.current_data_layout();
     let handle_variant = |def: VariantId, var: &VariantData| {
         var.fields()
             .iter()
-            .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), cx.krate))
+            .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), trait_env.clone()))
             .collect::<Result<Vec<_>, _>>()
     };
     let (variants, repr) = match def {
@@ -134,7 +134,7 @@ pub fn layout_of_adt_recover(
     _: &[String],
     _: &AdtId,
     _: &Substitution,
-    _: &CrateId,
+    _: &Arc<TraitEnvironment>,
 ) -> Result<Arc<Layout>, LayoutError> {
     user_error!("infinite sized recursive type");
 }
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index bc65fd5bac..5e1040bc6a 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -1504,7 +1504,7 @@ fn autoderef_method_receiver(
     ty: Ty,
 ) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
     let mut deref_chain: Vec<_> = Vec::new();
-    let mut autoderef = autoderef::Autoderef::new(table, ty, false);
+    let mut autoderef = autoderef::Autoderef::new(table, ty, true);
     while let Some((ty, derefs)) = autoderef.next() {
         deref_chain.push((
             autoderef.table.canonicalize(ty).value,
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 16843b10d2..7bd2756c14 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -484,9 +484,10 @@ pub fn interpret_mir(
     // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
     // (and probably should) do better here, for example by excluding bindings outside of the target expression.
     assert_placeholder_ty_is_unused: bool,
+    trait_env: Option<Arc<TraitEnvironment>>,
 ) -> (Result<Const>, String, String) {
     let ty = body.locals[return_slot()].ty.clone();
-    let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused);
+    let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env);
     let it: Result<Const> = (|| {
         if evaluator.ptr_size() != std::mem::size_of::<usize>() {
             not_supported!("targets with different pointer size from host");
@@ -512,9 +513,9 @@ impl Evaluator<'_> {
         db: &'a dyn HirDatabase,
         owner: DefWithBodyId,
         assert_placeholder_ty_is_unused: bool,
+        trait_env: Option<Arc<TraitEnvironment>>,
     ) -> Evaluator<'a> {
         let crate_id = owner.module(db.upcast()).krate();
-        let trait_env = db.trait_environment_for_body(owner);
         Evaluator {
             stack: vec![0],
             heap: vec![0],
@@ -524,7 +525,7 @@ impl Evaluator<'_> {
             static_locations: HashMap::default(),
             db,
             random_state: oorandom::Rand64::new(0),
-            trait_env,
+            trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)),
             crate_id,
             stdout: vec![],
             stderr: vec![],
@@ -694,14 +695,14 @@ impl Evaluator<'_> {
         }
         let r = self
             .db
-            .layout_of_ty(ty.clone(), self.crate_id)
+            .layout_of_ty(ty.clone(), self.trait_env.clone())
             .map_err(|e| MirEvalError::LayoutError(e, ty.clone()))?;
         self.layout_cache.borrow_mut().insert(ty.clone(), r.clone());
         Ok(r)
     }
 
     fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> {
-        self.db.layout_of_adt(adt, subst.clone(), self.crate_id).map_err(|e| {
+        self.db.layout_of_adt(adt, subst.clone(), self.trait_env.clone()).map_err(|e| {
             MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
         })
     }
@@ -1582,10 +1583,13 @@ impl Evaluator<'_> {
                     const_id = hir_def::GeneralConstId::ConstId(c);
                     subst = s;
                 }
-                result_owner = self.db.const_eval(const_id.into(), subst).map_err(|e| {
-                    let name = const_id.name(self.db.upcast());
-                    MirEvalError::ConstEvalError(name, Box::new(e))
-                })?;
+                result_owner = self
+                    .db
+                    .const_eval(const_id.into(), subst, Some(self.trait_env.clone()))
+                    .map_err(|e| {
+                        let name = const_id.name(self.db.upcast());
+                        MirEvalError::ConstEvalError(name, Box::new(e))
+                    })?;
                 if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value {
                     if let ConstScalar::Bytes(v, mm) = &c.interned {
                         break 'b (v, mm);
@@ -1818,9 +1822,13 @@ impl Evaluator<'_> {
                     }
                     AdtId::EnumId(e) => {
                         let layout = this.layout(ty)?;
-                        if let Some((v, l)) =
-                            detect_variant_from_bytes(&layout, this.db, this.crate_id, bytes, e)
-                        {
+                        if let Some((v, l)) = detect_variant_from_bytes(
+                            &layout,
+                            this.db,
+                            this.trait_env.clone(),
+                            bytes,
+                            e,
+                        ) {
                             let data = &this.db.enum_data(e).variants[v].variant_data;
                             let field_types = this
                                 .db
@@ -2409,7 +2417,7 @@ pub fn render_const_using_debug_impl(
     owner: ConstId,
     c: &Const,
 ) -> Result<String> {
-    let mut evaluator = Evaluator::new(db, owner.into(), false);
+    let mut evaluator = Evaluator::new(db, owner.into(), false, None);
     let locals = &Locals {
         ptr: ArenaMap::new(),
         body: db
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 724b9ecb60..e443c58f22 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1341,7 +1341,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
     fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<Operand> {
         let size = self
             .db
-            .layout_of_ty(ty.clone(), self.owner.module(self.db.upcast()).krate())?
+            .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))?
             .size
             .bytes_usize();
         let bytes = match l {
@@ -1418,7 +1418,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         } else {
             let name = const_id.name(self.db.upcast());
             self.db
-                .const_eval(const_id.into(), subst)
+                .const_eval(const_id.into(), subst, None)
                 .map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
         };
         Ok(Operand::Constant(c))
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 0c38fe5d6a..75b8b9afa7 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -28,14 +28,15 @@ use intern::Interned;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
+use triomphe::Arc;
 
 use crate::{
     consteval::unknown_const,
     db::HirDatabase,
     layout::{Layout, TagEncoding},
     mir::pad16,
-    ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
-    Ty, WhereClause,
+    ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitEnvironment,
+    TraitRef, TraitRefExt, Ty, WhereClause,
 };
 
 pub(crate) fn fn_traits(
@@ -417,7 +418,7 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
     ) -> Result<Const, Self::Error> {
         if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value {
             if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned {
-                if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
+                if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
                     return Ok(eval);
                 } else {
                     return Ok(unknown_const(constant.data(Interner).ty.clone()));
@@ -431,10 +432,11 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
 pub(crate) fn detect_variant_from_bytes<'a>(
     layout: &'a Layout,
     db: &dyn HirDatabase,
-    krate: CrateId,
+    trait_env: Arc<TraitEnvironment>,
     b: &[u8],
     e: EnumId,
 ) -> Option<(LocalEnumVariantId, &'a Layout)> {
+    let krate = trait_env.krate;
     let (var_id, var_layout) = match &layout.variants {
         hir_def::layout::Variants::Single { index } => (index.0, &*layout),
         hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f8d9398ae2..2b0fdffca9 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -965,8 +965,15 @@ impl Field {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into())
-            .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
+        db.layout_of_ty(
+            self.ty(db).ty.clone(),
+            db.trait_environment(match hir_def::VariantId::from(self.parent) {
+                hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id),
+                hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
+                hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
+            }),
+        )
+        .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
     }
 
     pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
@@ -1246,8 +1253,12 @@ impl Adt {
             return Err(LayoutError::HasPlaceholder);
         }
         let krate = self.krate(db).id;
-        db.layout_of_adt(self.into(), Substitution::empty(Interner), krate)
-            .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
+        db.layout_of_adt(
+            self.into(),
+            Substitution::empty(Interner),
+            db.trait_environment(self.into()),
+        )
+        .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
     }
 
     /// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -1987,7 +1998,7 @@ impl Function {
                 return r;
             }
         };
-        let (result, stdout, stderr) = interpret_mir(db, body, false);
+        let (result, stdout, stderr) = interpret_mir(db, body, false, None);
         let mut text = match result {
             Ok(_) => "pass".to_string(),
             Err(e) => {
@@ -2156,7 +2167,7 @@ impl Const {
     }
 
     pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
-        let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
+        let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
         let data = &c.data(Interner);
         if let TyKind::Scalar(s) = data.ty.kind(Interner) {
             if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
@@ -4322,7 +4333,7 @@ impl Type {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        db.layout_of_ty(self.ty.clone(), self.env.krate)
+        db.layout_of_ty(self.ty.clone(), self.env.clone())
             .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
     }
 }
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index a868419821..1814e0e54c 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -211,54 +211,70 @@ impl BlockLike {
 const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]);
 
 fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
-    if !p.at(T![pub]) {
-        return false;
-    }
-
-    let m = p.start();
-    p.bump(T![pub]);
-    if p.at(T!['(']) {
-        match p.nth(1) {
-            // test crate_visibility
-            // pub(crate) struct S;
-            // pub(self) struct S;
-            // pub(super) struct S;
-
-            // test_err crate_visibility_empty_recover
-            // pub() struct S;
-
-            // test pub_parens_typepath
-            // struct B(pub (super::A));
-            // struct B(pub (crate::A,));
-            T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
-                // If we are in a tuple struct, then the parens following `pub`
-                // might be an tuple field, not part of the visibility. So in that
-                // case we don't want to consume an identifier.
-
-                // test pub_tuple_field
-                // struct MyStruct(pub (u32, u32));
-                // struct MyStruct(pub (u32));
-                // struct MyStruct(pub ());
-                if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
-                    p.bump(T!['(']);
-                    paths::use_path(p);
-                    p.expect(T![')']);
+    match p.current() {
+        T![pub] => {
+            let m = p.start();
+            p.bump(T![pub]);
+            if p.at(T!['(']) {
+                match p.nth(1) {
+                    // test crate_visibility
+                    // pub(crate) struct S;
+                    // pub(self) struct S;
+                    // pub(super) struct S;
+
+                    // test_err crate_visibility_empty_recover
+                    // pub() struct S;
+
+                    // test pub_parens_typepath
+                    // struct B(pub (super::A));
+                    // struct B(pub (crate::A,));
+                    T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
+                        // If we are in a tuple struct, then the parens following `pub`
+                        // might be an tuple field, not part of the visibility. So in that
+                        // case we don't want to consume an identifier.
+
+                        // test pub_tuple_field
+                        // struct MyStruct(pub (u32, u32));
+                        // struct MyStruct(pub (u32));
+                        // struct MyStruct(pub ());
+                        if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
+                            p.bump(T!['(']);
+                            paths::use_path(p);
+                            p.expect(T![')']);
+                        }
+                    }
+                    // test crate_visibility_in
+                    // pub(in super::A) struct S;
+                    // pub(in crate) struct S;
+                    T![in] => {
+                        p.bump(T!['(']);
+                        p.bump(T![in]);
+                        paths::use_path(p);
+                        p.expect(T![')']);
+                    }
+                    _ => {}
                 }
             }
-            // test crate_visibility_in
-            // pub(in super::A) struct S;
-            // pub(in crate) struct S;
-            T![in] => {
-                p.bump(T!['(']);
-                p.bump(T![in]);
-                paths::use_path(p);
-                p.expect(T![')']);
+            m.complete(p, VISIBILITY);
+            true
+        }
+        // test crate_keyword_vis
+        // crate fn main() { }
+        // struct S { crate field: u32 }
+        // struct T(crate u32);
+        T![crate] => {
+            if p.nth_at(1, T![::]) {
+                // test crate_keyword_path
+                // fn foo() { crate::foo(); }
+                return false;
             }
-            _ => {}
+            let m = p.start();
+            p.bump(T![crate]);
+            m.complete(p, VISIBILITY);
+            true
         }
+        _ => false,
     }
-    m.complete(p, VISIBILITY);
-    true
 }
 
 fn opt_rename(p: &mut Parser<'_>) {
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 8d68bf160a..33d7b5ed87 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -8,7 +8,7 @@ use std::{
 
 use hir::{
     db::{DefDatabase, ExpandDatabase, HirDatabase},
-    Adt, AssocItem, Crate, DefWithBody, HasCrate, HasSource, HirDisplay, ModuleDef, Name,
+    Adt, AssocItem, Crate, DefWithBody, HasSource, HirDisplay, ModuleDef, Name,
 };
 use hir_def::{
     body::{BodySourceMap, SyntheticSyntax},
@@ -277,7 +277,7 @@ impl flags::AnalysisStats {
             let Err(e) = db.layout_of_adt(
                 hir_def::AdtId::from(a).into(),
                 Substitution::empty(Interner),
-                a.krate(db).into(),
+                db.trait_environment(a.into()),
             ) else {
                 continue;
             };


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 5bb327606d..de792a6c5a 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -114,7 +114,7 @@ fn eval_goal(db: &TestDB, file_id: FileId) -> Result<Const, ConstEvalError> {
             _ => None,
         })
         .expect("No const named GOAL found in the test");
-    db.const_eval(const_id.into(), Substitution::empty(Interner))
+    db.const_eval(const_id.into(), Substitution::empty(Interner), None)
 }
 
 #[test]
@@ -2492,6 +2492,28 @@ fn const_trait_assoc() {
     "#,
         5,
     );
+    check_number(
+        r#"
+    //- minicore: size_of
+    //- /a/lib.rs crate:a
+    use core::mem::size_of;
+    pub struct S<T>(T);
+    impl<T> S<T> {
+        pub const X: usize = core::mem::size_of::<T>();
+    }
+    //- /main.rs crate:main deps:a
+    use a::{S};
+    trait Tr {
+        type Ty;
+    }
+    impl Tr for i32 {
+        type Ty = u64;
+    }
+    struct K<T: Tr>(<T as Tr>::Ty);
+    const GOAL: usize = S::<K<i32>>::X;
+    "#,
+        8,
+    );
     check_number(
         r#"
     struct S<T>(*mut T);
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index a3ced2bac0..333ad473a8 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -26,7 +26,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
     );
 
     let (db, file_ids) = TestDB::with_many_files(&ra_fixture);
-    let (adt_or_type_alias_id, module_id) = file_ids
+    let adt_or_type_alias_id = file_ids
         .into_iter()
         .find_map(|file_id| {
             let module_id = db.module_for_file(file_id);
@@ -47,7 +47,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
                 }
                 _ => None,
             })?;
-            Some((adt_or_type_alias_id, module_id))
+            Some(adt_or_type_alias_id)
         })
         .unwrap();
     let goal_ty = match adt_or_type_alias_id {
@@ -58,7 +58,13 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
             db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner))
         }
     };
-    db.layout_of_ty(goal_ty, module_id.krate())
+    db.layout_of_ty(
+        goal_ty,
+        db.trait_environment(match adt_or_type_alias_id {
+            Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
+            Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
+        }),
+    )
 }
 
 /// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
@@ -72,7 +78,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
     let module_id = db.module_for_file(file_id);
     let def_map = module_id.def_map(&db);
     let scope = &def_map[module_id.local_id].scope;
-    let adt_id = scope
+    let function_id = scope
         .declarations()
         .find_map(|x| match x {
             hir_def::ModuleDefId::FunctionId(x) => {
@@ -82,11 +88,11 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
             _ => None,
         })
         .unwrap();
-    let hir_body = db.body(adt_id.into());
+    let hir_body = db.body(function_id.into());
     let b = hir_body.bindings.iter().find(|x| x.1.name.to_smol_str() == "goal").unwrap().0;
-    let infer = db.infer(adt_id.into());
+    let infer = db.infer(function_id.into());
     let goal_ty = infer.type_of_binding[b].clone();
-    db.layout_of_ty(goal_ty, module_id.krate())
+    db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))
 }
 
 #[track_caller]
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 03c083bac4..93f4b69914 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
             db.trait_environment(func_id.into()),
         )
         .map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?;
-    let (result, stdout, stderr) = interpret_mir(db, body, false);
+    let (result, stdout, stderr) = interpret_mir(db, body, false, None);
     result?;
     Ok((stdout, stderr))
 }
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index c837fae3fe..a8e146b096 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -1236,27 +1236,6 @@ fn main() {
     );
 }
 
-#[test]
-fn inherent_method_ref_self_deref_raw() {
-    check_types(
-        r#"
-struct Val;
-
-impl Val {
-    pub fn method(&self) -> u32 {
-        0
-    }
-}
-
-fn main() {
-    let foo: *const Val;
-    foo.method();
- // ^^^^^^^^^^^^ {unknown}
-}
-"#,
-    );
-}
-
 #[test]
 fn trait_method_deref_raw() {
     check_types(
diff --git a/crates/parser/src/tests/prefix_entries.rs b/crates/parser/src/tests/prefix_entries.rs
index 2f3c7febc0..11f9c34abd 100644
--- a/crates/parser/src/tests/prefix_entries.rs
+++ b/crates/parser/src/tests/prefix_entries.rs
@@ -6,6 +6,7 @@ fn vis() {
     check(PrefixEntryPoint::Vis, "fn foo() {}", "");
     check(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
     check(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
+    check(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
 }
 
 #[test]
diff --git a/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast b/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
new file mode 100644
index 0000000000..07b0210e44
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
@@ -0,0 +1,63 @@
+SOURCE_FILE
+  FN
+    VISIBILITY
+      CRATE_KW "crate"
+    WHITESPACE " "
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "main"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        R_CURLY "}"
+  WHITESPACE "\n"
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "S"
+    WHITESPACE " "
+    RECORD_FIELD_LIST
+      L_CURLY "{"
+      WHITESPACE " "
+      RECORD_FIELD
+        VISIBILITY
+          CRATE_KW "crate"
+        WHITESPACE " "
+        NAME
+          IDENT "field"
+        COLON ":"
+        WHITESPACE " "
+        PATH_TYPE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "u32"
+      WHITESPACE " "
+      R_CURLY "}"
+  WHITESPACE "\n"
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "T"
+    TUPLE_FIELD_LIST
+      L_PAREN "("
+      TUPLE_FIELD
+        VISIBILITY
+          CRATE_KW "crate"
+        WHITESPACE " "
+        PATH_TYPE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "u32"
+      R_PAREN ")"
+    SEMICOLON ";"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs b/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs
new file mode 100644
index 0000000000..e2b5f2161d
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs
@@ -0,0 +1,3 @@
+crate fn main() { }
+struct S { crate field: u32 }
+struct T(crate u32);
diff --git a/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast b/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast
new file mode 100644
index 0000000000..8d9b61630a
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        EXPR_STMT
+          CALL_EXPR
+            PATH_EXPR
+              PATH
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      CRATE_KW "crate"
+                COLON2 "::"
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "foo"
+            ARG_LIST
+              L_PAREN "("
+              R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE " "
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs b/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs
new file mode 100644
index 0000000000..0f454d121d
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs
@@ -0,0 +1,1 @@
+fn foo() { crate::foo(); }