Repository: rust-lang/rust-analyzer
Pull request #15290 (2023-07-15 19:42:26)

editor/code: [DX] Use notification command links for debugger installation
This PR improves DX (developer experience) when installing the VS Code extension for the first time. When doing so and trying to debug a Rust file, we get an error notification that either CodeLLDB or C++ extension/debugger should be installed (see image below).

<div align="center">
	<img src="https://github.com/rust-lang/rust-analyzer/assets/20957750/e8ebeb1e-85f4-44e2-b79f-c48cf52e5f36" alt="Rust, prompt to install debug extension">
</div>

The PR enhances the links in the given notification and upon clicking instead of opening the Web page of the extension it installs the extension immediately, without the need to leave the editor.

Note: the feature needs to be refined, maybe an "install in progress" message or something similar, I left that for you guys to decide and implement. I think it also possible to first open the sidebar, open the Extensions tab, then run the extension installation command which would make it more user-friendly.

P.S. it is also possible to open the extension's details in VS Code directly via the same links and then the user would have to manually click on the Install button - if installation is not the desired behavior.

Happy coding! 🎉

lnicola: Two remarks:
 - you can merge the two functions by passing the extension id as JSON, as in the second example in https://code.visualstudio.com/api/extension-guides/command#command-uris
 - it might be nice to try `workbench.extensions.installExtension` or `workbench.extensions.search`, from https://code.visualstudio.com/api/references/commands (though it's not really clear to me what to use as the JSON key)
igorskyflyer: <div align="center">
	<video src="https://github.com/rust-lang/rust-analyzer/assets/20957750/a0f911e2-1a67-44cd-8c1e-73dba556998d"></video>
	<p>Command line tooltips</p>
</div>

igorskyflyer: > Two remarks:
> 
> * you can merge the two functions by passing the extension id as JSON, as in the second example in [code.visualstudio.com/api/extension-guides/command#command-uris](https://code.visualstudio.com/api/extension-guides/command#command-uris)
> * it might be nice to try `workbench.extensions.installExtension` or `workbench.extensions.search`, from [code.visualstudio.com/api/references/commands](https://code.visualstudio.com/api/references/commands) (though it's not really clear to me what to use as the JSON key)

Didn't know we could pass args to command links, thanks for the heads-up!
Regarding the commands, this PR already implements `workbench.extensions.installExtension`, that's the whole point of it. 😊

I am working on the proposed changes, I'll push the changes when done.
lnicola: Stupid question, but how do you test this? If I press F5 in a Rust project (not rust-analyzer itself), I get:

![image](https://github.com/rust-lang/rust-analyzer/assets/308347/e9452661-de3e-43da-a16b-1ce15eff725e)

lnicola: > Which option you think is the optimal solution?

Ideally, we'd open the extension page, or search with the id filled in. We shouldn't install anything by ourselves.

The only issue is that I'm not sure if this is possible.
igorskyflyer: > Stupid question, but how do you test this? If I press F5 in a Rust project (not rust-analyzer itself), I get:
> 
> ![image](https://user-images.githubusercontent.com/308347/254623962-e9452661-de3e-43da-a16b-1ce15eff725e.png)

Funny thing, I actually never started debugging with `F5` here, I always click on the highlighted Debug link above code, see the image below.  😅

<div align="center">
	<img src="https://github.com/rust-lang/rust-analyzer/assets/20957750/53458982-a356-41f5-a719-29f50d566833">
</div>

igorskyflyer: I actually made it work. 🎉

Here's the final version with one note, see below:

<div align="center">
	<video src="https://github.com/rust-lang/rust-analyzer/assets/20957750/0c58f827-29a2-4eb0-aa2d-47c2df18a703"></video>
</div>

https://github.com/igorskyflyer/rust-analyzer/blob/02e6446909c6966cca2b84d827eed93e4bfdb095/editors/code/src/debug.ts#L103

We cannot remove the command links' tooltip; if it's set to an empty string, VS Code consumes the rest of the error message as the first link's tooltip and if the tooltip is removed altogether then VS Code shows an *ugly* tooltip, like `Execute command <commandName>`

And, I've changed the `MS C++ tools` link name to `C/C++` to adhere the extension's official name [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) but then again, you guys can change that whenever you want. 😉
bors: :v: @igorskyflyer, you can now approve this pull request!

If @lnicola told you to "`r=me`" after making some further change, please make that change, then do `@bors r=@lnicola`
<!-- homu: {"type":"Delegated","delegator":"lnicola","delegate":"igorskyflyer"} -->

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index f6a50bfa6b..24889fc142 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.70"
+rust-version = "1.66"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 1c0f7b08da..4de90d40a7 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -16,8 +16,7 @@ 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, TraitEnvironment, Ty,
-    TyBuilder,
+    ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder,
 };
 
 use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
@@ -136,7 +135,7 @@ pub fn intern_const_ref(
     ty: Ty,
     krate: CrateId,
 ) -> Const {
-    let layout = db.layout_of_ty(ty.clone(), Arc::new(TraitEnvironment::empty(krate)));
+    let layout = db.layout_of_ty(ty.clone(), krate);
     let bytes = match value {
         LiteralConstRef::Int(i) => {
             // FIXME: We should handle failure of layout better.
@@ -174,7 +173,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(), None).ok()?;
+                let ec = db.const_eval(*c, subst.clone()).ok()?;
                 try_const_usize(db, &ec)
             }
             _ => None,
@@ -187,7 +186,6 @@ pub(crate) fn const_eval_recover(
     _: &[String],
     _: &GeneralConstId,
     _: &Substitution,
-    _: &Option<Arc<TraitEnvironment>>,
 ) -> Result<Const, ConstEvalError> {
     Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
 }
@@ -212,7 +210,6 @@ 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) => {
@@ -231,7 +228,7 @@ pub(crate) fn const_eval_query(
         }
         GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
     };
-    let c = interpret_mir(db, body, false, trait_env).0?;
+    let c = interpret_mir(db, body, false).0?;
     Ok(c)
 }
 
@@ -244,7 +241,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, None).0?;
+    let c = interpret_mir(db, body, false).0?;
     Ok(c)
 }
 
@@ -271,7 +268,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, None).0?;
+    let c = interpret_mir(db, mir_body, false).0?;
     let c = try_const_usize(db, &c).unwrap() as i128;
     Ok(c)
 }
@@ -296,7 +293,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, None).0 {
+        if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 {
             return result;
         }
     }
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 9c96b5ab8d..14b719ea41 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -77,12 +77,8 @@ 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,
-        trait_env: Option<Arc<crate::TraitEnvironment>>,
-    ) -> Result<Const, ConstEvalError>;
+    fn const_eval(&self, def: GeneralConstId, subst: Substitution)
+        -> Result<Const, ConstEvalError>;
 
     #[salsa::invoke(crate::consteval::const_eval_static_query)]
     #[salsa::cycle(crate::consteval::const_eval_static_recover)]
@@ -104,16 +100,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         &self,
         def: AdtId,
         subst: Substitution,
-        env: Arc<crate::TraitEnvironment>,
+        krate: CrateId,
     ) -> 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,
-        env: Arc<crate::TraitEnvironment>,
-    ) -> Result<Arc<Layout>, LayoutError>;
+    fn layout_of_ty(&self, ty: Ty, krate: CrateId) -> 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 96787959e1..8cffdef289 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -29,7 +29,6 @@ use itertools::Itertools;
 use la_arena::ArenaMap;
 use smallvec::SmallVec;
 use stdx::never;
-use triomphe::Arc;
 
 use crate::{
     consteval::try_const_usize,
@@ -44,7 +43,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, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
+    Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
 };
 
 pub trait HirWrite: fmt::Write {
@@ -455,9 +454,7 @@ 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 trait_env = Arc::new(TraitEnvironment::empty(
-        *f.db.crate_graph().crates_in_topological_order().last().unwrap(),
-    ));
+    let krate = *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 }),
@@ -500,7 +497,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(), trait_env) else {
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
                     return f.write_str("<layout-error>");
                 };
                 let size_one = layout.size.bytes_usize();
@@ -526,7 +523,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(), trait_env) else {
+                let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
                     return f.write_str("<layout-error>");
                 };
                 let size = layout.size.bytes_usize();
@@ -558,7 +555,7 @@ fn render_const_scalar(
                         return f.write_str("<layout-error>");
                     }
                 });
-                let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
+                let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
                     return f.write_str("<layout-error>");
                 };
                 let size = layout.size.bytes_usize();
@@ -570,7 +567,7 @@ fn render_const_scalar(
             }
         },
         TyKind::Tuple(_, subst) => {
-            let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
+            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
                 return f.write_str("<layout-error>");
             };
             f.write_str("(")?;
@@ -583,7 +580,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(), trait_env.clone()) else {
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
                     f.write_str("<layout-error>")?;
                     continue;
                 };
@@ -593,7 +590,7 @@ fn render_const_scalar(
             f.write_str(")")
         }
         TyKind::Adt(adt, subst) => {
-            let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), trait_env.clone()) else {
+            let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
                 return f.write_str("<layout-error>");
             };
             match adt.0 {
@@ -605,7 +602,7 @@ fn render_const_scalar(
                         &data.variant_data,
                         f,
                         &field_types,
-                        f.db.trait_environment(adt.0.into()),
+                        adt.0.module(f.db.upcast()).krate(),
                         &layout,
                         subst,
                         b,
@@ -617,7 +614,7 @@ fn render_const_scalar(
                 }
                 hir_def::AdtId::EnumId(e) => {
                     let Some((var_id, var_layout)) =
-                        detect_variant_from_bytes(&layout, f.db, trait_env.clone(), b, e)
+                        detect_variant_from_bytes(&layout, f.db, krate, b, e)
                     else {
                         return f.write_str("<failed-to-detect-variant>");
                     };
@@ -629,7 +626,7 @@ fn render_const_scalar(
                         &data.variant_data,
                         f,
                         &field_types,
-                        f.db.trait_environment(adt.0.into()),
+                        adt.0.module(f.db.upcast()).krate(),
                         &var_layout,
                         subst,
                         b,
@@ -648,7 +645,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(), trait_env) else {
+            let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
                 return f.write_str("<layout-error>");
             };
             let size_one = layout.size.bytes_usize();
@@ -687,7 +684,7 @@ fn render_variant_after_name(
     data: &VariantData,
     f: &mut HirFormatter<'_>,
     field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
-    trait_env: Arc<TraitEnvironment>,
+    krate: CrateId,
     layout: &Layout,
     subst: &Substitution,
     b: &[u8],
@@ -698,7 +695,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(), trait_env.clone()) else {
+                let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) 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 0fb71135b4..385f39f537 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -252,8 +252,7 @@ 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(), None)
+                                if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
                                 {
                                     eval
                                 } else {
@@ -786,7 +785,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(), None) {
+                    if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
                         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 ffc7a6f2eb..72e2bcc555 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -1,5 +1,6 @@
 //! Compute the binary representation of a type
 
+use base_db::CrateId;
 use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
 use hir_def::{
     layout::{
@@ -60,6 +61,7 @@ pub enum LayoutError {
 }
 
 struct LayoutCx<'a> {
+    krate: CrateId,
     target: &'a TargetDataLayout,
 }
 
@@ -80,7 +82,7 @@ fn layout_of_simd_ty(
     db: &dyn HirDatabase,
     id: StructId,
     subst: &Substitution,
-    env: Arc<TraitEnvironment>,
+    krate: CrateId,
     dl: &TargetDataLayout,
 ) -> Result<Arc<Layout>, LayoutError> {
     let fields = db.field_types(id.into());
@@ -109,7 +111,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(), env.clone())?.fields else {
+        let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), krate)?.fields else {
             user_error!("Array with non array layout");
         };
 
@@ -120,7 +122,7 @@ fn layout_of_simd_ty(
     };
 
     // Compute the ABI of the element type:
-    let e_ly = db.layout_of_ty(e_ty, env.clone())?;
+    let e_ly = db.layout_of_ty(e_ty, krate)?;
     let Abi::Scalar(e_abi) = e_ly.abi else {
         user_error!("simd type with inner non scalar type");
     };
@@ -150,25 +152,25 @@ fn layout_of_simd_ty(
 pub fn layout_of_ty_query(
     db: &dyn HirDatabase,
     ty: Ty,
-    trait_env: Arc<TraitEnvironment>,
+    krate: CrateId,
 ) -> 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 { target: &target };
+    let cx = LayoutCx { krate, target: &target };
     let dl = &*cx.current_data_layout();
-    let ty = normalize(db, trait_env.clone(), ty.clone());
+    let trait_env = Arc::new(TraitEnvironment::empty(krate));
+    let ty = normalize(db, trait_env, 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, trait_env.clone(), &target);
+                    return layout_of_simd_ty(db, *s, subst, krate, &target);
                 }
             };
-            return db.layout_of_adt(*def, subst.clone(), trait_env.clone());
+            return db.layout_of_adt(*def, subst.clone(), krate);
         }
         TyKind::Scalar(s) => match s {
             chalk_ir::Scalar::Bool => Layout::scalar(
@@ -226,7 +228,7 @@ pub fn layout_of_ty_query(
 
             let fields = tys
                 .iter(Interner)
-                .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone()))
+                .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate))
                 .collect::<Result<Vec<_>, _>>()?;
             let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
             let fields = fields.iter().collect::<Vec<_>>();
@@ -236,7 +238,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(), trait_env.clone())?;
+            let element = db.layout_of_ty(element.clone(), krate)?;
             let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
 
             let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
@@ -257,7 +259,7 @@ pub fn layout_of_ty_query(
             }
         }
         TyKind::Slice(element) => {
-            let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
+            let element = db.layout_of_ty(element.clone(), krate)?;
             Layout {
                 variants: Variants::Single { index: struct_variant_idx() },
                 fields: FieldsShape::Array { stride: element.size, count: 0 },
@@ -333,7 +335,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(), trait_env.clone());
+                    return db.layout_of_ty(infer.type_of_rpit[idx].clone(), krate);
                 }
                 crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
                     return Err(LayoutError::NotImplemented)
@@ -349,7 +351,7 @@ pub fn layout_of_ty_query(
                 .map(|it| {
                     db.layout_of_ty(
                         it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()),
-                        trait_env.clone(),
+                        krate,
                     )
                 })
                 .collect::<Result<Vec<_>, _>>()?;
@@ -375,7 +377,7 @@ pub fn layout_of_ty_recover(
     _: &dyn HirDatabase,
     _: &[String],
     _: &Ty,
-    _: &Arc<TraitEnvironment>,
+    _: &CrateId,
 ) -> 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 1c92e80f33..19d5e98e73 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -2,6 +2,7 @@
 
 use std::{cmp, ops::Bound};
 
+use base_db::CrateId;
 use hir_def::{
     data::adt::VariantData,
     layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
@@ -15,7 +16,7 @@ use crate::{
     db::HirDatabase,
     lang_items::is_unsafe_cell,
     layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
-    Substitution, TraitEnvironment,
+    Substitution,
 };
 
 use super::LayoutCx;
@@ -28,18 +29,17 @@ pub fn layout_of_adt_query(
     db: &dyn HirDatabase,
     def: AdtId,
     subst: Substitution,
-    trait_env: Arc<TraitEnvironment>,
+    krate: CrateId,
 ) -> 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 { target: &target };
+    let cx = LayoutCx { krate, 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), trait_env.clone()))
+            .map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), cx.krate))
             .collect::<Result<Vec<_>, _>>()
     };
     let (variants, repr) = match def {
@@ -134,7 +134,7 @@ pub fn layout_of_adt_recover(
     _: &[String],
     _: &AdtId,
     _: &Substitution,
-    _: &Arc<TraitEnvironment>,
+    _: &CrateId,
 ) -> 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 f3a5f69b2a..5e1040bc6a 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -665,21 +665,13 @@ pub fn is_dyn_method(
     };
     let self_ty = trait_ref.self_type_parameter(Interner);
     if let TyKind::Dyn(d) = self_ty.kind(Interner) {
-        let is_my_trait_in_bounds = d
-            .bounds
-            .skip_binders()
-            .as_slice(Interner)
-            .iter()
-            .map(|it| it.skip_binders())
-            .flat_map(|it| match it {
-                WhereClause::Implemented(tr) => {
-                    all_super_traits(db.upcast(), from_chalk_trait_id(tr.trait_id))
-                }
-                _ => smallvec![],
-            })
-            // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
-            // what the generics are, we are sure that the method is come from the vtable.
-            .any(|x| x == trait_id);
+        let is_my_trait_in_bounds =
+            d.bounds.skip_binders().as_slice(Interner).iter().any(|it| match it.skip_binders() {
+                // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
+                // what the generics are, we are sure that the method is come from the vtable.
+                WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id,
+                _ => false,
+            });
         if is_my_trait_in_bounds {
             return Some(fn_params);
         }
@@ -1512,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.rs b/crates/hir-ty/src/mir.rs
index 922e49d281..df53d239ca 100644
--- a/crates/hir-ty/src/mir.rs
+++ b/crates/hir-ty/src/mir.rs
@@ -3,14 +3,9 @@
 use std::{fmt::Display, iter};
 
 use crate::{
-    consteval::usize_const,
-    db::HirDatabase,
-    display::HirDisplay,
-    infer::{normalize, PointerCast},
-    lang_items::is_box,
-    mapping::ToChalk,
-    CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap,
-    Substitution, TraitEnvironment, Ty, TyKind,
+    consteval::usize_const, db::HirDatabase, display::HirDisplay, infer::PointerCast,
+    lang_items::is_box, mapping::ToChalk, CallableDefId, ClosureId, Const, ConstScalar,
+    InferenceResult, Interner, MemoryMap, Substitution, Ty, TyKind,
 };
 use base_db::CrateId;
 use chalk_ir::Mutability;
@@ -39,7 +34,6 @@ pub use monomorphization::{
 };
 use smallvec::{smallvec, SmallVec};
 use stdx::{impl_from, never};
-use triomphe::Arc;
 
 use super::consteval::{intern_const_scalar, try_const_usize};
 
@@ -137,21 +131,13 @@ pub enum ProjectionElem<V, T> {
 impl<V, T> ProjectionElem<V, T> {
     pub fn projected_ty(
         &self,
-        mut base: Ty,
+        base: Ty,
         db: &dyn HirDatabase,
         closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
         krate: CrateId,
     ) -> Ty {
-        if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) {
-            base = normalize(
-                db,
-                // FIXME: we should get this from caller
-                Arc::new(TraitEnvironment::empty(krate)),
-                base,
-            );
-        }
         match self {
-            ProjectionElem::Deref => match &base.kind(Interner) {
+            ProjectionElem::Deref => match &base.data(Interner).kind {
                 TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
                 TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
                     subst.at(Interner, 0).assert_ty_ref(Interner).clone()
@@ -161,16 +147,17 @@ impl<V, T> ProjectionElem<V, T> {
                     return TyKind::Error.intern(Interner);
                 }
             },
-            ProjectionElem::Field(f) => match &base.kind(Interner) {
+            ProjectionElem::Field(f) => match &base.data(Interner).kind {
                 TyKind::Adt(_, subst) => {
                     db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
                 }
+                TyKind::Alias(inner) => inner.clone().intern(Interner),
                 _ => {
                     never!("Only adt has field");
                     return TyKind::Error.intern(Interner);
                 }
             },
-            ProjectionElem::TupleOrClosureField(f) => match &base.kind(Interner) {
+            ProjectionElem::TupleOrClosureField(f) => match &base.data(Interner).kind {
                 TyKind::Tuple(_, subst) => subst
                     .as_slice(Interner)
                     .get(*f)
@@ -181,13 +168,14 @@ impl<V, T> ProjectionElem<V, T> {
                         TyKind::Error.intern(Interner)
                     }),
                 TyKind::Closure(id, subst) => closure_field(*id, subst, *f),
+                TyKind::Alias(inner) => inner.clone().intern(Interner),
                 _ => {
                     never!("Only tuple or closure has tuple or closure field");
                     return TyKind::Error.intern(Interner);
                 }
             },
             ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
-                match &base.kind(Interner) {
+                match &base.data(Interner).kind {
                     TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
                     _ => {
                         never!("Overloaded index is not a projection");
@@ -195,7 +183,7 @@ impl<V, T> ProjectionElem<V, T> {
                     }
                 }
             }
-            &ProjectionElem::Subslice { from, to } => match &base.kind(Interner) {
+            &ProjectionElem::Subslice { from, to } => match &base.data(Interner).kind {
                 TyKind::Array(inner, c) => {
                     let next_c = usize_const(
                         db,
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 7bd2756c14..d7820de629 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -484,10 +484,9 @@ 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, trait_env);
+    let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused);
     let it: Result<Const> = (|| {
         if evaluator.ptr_size() != std::mem::size_of::<usize>() {
             not_supported!("targets with different pointer size from host");
@@ -513,9 +512,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],
@@ -525,7 +524,7 @@ impl Evaluator<'_> {
             static_locations: HashMap::default(),
             db,
             random_state: oorandom::Rand64::new(0),
-            trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)),
+            trait_env,
             crate_id,
             stdout: vec![],
             stderr: vec![],
@@ -635,7 +634,7 @@ impl Evaluator<'_> {
                     addr = addr.offset(ty_size * offset);
                 }
                 &ProjectionElem::Subslice { from, to } => {
-                    let inner_ty = match &ty.kind(Interner) {
+                    let inner_ty = match &ty.data(Interner).kind {
                         TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
                         _ => TyKind::Error.intern(Interner),
                     };
@@ -695,14 +694,14 @@ impl Evaluator<'_> {
         }
         let r = self
             .db
-            .layout_of_ty(ty.clone(), self.trait_env.clone())
+            .layout_of_ty(ty.clone(), self.crate_id)
             .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.trait_env.clone()).map_err(|e| {
+        self.db.layout_of_adt(adt, subst.clone(), self.crate_id).map_err(|e| {
             MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
         })
     }
@@ -794,7 +793,7 @@ impl Evaluator<'_> {
                                 .iter()
                                 .map(|it| self.operand_ty_and_eval(it, &mut locals))
                                 .collect::<Result<Vec<_>>>()?;
-                            let stack_frame = match &fn_ty.kind(Interner) {
+                            let stack_frame = match &fn_ty.data(Interner).kind {
                                 TyKind::Function(_) => {
                                     let bytes = self.eval_operand(func, &mut locals)?;
                                     self.exec_fn_pointer(
@@ -1256,7 +1255,7 @@ impl Evaluator<'_> {
                     PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => {
                         let current_ty = self.operand_ty(operand, locals)?;
                         if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) =
-                            &current_ty.kind(Interner)
+                            &current_ty.data(Interner).kind
                         {
                             let id = self.vtable_map.id(current_ty);
                             let ptr_size = self.ptr_size();
@@ -1409,8 +1408,8 @@ impl Evaluator<'_> {
         addr: Interval,
     ) -> Result<IntervalOrOwned> {
         use IntervalOrOwned::*;
-        Ok(match &target_ty.kind(Interner) {
-            TyKind::Slice(_) => match &current_ty.kind(Interner) {
+        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 => {
@@ -1436,7 +1435,7 @@ impl Evaluator<'_> {
                 r.extend(vtable.to_le_bytes().into_iter());
                 Owned(r)
             }
-            TyKind::Adt(id, target_subst) => match &current_ty.kind(Interner) {
+            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");
@@ -1583,13 +1582,10 @@ impl Evaluator<'_> {
                     const_id = hir_def::GeneralConstId::ConstId(c);
                     subst = s;
                 }
-                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))
-                    })?;
+                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))
+                })?;
                 if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value {
                     if let ConstScalar::Bytes(v, mm) = &c.interned {
                         break 'b (v, mm);
@@ -1822,13 +1818,9 @@ impl Evaluator<'_> {
                     }
                     AdtId::EnumId(e) => {
                         let layout = this.layout(ty)?;
-                        if let Some((v, l)) = detect_variant_from_bytes(
-                            &layout,
-                            this.db,
-                            this.trait_env.clone(),
-                            bytes,
-                            e,
-                        ) {
+                        if let Some((v, l)) =
+                            detect_variant_from_bytes(&layout, this.db, this.crate_id, bytes, e)
+                        {
                             let data = &this.db.enum_data(e).variants[v].variant_data;
                             let field_types = this
                                 .db
@@ -1939,7 +1931,7 @@ impl Evaluator<'_> {
     ) -> Result<Option<StackFrame>> {
         let id = from_bytes!(usize, bytes.get(self)?);
         let next_ty = self.vtable_map.ty(id)?.clone();
-        match &next_ty.kind(Interner) {
+        match &next_ty.data(Interner).kind {
             TyKind::FnDef(def, generic_args) => {
                 self.exec_fn_def(*def, generic_args, destination, args, &locals, target_bb, span)
             }
@@ -2190,7 +2182,7 @@ impl Evaluator<'_> {
             let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?;
             func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size };
         }
-        match &func_ty.kind(Interner) {
+        match &func_ty.data(Interner).kind {
             TyKind::FnDef(def, subst) => {
                 return self.exec_fn_def(
                     *def,
@@ -2417,7 +2409,7 @@ pub fn render_const_using_debug_impl(
     owner: ConstId,
     c: &Const,
 ) -> Result<String> {
-    let mut evaluator = Evaluator::new(db, owner.into(), false, None);
+    let mut evaluator = Evaluator::new(db, owner.into(), false);
     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 e443c58f22..3610858790 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -633,7 +633,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     );
                 }
                 let callee_ty = self.expr_ty_after_adjustments(*callee);
-                match &callee_ty.kind(Interner) {
+                match &callee_ty.data(Interner).kind {
                     chalk_ir::TyKind::FnDef(..) => {
                         let func = Operand::from_bytes(vec![], callee_ty.clone());
                         self.lower_call_and_args(
@@ -1229,7 +1229,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             }
             Expr::Array(l) => match l {
                 Array::ElementList { elements, .. } => {
-                    let elem_ty = match &self.expr_ty_without_adjust(expr_id).kind(Interner) {
+                    let elem_ty = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind {
                         TyKind::Array(ty, _) => ty.clone(),
                         _ => {
                             return Err(MirLowerError::TypeError(
@@ -1260,7 +1260,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     else {
                         return Ok(None);
                     };
-                    let len = match &self.expr_ty_without_adjust(expr_id).kind(Interner) {
+                    let len = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind {
                         TyKind::Array(_, len) => len.clone(),
                         _ => {
                             return Err(MirLowerError::TypeError(
@@ -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.db.trait_environment_for_body(self.owner))?
+            .layout_of_ty(ty.clone(), self.owner.module(self.db.upcast()).krate())?
             .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, None)
+                .const_eval(const_id.into(), subst)
                 .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 75b8b9afa7..0c38fe5d6a 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -28,15 +28,14 @@ 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, TraitEnvironment,
-    TraitRef, TraitRefExt, Ty, WhereClause,
+    ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
+    Ty, WhereClause,
 };
 
 pub(crate) fn fn_traits(
@@ -418,7 +417,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(), None) {
+                if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
                     return Ok(eval);
                 } else {
                     return Ok(unknown_const(constant.data(Interner).ty.clone()));
@@ -432,11 +431,10 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
 pub(crate) fn detect_variant_from_bytes<'a>(
     layout: &'a Layout,
     db: &dyn HirDatabase,
-    trait_env: Arc<TraitEnvironment>,
+    krate: CrateId,
     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 2b0fdffca9..f8d9398ae2 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -965,15 +965,8 @@ impl Field {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        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()))
+        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()))
     }
 
     pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
@@ -1253,12 +1246,8 @@ impl Adt {
             return Err(LayoutError::HasPlaceholder);
         }
         let krate = self.krate(db).id;
-        db.layout_of_adt(
-            self.into(),
-            Substitution::empty(Interner),
-            db.trait_environment(self.into()),
-        )
-        .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
+        db.layout_of_adt(self.into(), Substitution::empty(Interner), krate)
+            .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
     }
 
     /// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -1998,7 +1987,7 @@ impl Function {
                 return r;
             }
         };
-        let (result, stdout, stderr) = interpret_mir(db, body, false, None);
+        let (result, stdout, stderr) = interpret_mir(db, body, false);
         let mut text = match result {
             Ok(_) => "pass".to_string(),
             Err(e) => {
@@ -2167,7 +2156,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), None)?;
+        let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
         let data = &c.data(Interner);
         if let TyKind::Scalar(s) = data.ty.kind(Interner) {
             if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
@@ -4333,7 +4322,7 @@ impl Type {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        db.layout_of_ty(self.ty.clone(), self.env.clone())
+        db.layout_of_ty(self.ty.clone(), self.env.krate)
             .map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
     }
 }
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index e0c3bedce4..935f12a396 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -1084,33 +1084,6 @@ fn f() {
         );
     }
 
-    #[test]
-    fn regression_15143() {
-        check_diagnostics(
-            r#"
-        trait Tr {
-            type Ty;
-        }
-
-        struct A;
-
-        impl Tr for A {
-            type Ty = (u32, i64);
-        }
-
-        struct B<T: Tr> {
-            f: <T as Tr>::Ty,
-        }
-
-        fn main(b: B<A>) {
-            let f = b.f.0;
-            f = 5;
-          //^^^^^ 💡 error: cannot mutate immutable variable `f`
-        }
-            "#,
-        );
-    }
-
     #[test]
     fn allow_unused_mut_for_identifiers_starting_with_underline() {
         check_diagnostics(
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/proc-macro-api/src/version.rs b/crates/proc-macro-api/src/version.rs
index 48efbf589c..13f67a0128 100644
--- a/crates/proc-macro-api/src/version.rs
+++ b/crates/proc-macro-api/src/version.rs
@@ -135,12 +135,7 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
         }
     };
 
-    let mut uncompressed: Box<dyn Read> = if &snappy_portion[0..4] == b"rust" {
-        // Not compressed.
-        Box::new(snappy_portion)
-    } else {
-        Box::new(SnapDecoder::new(snappy_portion))
-    };
+    let mut snappy_decoder = SnapDecoder::new(snappy_portion);
 
     // the bytes before version string bytes, so this basically is:
     // 8 bytes for [b'r',b'u',b's',b't',0,0,0,5]
@@ -149,11 +144,11 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> {
     // so 13 bytes in total, and we should check the 13th byte
     // to know the length
     let mut bytes_before_version = [0u8; 13];
-    uncompressed.read_exact(&mut bytes_before_version)?;
+    snappy_decoder.read_exact(&mut bytes_before_version)?;
     let length = bytes_before_version[12];
 
     let mut version_string_utf8 = vec![0u8; length as usize];
-    uncompressed.read_exact(&mut version_string_utf8)?;
+    snappy_decoder.read_exact(&mut version_string_utf8)?;
     let version_string = String::from_utf8(version_string_utf8);
     version_string.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
 }
diff --git a/crates/proc-macro-srv/src/server.rs b/crates/proc-macro-srv/src/server.rs
index 1980d4c78b..6fd8de5934 100644
--- a/crates/proc-macro-srv/src/server.rs
+++ b/crates/proc-macro-srv/src/server.rs
@@ -8,7 +8,10 @@
 //!
 //! FIXME: No span and source file information is implemented yet
 
-use proc_macro::bridge::{self, server};
+use proc_macro::{
+    bridge::{self, server},
+    LineColumn,
+};
 
 mod token_stream;
 pub use token_stream::TokenStream;
@@ -301,6 +304,14 @@ impl server::Span for RustAnalyzer {
         // FIXME handle span
         Range { start: 0, end: 0 }
     }
+    fn start(&mut self, _span: Self::Span) -> LineColumn {
+        // FIXME handle span
+        LineColumn { line: 0, column: 0 }
+    }
+    fn end(&mut self, _span: Self::Span) -> LineColumn {
+        // FIXME handle span
+        LineColumn { line: 0, column: 0 }
+    }
     fn join(&mut self, first: Self::Span, _second: Self::Span) -> Option<Self::Span> {
         // Just return the first span again, because some macros will unwrap the result.
         Some(first)
@@ -319,23 +330,13 @@ impl server::Span for RustAnalyzer {
         tt::TokenId::unspecified()
     }
 
-    fn end(&mut self, _self_: Self::Span) -> Self::Span {
+    fn after(&mut self, _self_: Self::Span) -> Self::Span {
         tt::TokenId::unspecified()
     }
 
-    fn start(&mut self, _self_: Self::Span) -> Self::Span {
+    fn before(&mut self, _self_: Self::Span) -> Self::Span {
         tt::TokenId::unspecified()
     }
-
-    fn line(&mut self, _span: Self::Span) -> usize {
-        // FIXME handle line
-        0
-    }
-
-    fn column(&mut self, _span: Self::Span) -> usize {
-        // FIXME handle column
-        0
-    }
 }
 
 impl server::Symbol for RustAnalyzer {
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 33d7b5ed87..8d68bf160a 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, HasSource, HirDisplay, ModuleDef, Name,
+    Adt, AssocItem, Crate, DefWithBody, HasCrate, 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),
-                db.trait_environment(a.into()),
+                a.krate(db).into(),
             ) else {
                 continue;
             };
diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs
index 13b7f039bb..31be535fc2 100644
--- a/crates/rust-analyzer/src/cli/flags.rs
+++ b/crates/rust-analyzer/src/cli/flags.rs
@@ -12,7 +12,7 @@ xflags::xflags! {
     /// LSP server for the Rust programming language.
     ///
     /// Subcommands and their flags do not provide any stability guarantees and may be removed or
-    /// changed without notice. Top-level flags that are not marked as [Unstable] provide
+    /// changed without notice. Top-level flags that are not are marked as [Unstable] provide
     /// backwards-compatibility and may be relied on.
     cmd rust-analyzer {
         /// Verbosity level, can be repeated multiple times.
@@ -113,7 +113,7 @@ xflags::xflags! {
         }
 
         cmd ssr {
-            /// A structured search replace rule (`$a.foo($b) ==>> bar($a, $b)`)
+            /// A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)
             repeated rule: SsrRule
         }
 
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 2cf985adab..31035c4b72 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -449,24 +449,27 @@ You'll need to close and reopen all .rs and Cargo files, or to restart the IDE,
 Support for the language server protocol is built into Kate through the LSP plugin, which is included by default.
 It is preconfigured to use rust-analyzer for Rust sources since Kate 21.12.
 
-To change rust-analyzer config options, start from the following example and put it into Kate's "User Server Settings" tab (located under the LSP Client settings):
+Earlier versions allow you to use rust-analyzer through a simple settings change.
+In the LSP Client settings of Kate, copy the content of the third tab "default parameters" to the second tab "server configuration".
+Then in the configuration replace:
 [source,json]
 ----
-{
-    "servers": {
         "rust": {
-            "initializationOptions": {
-                "cachePriming": {
-                    "enable": false
-                },
-                "check": {
-                    "allTargets": false
-                },
-                "checkOnSave": false
-            }
-        }
-    }
-}
+            "command": ["rls"],
+            "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
+            "url": "https://github.com/rust-lang/rls",
+            "highlightingModeRegex": "^Rust$"
+        },
+----
+With
+[source,json]
+----
+        "rust": {
+            "command": ["rust-analyzer"],
+            "rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
+            "url": "https://github.com/rust-lang/rust-analyzer",
+            "highlightingModeRegex": "^Rust$"
+        },
 ----
 Then click on apply, and restart the LSP server for your rust project.
 
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index f3d6238d51..e817d680ea 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -66,6 +66,12 @@ export async function startDebugSession(ctx: Ctx, runnable: ra.Runnable): Promis
     return vscode.debug.startDebugging(undefined, debugConfig);
 }
 
+function createCommandLink(extensionId: string): string {
+    // do not remove the second quotes inside
+    // encodeURIComponent or it won't work
+    return `extension.open?${encodeURIComponent(`"${extensionId}"`)}`;
+}
+
 async function getDebugConfiguration(
     ctx: Ctx,
     runnable: ra.Runnable,
@@ -90,9 +96,12 @@ async function getDebugConfiguration(
     }
 
     if (!debugEngine) {
+        const commandCodeLLDB: string = createCommandLink("vadimcn.vscode-lldb");
+        const commandCpp: string = createCommandLink("ms-vscode.cpptools");
+
         await vscode.window.showErrorMessage(
-            `Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)` +
-                ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`,
+            `Install [CodeLLDB](command:${commandCodeLLDB} "Open CodeLLDB")` +
+                ` or [C/C++](command:${commandCpp} "Open C/C++") extension for debugging.`,
         );
         return;
     }
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 7a34617e25..b4b294c309 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 publish = false
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version.workspace = true
+rust-version = "1.65"
 
 [dependencies]
 anyhow = "1.0.62"


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 98ebe55724..5bb327606d 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), None)
+    db.const_eval(const_id.into(), Substitution::empty(Interner))
 }
 
 #[test]
@@ -1941,33 +1941,6 @@ fn dyn_trait() {
         "#,
         900,
     );
-    check_number(
-        r#"
-    //- minicore: coerce_unsized, index, slice
-    trait A {
-        fn x(&self) -> i32;
-    }
-
-    trait B: A {}
-
-    impl A for i32 {
-        fn x(&self) -> i32 {
-            5
-        }
-    }
-
-    impl B for i32 {
-
-    }
-
-    const fn f(x: &dyn B) -> i32 {
-        x.x()
-    }
-
-    const GOAL: i32 = f(&2i32);
-        "#,
-        5,
-    );
 }
 
 #[test]
@@ -2519,28 +2492,6 @@ 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 333ad473a8..a3ced2bac0 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 = file_ids
+    let (adt_or_type_alias_id, module_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)
+            Some((adt_or_type_alias_id, module_id))
         })
         .unwrap();
     let goal_ty = match adt_or_type_alias_id {
@@ -58,13 +58,7 @@ 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,
-        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),
-        }),
-    )
+    db.layout_of_ty(goal_ty, module_id.krate())
 }
 
 /// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
@@ -78,7 +72,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 function_id = scope
+    let adt_id = scope
         .declarations()
         .find_map(|x| match x {
             hir_def::ModuleDefId::FunctionId(x) => {
@@ -88,11 +82,11 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
             _ => None,
         })
         .unwrap();
-    let hir_body = db.body(function_id.into());
+    let hir_body = db.body(adt_id.into());
     let b = hir_body.bindings.iter().find(|x| x.1.name.to_smol_str() == "goal").unwrap().0;
-    let infer = db.infer(function_id.into());
+    let infer = db.infer(adt_id.into());
     let goal_ty = infer.type_of_binding[b].clone();
-    db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))
+    db.layout_of_ty(goal_ty, module_id.krate())
 }
 
 #[track_caller]
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 93f4b69914..03c083bac4 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, None);
+    let (result, stdout, stderr) = interpret_mir(db, body, false);
     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(); }