Repository: rust-lang/rust-analyzer
Pull request #15353 (2023-07-28 15:28:06)

Add manual implementation of clone for tuples in mir interpreter
And some other minor changes.

Clone for tuple is not implemented in the std and it is magically implemented by the compiler, so we need this.



Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 9f246098e7..31bb7eed8d 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -161,21 +161,10 @@ jobs:
       #      if: runner.os == 'Linux'
       #      working-directory: ./editors/code
 
-      # If this steps fails, your code's type integrity might be wrong at some places at TypeScript level.
-      - run: npm run typecheck
-        working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
-
-      # You may fix the code automatically by running `npm run lint:fix` if this steps fails.
       - run: npm run lint
         working-directory: ./editors/code
         if: needs.changes.outputs.typescript == 'true'
 
-      # To fix this steps, please run `npm run format`.
-      - run: npm run format:check
-        working-directory: ./editors/code
-        if: needs.changes.outputs.typescript == 'true'
-
       - name: Run VS Code tests (Linux)
         if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true'
         env:
@@ -190,6 +179,10 @@ jobs:
         run: npm test
         working-directory: ./editors/code
 
+      - run: npm run pretest
+        working-directory: ./editors/code
+        if: needs.changes.outputs.typescript == 'true'
+
       - run: npm run package --scripts-prepend-node-path
         working-directory: ./editors/code
         if: needs.changes.outputs.typescript == 'true'
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index eeaed87164..0c6cf0b49a 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -634,7 +634,7 @@ impl Printer<'_> {
         match literal {
             Literal::String(it) => w!(self, "{:?}", it),
             Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
-            Literal::CString(it) => w!(self, "\"{}\\0\"", it.escape_ascii()),
+            Literal::CString(it) => w!(self, "\"{}\\0\"", it),
             Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
             Literal::Bool(it) => w!(self, "{}", it),
             Literal::Int(i, suffix) => {
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index 8a140a1ec1..500e880061 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -85,7 +85,7 @@ impl fmt::Display for FloatTypeWrapper {
 pub enum Literal {
     String(Box<str>),
     ByteString(Box<[u8]>),
-    CString(Box<[u8]>),
+    CString(Box<str>),
     Char(char),
     Bool(bool),
     Int(i128, Option<BuiltinInt>),
diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs
index 5aaa2bcc7c..73c8ad3dd5 100644
--- a/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -14,12 +14,13 @@ mod case_conv;
 
 use std::fmt;
 
+use base_db::CrateId;
 use hir_def::{
     data::adt::VariantData,
     hir::{Pat, PatId},
     src::HasSource,
-    AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId,
-    Lookup, ModuleDefId, StaticId, StructId,
+    AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, StaticId,
+    StructId,
 };
 use hir_expand::{
     name::{AsName, Name},
@@ -43,9 +44,13 @@ mod allow {
     pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
 }
 
-pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
+pub fn incorrect_case(
+    db: &dyn HirDatabase,
+    krate: CrateId,
+    owner: ModuleDefId,
+) -> Vec<IncorrectCase> {
     let _p = profile::span("validate_module_item");
-    let mut validator = DeclValidator::new(db);
+    let mut validator = DeclValidator::new(db, krate);
     validator.validate_item(owner);
     validator.sink
 }
@@ -115,6 +120,7 @@ pub struct IncorrectCase {
 
 pub(super) struct DeclValidator<'a> {
     db: &'a dyn HirDatabase,
+    krate: CrateId,
     pub(super) sink: Vec<IncorrectCase>,
 }
 
@@ -126,8 +132,8 @@ struct Replacement {
 }
 
 impl<'a> DeclValidator<'a> {
-    pub(super) fn new(db: &'a dyn HirDatabase) -> DeclValidator<'a> {
-        DeclValidator { db, sink: Vec::new() }
+    pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
+        DeclValidator { db, krate, sink: Vec::new() }
     }
 
     pub(super) fn validate_item(&mut self, item: ModuleDefId) {
@@ -189,7 +195,8 @@ impl<'a> DeclValidator<'a> {
                 AttrDefId::TypeAliasId(_) => None,
                 AttrDefId::GenericParamId(_) => None,
             }
-            .is_some_and(|mid| self.allowed(mid, allow_name, true))
+            .map(|mid| self.allowed(mid, allow_name, true))
+            .unwrap_or(false)
     }
 
     fn validate_func(&mut self, func: FunctionId) {
@@ -199,7 +206,17 @@ impl<'a> DeclValidator<'a> {
             return;
         }
 
-        self.validate_body_inner_items(func.into());
+        let body = self.db.body(func.into());
+
+        // Recursively validate inner scope items, such as static variables and constants.
+        for (_, block_def_map) in body.blocks(self.db.upcast()) {
+            for (_, module) in block_def_map.modules() {
+                for def_id in module.scope.declarations() {
+                    let mut validator = DeclValidator::new(self.db, self.krate);
+                    validator.validate_item(def_id);
+                }
+            }
+        }
 
         // Check whether non-snake case identifiers are allowed for this function.
         if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
@@ -214,8 +231,6 @@ impl<'a> DeclValidator<'a> {
             expected_case: CaseType::LowerSnakeCase,
         });
 
-        let body = self.db.body(func.into());
-
         // Check the patterns inside the function body.
         // This includes function parameters.
         let pats_replacements = body
@@ -481,11 +496,6 @@ impl<'a> DeclValidator<'a> {
     fn validate_enum(&mut self, enum_id: EnumId) {
         let data = self.db.enum_data(enum_id);
 
-        for (local_id, _) in data.variants.iter() {
-            let variant_id = EnumVariantId { parent: enum_id, local_id };
-            self.validate_body_inner_items(variant_id.into());
-        }
-
         // Check whether non-camel case names are allowed for this enum.
         if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
             return;
@@ -502,11 +512,13 @@ impl<'a> DeclValidator<'a> {
         // Check the field names.
         let enum_fields_replacements = data
             .variants
-            .values()
-            .filter_map(|variant| {
+            .iter()
+            .filter_map(|(_, variant)| {
                 Some(Replacement {
                     current_name: variant.name.clone(),
-                    suggested_text: to_camel_case(&variant.name.to_smol_str())?,
+                    suggested_text: to_camel_case(
+                        &variant.name.display(self.db.upcast()).to_string(),
+                    )?,
                     expected_case: CaseType::UpperCamelCase,
                 })
             })
@@ -610,8 +622,6 @@ impl<'a> DeclValidator<'a> {
     fn validate_const(&mut self, const_id: ConstId) {
         let data = self.db.const_data(const_id);
 
-        self.validate_body_inner_items(const_id.into());
-
         if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
             return;
         }
@@ -621,7 +631,7 @@ impl<'a> DeclValidator<'a> {
             None => return,
         };
 
-        let const_name = name.to_smol_str();
+        let const_name = name.display(self.db.upcast()).to_string();
         let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) {
             Replacement {
                 current_name: name.clone(),
@@ -660,15 +670,13 @@ impl<'a> DeclValidator<'a> {
             return;
         }
 
-        self.validate_body_inner_items(static_id.into());
-
         if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
             return;
         }
 
         let name = &data.name;
 
-        let static_name = name.to_smol_str();
+        let static_name = name.display(self.db.upcast()).to_string();
         let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) {
             Replacement {
                 current_name: name.clone(),
@@ -699,17 +707,4 @@ impl<'a> DeclValidator<'a> {
 
         self.sink.push(diagnostic);
     }
-
-    // FIXME: We don't currently validate names within `DefWithBodyId::InTypeConstId`.
-    /// Recursively validates inner scope items, such as static variables and constants.
-    fn validate_body_inner_items(&mut self, body_id: DefWithBodyId) {
-        let body = self.db.body(body_id);
-        for (_, block_def_map) in body.blocks(self.db.upcast()) {
-            for (_, module) in block_def_map.modules() {
-                for def_id in module.scope.declarations() {
-                    self.validate_item(def_id);
-                }
-            }
-        }
-    }
 }
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 1b4ee4613d..96787959e1 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -48,15 +48,22 @@ use crate::{
 };
 
 pub trait HirWrite: fmt::Write {
-    fn start_location_link(&mut self, _location: ModuleDefId) {}
-    fn end_location_link(&mut self) {}
+    fn start_location_link(&mut self, location: ModuleDefId);
+    fn end_location_link(&mut self);
 }
 
 // String will ignore link metadata
-impl HirWrite for String {}
+impl HirWrite for String {
+    fn start_location_link(&mut self, _: ModuleDefId) {}
+
+    fn end_location_link(&mut self) {}
+}
 
 // `core::Formatter` will ignore metadata
-impl HirWrite for fmt::Formatter<'_> {}
+impl HirWrite for fmt::Formatter<'_> {
+    fn start_location_link(&mut self, _: ModuleDefId) {}
+    fn end_location_link(&mut self) {}
+}
 
 pub struct HirFormatter<'a> {
     pub db: &'a dyn HirDatabase,
@@ -878,13 +885,6 @@ impl HirDisplay for Ty {
             TyKind::FnDef(def, parameters) => {
                 let def = from_chalk(db, *def);
                 let sig = db.callable_item_signature(def).substitute(Interner, parameters);
-
-                if f.display_target.is_source_code() {
-                    // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
-                    // function pointer type.
-                    return sig.hir_fmt(f);
-                }
-
                 f.start_location_link(def.into());
                 match def {
                     CallableDefId::FunctionId(ff) => {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index b4915dbf0f..0a617dae7d 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -13,15 +13,6 @@
 //! to certain types. To record this, we use the union-find implementation from
 //! the `ena` crate, which is extracted from rustc.
 
-mod cast;
-pub(crate) mod closure;
-mod coerce;
-mod expr;
-mod mutability;
-mod pat;
-mod path;
-pub(crate) mod unify;
-
 use std::{convert::identity, ops::Index};
 
 use chalk_ir::{
@@ -69,8 +60,15 @@ pub use coerce::could_coerce;
 #[allow(unreachable_pub)]
 pub use unify::could_unify;
 
-use cast::CastCheck;
-pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
+pub(crate) use self::closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
+
+pub(crate) mod unify;
+mod path;
+mod expr;
+mod pat;
+mod coerce;
+pub(crate) mod closure;
+mod mutability;
 
 /// The entry point of type inference.
 pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
@@ -510,8 +508,6 @@ pub(crate) struct InferenceContext<'a> {
     diverges: Diverges,
     breakables: Vec<BreakableContext>,
 
-    deferred_cast_checks: Vec<CastCheck>,
-
     // fields related to closure capture
     current_captures: Vec<CapturedItemWithoutTy>,
     current_closure: Option<ClosureId>,
@@ -586,8 +582,7 @@ impl<'a> InferenceContext<'a> {
             resolver,
             diverges: Diverges::Maybe,
             breakables: Vec::new(),
-            deferred_cast_checks: Vec::new(),
-            current_captures: Vec::new(),
+            current_captures: vec![],
             current_closure: None,
             deferred_closures: FxHashMap::default(),
             closure_dependencies: FxHashMap::default(),
@@ -599,7 +594,7 @@ impl<'a> InferenceContext<'a> {
     // used this function for another workaround, mention it here. If you really need this function and believe that
     // there is no problem in it being `pub(crate)`, remove this comment.
     pub(crate) fn resolve_all(self) -> InferenceResult {
-        let InferenceContext { mut table, mut result, deferred_cast_checks, .. } = self;
+        let InferenceContext { mut table, mut result, .. } = self;
         // Destructure every single field so whenever new fields are added to `InferenceResult` we
         // don't forget to handle them here.
         let InferenceResult {
@@ -627,13 +622,6 @@ impl<'a> InferenceContext<'a> {
 
         table.fallback_if_possible();
 
-        // Comment from rustc:
-        // Even though coercion casts provide type hints, we check casts after fallback for
-        // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
-        for cast in deferred_cast_checks {
-            cast.check(&mut table);
-        }
-
         // FIXME resolve obligations as well (use Guidance if necessary)
         table.resolve_obligations_as_possible();
 
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
deleted file mode 100644
index 9e1c74b16f..0000000000
--- a/crates/hir-ty/src/infer/cast.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-//! Type cast logic. Basically coercion + additional casts.
-
-use crate::{infer::unify::InferenceTable, Interner, Ty, TyExt, TyKind};
-
-#[derive(Clone, Debug)]
-pub(super) struct CastCheck {
-    expr_ty: Ty,
-    cast_ty: Ty,
-}
-
-impl CastCheck {
-    pub(super) fn new(expr_ty: Ty, cast_ty: Ty) -> Self {
-        Self { expr_ty, cast_ty }
-    }
-
-    pub(super) fn check(self, table: &mut InferenceTable<'_>) {
-        // FIXME: This function currently only implements the bits that influence the type
-        // inference. We should return the adjustments on success and report diagnostics on error.
-        let expr_ty = table.resolve_ty_shallow(&self.expr_ty);
-        let cast_ty = table.resolve_ty_shallow(&self.cast_ty);
-
-        if expr_ty.contains_unknown() || cast_ty.contains_unknown() {
-            return;
-        }
-
-        if table.coerce(&expr_ty, &cast_ty).is_ok() {
-            return;
-        }
-
-        if check_ref_to_ptr_cast(expr_ty, cast_ty, table) {
-            // Note that this type of cast is actually split into a coercion to a
-            // pointer type and a cast:
-            // &[T; N] -> *[T; N] -> *T
-            return;
-        }
-
-        // FIXME: Check other kinds of non-coercion casts and report error if any?
-    }
-}
-
-fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool {
-    let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { return false; };
-    let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { return false; };
-    let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { return false; };
-    table.coerce(expr_elt_ty, cast_inner_ty).is_ok()
-}
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 501c0b4bd7..72e6443beb 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -46,8 +46,8 @@ use crate::{
 };
 
 use super::{
-    cast::CastCheck, coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges,
-    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
+    coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges, Expectation,
+    InferenceContext, InferenceDiagnostic, TypeMismatch,
 };
 
 impl InferenceContext<'_> {
@@ -574,8 +574,16 @@ impl InferenceContext<'_> {
             }
             Expr::Cast { expr, type_ref } => {
                 let cast_ty = self.make_ty(type_ref);
-                let expr_ty = self.infer_expr(*expr, &Expectation::Castable(cast_ty.clone()));
-                self.deferred_cast_checks.push(CastCheck::new(expr_ty, cast_ty.clone()));
+                // FIXME: propagate the "castable to" expectation
+                let inner_ty = self.infer_expr_no_expect(*expr);
+                match (inner_ty.kind(Interner), cast_ty.kind(Interner)) {
+                    (TyKind::Ref(_, _, inner), TyKind::Raw(_, cast)) => {
+                        // FIXME: record invalid cast diagnostic in case of mismatch
+                        self.unify(inner, cast);
+                    }
+                    // FIXME check the other kinds of cast...
+                    _ => (),
+                }
                 cast_ty
             }
             Expr::Ref { expr, rawness, mutability } => {
@@ -1584,7 +1592,7 @@ impl InferenceContext<'_> {
         output: Ty,
         inputs: Vec<Ty>,
     ) -> Vec<Ty> {
-        if let Some(expected_ty) = expected_output.only_has_type(&mut self.table) {
+        if let Some(expected_ty) = expected_output.to_option(&mut self.table) {
             self.table.fudge_inference(|table| {
                 if table.try_unify(&expected_ty, &output).is_ok() {
                     table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind {
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index ffc7a6f2eb..b15339d443 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -14,7 +14,7 @@ use triomphe::Arc;
 
 use crate::{
     consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
-    utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty,
+    utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
 };
 
 pub use self::{
@@ -279,7 +279,15 @@ pub fn layout_of_ty_query(
             //     return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
             // }
 
-            let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
+            let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
+            if let TyKind::AssociatedType(id, subst) = unsized_part.kind(Interner) {
+                unsized_part = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
+                    associated_ty_id: *id,
+                    substitution: subst.clone(),
+                }))
+                .intern(Interner);
+            }
+            unsized_part = normalize(db, trait_env.clone(), unsized_part);
             let metadata = match unsized_part.kind(Interner) {
                 TyKind::Slice(_) | TyKind::Str => {
                     scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
@@ -362,8 +370,16 @@ pub fn layout_of_ty_query(
             return Err(LayoutError::NotImplemented)
         }
         TyKind::Error => return Err(LayoutError::HasErrorType),
-        TyKind::AssociatedType(_, _)
-        | TyKind::Alias(_)
+        TyKind::AssociatedType(id, subst) => {
+            // Try again with `TyKind::Alias` to normalize the associated type.
+            let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy {
+                associated_ty_id: *id,
+                substitution: subst.clone(),
+            }))
+            .intern(Interner);
+            return db.layout_of_ty(ty, trait_env);
+        }
+        TyKind::Alias(_)
         | TyKind::Placeholder(_)
         | TyKind::BoundVar(_)
         | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index f3a5f69b2a..95ebc70627 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -1512,7 +1512,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 7bd2756c14..2d5d7c7b1f 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -313,6 +313,7 @@ pub enum MirEvalError {
     InvalidVTableId(usize),
     CoerceUnsizedError(Ty),
     LangItemNotFound(LangItem),
+    BrokenLayout(Layout),
 }
 
 impl MirEvalError {
@@ -399,6 +400,7 @@ impl MirEvalError {
             | MirEvalError::TargetDataLayoutNotAvailable
             | MirEvalError::CoerceUnsizedError(_)
             | MirEvalError::LangItemNotFound(_)
+            | MirEvalError::BrokenLayout(_)
             | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?,
         }
         Ok(())
@@ -433,6 +435,7 @@ impl std::fmt::Debug for MirEvalError {
             Self::CoerceUnsizedError(arg0) => {
                 f.debug_tuple("CoerceUnsizedError").field(arg0).finish()
             }
+            Self::BrokenLayout(arg0) => f.debug_tuple("BrokenLayout").field(arg0).finish(),
             Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(),
             Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(),
             Self::InvalidConst(arg0) => {
@@ -702,9 +705,7 @@ impl Evaluator<'_> {
     }
 
     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| {
-            MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
-        })
+        self.layout(&TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
     }
 
     fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<Ty> {
@@ -1543,12 +1544,18 @@ impl Evaluator<'_> {
     ) -> Result<Vec<u8>> {
         let mut result = vec![0; size];
         if let Some((offset, size, value)) = tag {
-            result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]);
+            match result.get_mut(offset..offset + size) {
+                Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]),
+                None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+            }
         }
         for (i, op) in values.enumerate() {
             let offset = variant_layout.fields.offset(i).bytes_usize();
             let op = op.get(&self)?;
-            result[offset..offset + op.len()].copy_from_slice(op);
+            match result.get_mut(offset..offset + op.len()) {
+                Some(it) => it.copy_from_slice(op),
+                None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())),
+            }
         }
         Ok(result)
     }
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 9ad6087cad..356bf70a5f 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -124,9 +124,85 @@ impl Evaluator<'_> {
             destination.write_from_bytes(self, &result)?;
             return Ok(true);
         }
+        if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container {
+            if self.db.lang_attr(t.into()) == Some(LangItem::Clone) {
+                let [self_ty] = generic_args.as_slice(Interner) else {
+                    not_supported!("wrong generic arg count for clone");
+                };
+                let Some(self_ty) = self_ty.ty(Interner) else {
+                    not_supported!("wrong generic arg kind for clone");
+                };
+                // Clone has special impls for tuples and function pointers
+                if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) {
+                    self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?;
+                    return Ok(true);
+                }
+            }
+        }
         Ok(false)
     }
 
+    /// Clone has special impls for tuples and function pointers
+    fn exec_clone(
+        &mut self,
+        def: FunctionId,
+        args: &[IntervalAndTy],
+        self_ty: Ty,
+        locals: &Locals,
+        destination: Interval,
+        span: MirSpan,
+    ) -> Result<()> {
+        match self_ty.kind(Interner) {
+            TyKind::Function(_) => {
+                let [arg] = args else {
+                    not_supported!("wrong arg count for clone");
+                };
+                let addr = Address::from_bytes(arg.get(self)?)?;
+                return destination
+                    .write_from_interval(self, Interval { addr, size: destination.size });
+            }
+            TyKind::Tuple(_, subst) => {
+                let [arg] = args else {
+                    not_supported!("wrong arg count for clone");
+                };
+                let addr = Address::from_bytes(arg.get(self)?)?;
+                let layout = self.layout(&self_ty)?;
+                for (i, ty) in subst.iter(Interner).enumerate() {
+                    let ty = ty.assert_ty_ref(Interner);
+                    let size = self.layout(ty)?.size.bytes_usize();
+                    let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?;
+                    let arg = IntervalAndTy {
+                        interval: Interval { addr: tmp, size: self.ptr_size() },
+                        ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone())
+                            .intern(Interner),
+                    };
+                    let offset = layout.fields.offset(i).bytes_usize();
+                    self.write_memory(tmp, &addr.offset(offset).to_bytes())?;
+                    self.exec_clone(
+                        def,
+                        &[arg],
+                        ty.clone(),
+                        locals,
+                        destination.slice(offset..offset + size),
+                        span,
+                    )?;
+                }
+            }
+            _ => {
+                self.exec_fn_with_args(
+                    def,
+                    args,
+                    Substitution::from1(Interner, self_ty),
+                    locals,
+                    destination,
+                    None,
+                    span,
+                )?;
+            }
+        }
+        Ok(())
+    }
+
     fn exec_alloc_fn(
         &mut self,
         alloc_fn: &str,
@@ -1057,7 +1133,14 @@ impl Evaluator<'_> {
         _span: MirSpan,
     ) -> Result<()> {
         // We are a single threaded runtime with no UB checking and no optimization, so
-        // we can implement these as normal functions.
+        // we can implement atomic intrinsics as normal functions.
+
+        if name.starts_with("singlethreadfence_") || name.starts_with("fence_") {
+            return Ok(());
+        }
+
+        // The rest of atomic intrinsics have exactly one generic arg
+
         let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
             return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided"));
         };
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 9f25175a3a..2325426ff5 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -660,6 +660,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
                             expr_id.into(),
                         )
                     }
+                    TyKind::Closure(_, _) => {
+                        not_supported!(
+                            "method resolution not emitted for closure (Are Fn traits available?)"
+                        );
+                    }
                     TyKind::Error => {
                         return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id))
                     }
@@ -1355,6 +1360,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 return Ok(Operand::from_concrete_const(data, mm, ty));
             }
             hir_def::hir::Literal::CString(b) => {
+                let b = b.as_bytes();
                 let bytes = b.iter().copied().chain(iter::once(0)).collect::<Vec<_>>();
 
                 let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b094bb7a06..2b0fdffca9 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -378,6 +378,11 @@ impl ModuleDef {
             ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
         };
 
+        let module = match self.module(db) {
+            Some(it) => it,
+            None => return Vec::new(),
+        };
+
         let mut acc = Vec::new();
 
         match self.as_def_with_body() {
@@ -385,7 +390,7 @@ impl ModuleDef {
                 def.diagnostics(db, &mut acc);
             }
             None => {
-                for diag in hir_ty::diagnostics::incorrect_case(db, id) {
+                for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
                     acc.push(diag.into())
                 }
             }
@@ -1826,7 +1831,7 @@ impl DefWithBody {
             // FIXME: don't ignore diagnostics for in type const
             DefWithBody::InTypeConst(_) => return,
         };
-        for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) {
+        for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
             acc.push(diag.into())
         }
     }
diff --git a/crates/ide-assists/src/handlers/change_visibility.rs b/crates/ide-assists/src/handlers/change_visibility.rs
index e6179ab8b1..2b1d8f6f01 100644
--- a/crates/ide-assists/src/handlers/change_visibility.rs
+++ b/crates/ide-assists/src/handlers/change_visibility.rs
@@ -2,10 +2,9 @@ use syntax::{
     ast::{self, HasName, HasVisibility},
     AstNode,
     SyntaxKind::{
-        self, ASSOC_ITEM_LIST, CONST, ENUM, FN, MACRO_DEF, MODULE, SOURCE_FILE, STATIC, STRUCT,
-        TRAIT, TYPE_ALIAS, USE, VISIBILITY,
+        CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY,
     },
-    SyntaxNode, T,
+    T,
 };
 
 use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
@@ -47,11 +46,13 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
 
     let (offset, target) = if let Some(keyword) = item_keyword {
         let parent = keyword.parent()?;
-
-        if !can_add(&parent) {
+        let def_kws =
+            vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
+        // Parent is not a definition, can't add visibility
+        if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
             return None;
         }
-        // Already has visibility, do nothing
+        // Already have visibility, do nothing
         if parent.children().any(|child| child.kind() == VISIBILITY) {
             return None;
         }
@@ -85,29 +86,6 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     )
 }
 
-fn can_add(node: &SyntaxNode) -> bool {
-    const LEGAL: &[SyntaxKind] =
-        &[CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
-
-    LEGAL.contains(&node.kind()) && {
-        let Some(p) = node.parent() else {
-            return false;
-        };
-
-        if p.kind() == ASSOC_ITEM_LIST {
-            p.parent()
-                .and_then(|it| ast::Impl::cast(it))
-                // inherent impls i.e 'non-trait impls' have a non-local
-                // effect, thus can have visibility even when nested.
-                // so filter them out
-                .filter(|imp| imp.for_token().is_none())
-                .is_some()
-        } else {
-            matches!(p.kind(), SOURCE_FILE | MODULE)
-        }
-    }
-}
-
 fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
     if vis.syntax().text() == "pub" {
         let target = vis.syntax().text_range();
@@ -151,16 +129,6 @@ mod tests {
         check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}");
         check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}");
         check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;");
-        check_assist(
-            change_visibility,
-            "impl Foo { f$0n foo() {} }",
-            "impl Foo { pub(crate) fn foo() {} }",
-        );
-        check_assist(
-            change_visibility,
-            "fn bar() { impl Foo { f$0n foo() {} } }",
-            "fn bar() { impl Foo { pub(crate) fn foo() {} } }",
-        );
     }
 
     #[test]
@@ -245,33 +213,4 @@ mod tests {
         check_assist_target(change_visibility, "pub(crate)$0 fn foo() {}", "pub(crate)");
         check_assist_target(change_visibility, "struct S { $0field: u32 }", "field");
     }
-
-    #[test]
-    fn not_applicable_for_items_within_traits() {
-        check_assist_not_applicable(change_visibility, "trait Foo { f$0n run() {} }");
-        check_assist_not_applicable(change_visibility, "trait Foo { con$0st FOO: u8 = 69; }");
-        check_assist_not_applicable(change_visibility, "impl Foo for Bar { f$0n quox() {} }");
-    }
-
-    #[test]
-    fn not_applicable_for_items_within_fns() {
-        check_assist_not_applicable(change_visibility, "fn foo() { f$0n inner() {} }");
-        check_assist_not_applicable(change_visibility, "fn foo() { unsafe f$0n inner() {} }");
-        check_assist_not_applicable(change_visibility, "fn foo() { const f$0n inner() {} }");
-        check_assist_not_applicable(change_visibility, "fn foo() { con$0st FOO: u8 = 69; }");
-        check_assist_not_applicable(change_visibility, "fn foo() { en$0um Foo {} }");
-        check_assist_not_applicable(change_visibility, "fn foo() { stru$0ct Foo {} }");
-        check_assist_not_applicable(change_visibility, "fn foo() { mo$0d foo {} }");
-        check_assist_not_applicable(change_visibility, "fn foo() { $0use foo; }");
-        check_assist_not_applicable(change_visibility, "fn foo() { $0type Foo = Bar<T>; }");
-        check_assist_not_applicable(change_visibility, "fn foo() { tr$0ait Foo {} }");
-        check_assist_not_applicable(
-            change_visibility,
-            "fn foo() { impl Trait for Bar { f$0n bar() {} } }",
-        );
-        check_assist_not_applicable(
-            change_visibility,
-            "fn foo() { impl Trait for Bar { con$0st FOO: u8 = 69; } }",
-        );
-    }
 }
diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs
index 5b13e01b13..8085572497 100644
--- a/crates/ide-assists/src/handlers/generate_function.rs
+++ b/crates/ide-assists/src/handlers/generate_function.rs
@@ -1878,6 +1878,7 @@ where
 
     #[test]
     fn add_function_with_fn_arg() {
+        // FIXME: The argument in `bar` is wrong.
         check_assist(
             generate_function,
             r"
@@ -1898,7 +1899,7 @@ fn foo() {
     bar(Baz::new);
 }
 
-fn bar(new: fn() -> Baz) ${0:-> _} {
+fn bar(new: fn) ${0:-> _} {
     todo!()
 }
 ",
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 235062bf53..92fd4f71ca 100644
--- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -545,100 +545,4 @@ pub static SomeStatic: u8 = 10;
     "#,
         );
     }
-
-    #[test]
-    fn fn_inner_items() {
-        check_diagnostics(
-            r#"
-fn main() {
-    const foo: bool = true;
-        //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-    static bar: bool = true;
-         //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-    fn BAZ() {
-     //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-        const foo: bool = true;
-            //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-        static bar: bool = true;
-             //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-        fn BAZ() {
-         //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-            let INNER_INNER = 42;
-              //^^^^^^^^^^^ 💡 warn: Variable `INNER_INNER` should have snake_case name, e.g. `inner_inner`
-        }
-
-        let INNER_LOCAL = 42;
-          //^^^^^^^^^^^ 💡 warn: Variable `INNER_LOCAL` should have snake_case name, e.g. `inner_local`
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn const_body_inner_items() {
-        check_diagnostics(
-            r#"
-const _: () = {
-    static bar: bool = true;
-         //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-    fn BAZ() {}
-     //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-
-    const foo: () = {
-        //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-        const foo: bool = true;
-            //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-        static bar: bool = true;
-             //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-        fn BAZ() {}
-         //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-    };
-};
-"#,
-        );
-    }
-
-    #[test]
-    fn static_body_inner_items() {
-        check_diagnostics(
-            r#"
-static FOO: () = {
-    const foo: bool = true;
-        //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-    fn BAZ() {}
-     //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-
-    static bar: () = {
-         //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-        const foo: bool = true;
-            //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-        static bar: bool = true;
-             //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-        fn BAZ() {}
-         //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-    };
-};
-"#,
-        );
-    }
-
-    #[test]
-    fn enum_variant_body_inner_item() {
-        check_diagnostics(
-            r#"
-enum E {
-    A = {
-        const foo: bool = true;
-            //^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
-        static bar: bool = true;
-             //^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
-        fn BAZ() {}
-         //^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
-        42
-    },
-}
-"#,
-        );
-    }
 }
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index ae97236409..577bd2bc1f 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -24,7 +24,7 @@ use syntax::{
 
 use crate::{
     syntax_highlighting::{
-        escape::{highlight_escape_byte, highlight_escape_char, highlight_escape_string},
+        escape::{highlight_escape_char, highlight_escape_string},
         format::highlight_format_string,
         highlights::Highlights,
         macro_::MacroHighlighter,
@@ -471,14 +471,6 @@ fn traverse(
                 };
 
                 highlight_escape_char(hl, &char, range.start())
-            } else if ast::Byte::can_cast(token.kind())
-                && ast::Byte::can_cast(descended_token.kind())
-            {
-                let Some(byte) = ast::Byte::cast(token) else {
-                    continue;
-                };
-
-                highlight_escape_byte(hl, &byte, range.start())
             }
         }
 
diff --git a/crates/ide/src/syntax_highlighting/escape.rs b/crates/ide/src/syntax_highlighting/escape.rs
index 5913ca5e45..211e358809 100644
--- a/crates/ide/src/syntax_highlighting/escape.rs
+++ b/crates/ide/src/syntax_highlighting/escape.rs
@@ -1,7 +1,7 @@
 //! Syntax highlighting for escape sequences
 use crate::syntax_highlighting::highlights::Highlights;
 use crate::{HlRange, HlTag};
-use syntax::ast::{Byte, Char, IsString};
+use syntax::ast::{Char, IsString};
 use syntax::{AstToken, TextRange, TextSize};
 
 pub(super) fn highlight_escape_string<T: IsString>(
@@ -10,14 +10,14 @@ pub(super) fn highlight_escape_string<T: IsString>(
     start: TextSize,
 ) {
     string.escaped_char_ranges(&mut |piece_range, char| {
+        if char.is_err() {
+            return;
+        }
+
         if string.text()[piece_range.start().into()..].starts_with('\\') {
-            let highlight = match char {
-                Ok(_) => HlTag::EscapeSequence,
-                Err(_) => HlTag::InvalidEscapeSequence,
-            };
             stack.add(HlRange {
                 range: piece_range + start,
-                highlight: highlight.into(),
+                highlight: HlTag::EscapeSequence.into(),
                 binding_hash: None,
             });
         }
@@ -26,9 +26,6 @@ pub(super) fn highlight_escape_string<T: IsString>(
 
 pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
     if char.value().is_none() {
-        // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
-        // state and this token contains junks, since `'` is not a reliable delimiter (consider
-        // lifetimes). Nonetheless, parser errors should already be emitted.
         return;
     }
 
@@ -46,24 +43,3 @@ pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start:
         TextRange::new(start + TextSize::from(1), start + TextSize::from(text.len() as u32 + 1));
     stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None })
 }
-
-pub(super) fn highlight_escape_byte(stack: &mut Highlights, byte: &Byte, start: TextSize) {
-    if byte.value().is_none() {
-        // See `highlight_escape_char` for why no error highlighting here.
-        return;
-    }
-
-    let text = byte.text();
-    if !text.starts_with("b'") || !text.ends_with('\'') {
-        return;
-    }
-
-    let text = &text[2..text.len() - 1];
-    if !text.starts_with('\\') {
-        return;
-    }
-
-    let range =
-        TextRange::new(start + TextSize::from(2), start + TextSize::from(text.len() as u32 + 2));
-    stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None })
-}
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index bbc6b55a64..2c7823069b 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -109,7 +109,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 ";
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 6d4cdd0efe..f983109115 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -29,7 +29,6 @@ pub enum HlTag {
     Comment,
     EscapeSequence,
     FormatSpecifier,
-    InvalidEscapeSequence,
     Keyword,
     NumericLiteral,
     Operator(HlOperator),
@@ -167,7 +166,6 @@ impl HlTag {
             HlTag::CharLiteral => "char_literal",
             HlTag::Comment => "comment",
             HlTag::EscapeSequence => "escape_sequence",
-            HlTag::InvalidEscapeSequence => "invalid_escape_sequence",
             HlTag::FormatSpecifier => "format_specifier",
             HlTag::Keyword => "keyword",
             HlTag::Punctuation(punct) => match punct {
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/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index e47808a2cc..e1117ac464 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -145,7 +145,7 @@ pub struct PackageDependency {
     pub kind: DepKind,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
 pub enum DepKind {
     /// Available to the library, binary, and dev targets in the package (but not the build script).
     Normal,
@@ -156,20 +156,23 @@ pub enum DepKind {
 }
 
 impl DepKind {
-    fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> {
-        let mut dep_kinds = [None; 3];
+    fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ {
+        let mut dep_kinds = Vec::new();
         if list.is_empty() {
-            dep_kinds[0] = Some(Self::Normal);
+            dep_kinds.push(Self::Normal);
         }
         for info in list {
-            match info.kind {
-                cargo_metadata::DependencyKind::Normal => dep_kinds[0] = Some(Self::Normal),
-                cargo_metadata::DependencyKind::Development => dep_kinds[1] = Some(Self::Dev),
-                cargo_metadata::DependencyKind::Build => dep_kinds[2] = Some(Self::Build),
+            let kind = match info.kind {
+                cargo_metadata::DependencyKind::Normal => Self::Normal,
+                cargo_metadata::DependencyKind::Development => Self::Dev,
+                cargo_metadata::DependencyKind::Build => Self::Build,
                 cargo_metadata::DependencyKind::Unknown => continue,
-            }
+            };
+            dep_kinds.push(kind);
         }
-        dep_kinds.into_iter().flatten()
+        dep_kinds.sort_unstable();
+        dep_kinds.dedup();
+        dep_kinds.into_iter()
     }
 }
 
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 1fe02fc7ea..d4bb20c8f4 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -78,7 +78,6 @@ define_semantic_token_types![
         (DERIVE_HELPER, "deriveHelper") => DECORATOR,
         (DOT, "dot"),
         (ESCAPE_SEQUENCE, "escapeSequence") => STRING,
-        (INVALID_ESCAPE_SEQUENCE, "invalidEscapeSequence") => STRING,
         (FORMAT_SPECIFIER, "formatSpecifier") => STRING,
         (GENERIC, "generic") => TYPE_PARAMETER,
         (LABEL, "label"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 7a89533a5e..ba3421bf9e 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -640,7 +640,6 @@ fn semantic_token_type_and_modifiers(
         HlTag::CharLiteral => semantic_tokens::CHAR,
         HlTag::Comment => semantic_tokens::COMMENT,
         HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
-        HlTag::InvalidEscapeSequence => semantic_tokens::INVALID_ESCAPE_SEQUENCE,
         HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
         HlTag::Keyword => semantic_tokens::KEYWORD,
         HlTag::None => semantic_tokens::GENERIC,
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 87fd51d703..090eb89f47 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -2,9 +2,7 @@
 
 use std::borrow::Cow;
 
-use rustc_lexer::unescape::{
-    unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
-};
+use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
 
 use crate::{
     ast::{self, AstToken},
@@ -148,7 +146,6 @@ impl QuoteOffsets {
 
 pub trait IsString: AstToken {
     const RAW_PREFIX: &'static str;
-    const MODE: Mode;
     fn is_raw(&self) -> bool {
         self.text().starts_with(Self::RAW_PREFIX)
     }
@@ -184,7 +181,7 @@ pub trait IsString: AstToken {
         let text = &self.text()[text_range_no_quotes - start];
         let offset = text_range_no_quotes.start() - start;
 
-        unescape_literal(text, Self::MODE, &mut |range, unescaped_char| {
+        unescape_literal(text, Mode::Str, &mut |range, unescaped_char| {
             let text_range =
                 TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
             cb(text_range + offset, unescaped_char);
@@ -199,7 +196,6 @@ pub trait IsString: AstToken {
 
 impl IsString for ast::String {
     const RAW_PREFIX: &'static str = "r";
-    const MODE: Mode = Mode::Str;
 }
 
 impl ast::String {
@@ -217,7 +213,7 @@ impl ast::String {
         let mut buf = String::new();
         let mut prev_end = 0;
         let mut has_error = false;
-        unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match (
+        unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
@@ -243,7 +239,6 @@ impl ast::String {
 
 impl IsString for ast::ByteString {
     const RAW_PREFIX: &'static str = "br";
-    const MODE: Mode = Mode::ByteStr;
 }
 
 impl ast::ByteString {
@@ -261,7 +256,7 @@ impl ast::ByteString {
         let mut buf: Vec<u8> = Vec::new();
         let mut prev_end = 0;
         let mut has_error = false;
-        unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match (
+        unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
@@ -287,70 +282,42 @@ impl ast::ByteString {
 
 impl IsString for ast::CString {
     const RAW_PREFIX: &'static str = "cr";
-    const MODE: Mode = Mode::CStr;
-
-    fn escaped_char_ranges(
-        &self,
-        cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
-    ) {
-        let text_range_no_quotes = match self.text_range_between_quotes() {
-            Some(it) => it,
-            None => return,
-        };
-
-        let start = self.syntax().text_range().start();
-        let text = &self.text()[text_range_no_quotes - start];
-        let offset = text_range_no_quotes.start() - start;
-
-        unescape_c_string(text, Self::MODE, &mut |range, unescaped_char| {
-            let text_range =
-                TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
-            // XXX: This method should only be used for highlighting ranges. The unescaped
-            // char/byte is not used. For simplicity, we return an arbitrary placeholder char.
-            cb(text_range + offset, unescaped_char.map(|_| ' '));
-        });
-    }
 }
 
 impl ast::CString {
-    pub fn value(&self) -> Option<Cow<'_, [u8]>> {
+    pub fn value(&self) -> Option<Cow<'_, str>> {
         if self.is_raw() {
             let text = self.text();
             let text =
                 &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text.as_bytes()));
+            return Some(Cow::Borrowed(text));
         }
 
         let text = self.text();
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
-        let mut buf = Vec::new();
+        let mut buf = String::new();
         let mut prev_end = 0;
         let mut has_error = false;
-        let mut char_buf = [0u8; 4];
-        let mut extend_unit = |buf: &mut Vec<u8>, unit: CStrUnit| match unit {
-            CStrUnit::Byte(b) => buf.push(b),
-            CStrUnit::Char(c) => buf.extend(c.encode_utf8(&mut char_buf).as_bytes()),
-        };
-        unescape_c_string(text, Self::MODE, &mut |char_range, unescaped| match (
-            unescaped,
+        unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
+            unescaped_char,
             buf.capacity() == 0,
         ) {
-            (Ok(u), false) => extend_unit(&mut buf, u),
+            (Ok(c), false) => buf.push(c),
             (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
                 prev_end = char_range.end
             }
-            (Ok(u), true) => {
+            (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.extend(text[..prev_end].as_bytes());
-                extend_unit(&mut buf, u);
+                buf.push_str(&text[..prev_end]);
+                buf.push(c);
             }
             (Err(_), _) => has_error = true,
         });
 
         match (has_error, buf.capacity() == 0) {
             (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text.as_bytes())),
+            (false, true) => Some(Cow::Borrowed(text)),
             (false, false) => Some(Cow::Owned(buf)),
         }
     }
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 5dafd1a4c8..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.
 
@@ -949,29 +952,6 @@ Or it is possible to specify vars more granularly:
 You can use any valid regular expression as a mask.
 Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively.
 
-If needed, you can set different values for different platforms:
-```jsonc
-"rust-analyzer.runnables.extraEnv": [
-    {
-        "platform": "win32", // windows only
-        env: {
-             "APP_DATA": "windows specific data"
-        }
-    },
-    {
-        "platform": ["linux"],
-        "env": {
-             "APP_DATA": "linux data",
-        }
-    },
-    { // for all platforms
-        "env": {
-             "APP_COMMON_DATA": "xxx",
-        }
-    }
-]
-```
-
 ==== Compiler feedback from external commands
 
 Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 20fe781ae9..1c94f13d74 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -18,7 +18,7 @@
             "devDependencies": {
                 "@tsconfig/strictest": "^2.0.1",
                 "@types/node": "~16.11.7",
-                "@types/vscode": "~1.75",
+                "@types/vscode": "~1.78.1",
                 "@typescript-eslint/eslint-plugin": "^6.0.0",
                 "@typescript-eslint/parser": "^6.0.0",
                 "@vscode/test-electron": "^2.3.3",
@@ -32,7 +32,7 @@
                 "typescript": "^5.1.6"
             },
             "engines": {
-                "vscode": "^1.75.0"
+                "vscode": "^1.78.0"
             }
         },
         "node_modules/@aashutoshrathi/word-wrap": {
@@ -565,9 +565,9 @@
             "dev": true
         },
         "node_modules/@types/vscode": {
-            "version": "1.75.1",
-            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz",
-            "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==",
+            "version": "1.78.1",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz",
+            "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==",
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
diff --git a/editors/code/package.json b/editors/code/package.json
index 76d7e91f38..ffb5dd9079 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -26,7 +26,7 @@
         }
     },
     "engines": {
-        "vscode": "^1.75.0"
+        "vscode": "^1.78.0"
     },
     "enabledApiProposals": [],
     "scripts": {
@@ -35,12 +35,9 @@
         "build-base": "esbuild ./src/main.ts --bundle --outfile=out/main.js --external:vscode --format=cjs --platform=node --target=node16",
         "build": "npm run build-base -- --sourcemap",
         "watch": "npm run build-base -- --sourcemap --watch",
-        "format": "prettier --write .",
-        "format:check": "prettier --check .",
-        "lint": "eslint -c .eslintrc.js --ext ts ./src ./tests",
-        "lint:fix": "npm run lint -- --fix",
-        "typecheck": "tsc",
-        "pretest": "npm run typecheck && npm run build",
+        "lint": "prettier --check . && eslint -c .eslintrc.js --ext ts ./src ./tests",
+        "fix": "prettier --write . && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
+        "pretest": "tsc && npm run build",
         "test": "node ./out/tests/runTests.js"
     },
     "dependencies": {
@@ -53,7 +50,7 @@
     "devDependencies": {
         "@tsconfig/strictest": "^2.0.1",
         "@types/node": "~16.11.7",
-        "@types/vscode": "~1.75",
+        "@types/vscode": "~1.78.1",
         "@typescript-eslint/eslint-plugin": "^6.0.0",
         "@typescript-eslint/parser": "^6.0.0",
         "@vscode/test-electron": "^2.3.3",
@@ -328,15 +325,6 @@
                             "items": {
                                 "type": "object",
                                 "properties": {
-                                    "platform": {
-                                        "type": [
-                                            "null",
-                                            "string",
-                                            "array"
-                                        ],
-                                        "default": null,
-                                        "markdownDescription": "Platform(s) filter like \"win32\" or [\"linux\", \"win32\"]. See [process.platform](https://nodejs.org/api/process.html#processplatform) values."
-                                    },
                                     "mask": {
                                         "type": "string",
                                         "description": "Runnable name mask"
@@ -1813,16 +1801,12 @@
             },
             {
                 "id": "escapeSequence",
-                "description": "Style for char or byte escapes in strings"
+                "description": "Style for char escapes in strings"
             },
             {
                 "id": "formatSpecifier",
                 "description": "Style for {} placeholders in format strings"
             },
-            {
-                "id": "invalidEscapeSequence",
-                "description": "Style for invalid char or byte escapes in strings"
-            },
             {
                 "id": "label",
                 "description": "Style for labels"
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 0e64054c11..a047f9659a 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -6,12 +6,10 @@ import type { Env } from "./client";
 import { log } from "./util";
 import { expectNotUndefined, unwrapUndefinable } from "./undefinable";
 
-export type RunnableEnvCfgItem = {
-    mask?: string;
-    env: Record<string, string>;
-    platform?: string | string[];
-};
-export type RunnableEnvCfg = undefined | Record<string, string> | RunnableEnvCfgItem[];
+export type RunnableEnvCfg =
+    | undefined
+    | Record<string, string>
+    | { mask?: string; env: Record<string, string> }[];
 
 export class Config {
     readonly extensionId = "rust-lang.rust-analyzer";
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index e817d680ea..f3d6238d51 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -66,12 +66,6 @@ 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,
@@ -96,12 +90,9 @@ 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](command:${commandCodeLLDB} "Open CodeLLDB")` +
-                ` or [C/C++](command:${commandCpp} "Open C/C++") extension for debugging.`,
+            `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.`,
         );
         return;
     }
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 57881803a6..c893d39055 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -5,7 +5,7 @@ import * as tasks from "./tasks";
 
 import type { CtxInit } from "./ctx";
 import { makeDebugConfig } from "./debug";
-import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
+import type { Config, RunnableEnvCfg } from "./config";
 import { unwrapUndefinable } from "./undefinable";
 
 const quickPickButtons = [
@@ -112,21 +112,11 @@ export function prepareEnv(
     }
 
     Object.assign(env, process.env as { [key: string]: string });
-    const platform = process.platform;
-
-    const checkPlatform = (it: RunnableEnvCfgItem) => {
-        if (it.platform) {
-            const platforms = Array.isArray(it.platform) ? it.platform : [it.platform];
-            return platforms.indexOf(platform) >= 0;
-        }
-        return true;
-    };
 
     if (runnableEnvCfg) {
         if (Array.isArray(runnableEnvCfg)) {
             for (const it of runnableEnvCfg) {
-                const masked = !it.mask || new RegExp(it.mask).test(runnable.label);
-                if (masked && checkPlatform(it)) {
+                if (!it.mask || new RegExp(it.mask).test(runnable.label)) {
                     Object.assign(env, it.env);
                 }
             }


Test patch:
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 98ebe55724..4379299498 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1428,14 +1428,14 @@ fn builtin_derive_macro() {
     #[derive(Clone)]
     struct Y {
         field1: i32,
-        field2: u8,
+        field2: ((i32, u8), i64),
     }
 
     const GOAL: u8 = {
-        let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8);
+        let x = X(2, Z::Foo(Y { field1: 4, field2: ((32, 5), 12) }), 8);
         let x = x.clone();
         let Z::Foo(t) = x.1;
-        t.field2
+        t.field2.0 .1
     };
     "#,
         5,
@@ -1632,6 +1632,34 @@ const GOAL: i32 = {
     );
 }
 
+#[test]
+fn closure_capture_unsized_type() {
+    check_number(
+        r#"
+    //- minicore: fn, copy, slice, index, coerce_unsized
+    fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty {
+        let c = || &*x;
+        c()
+    }
+
+    trait A {
+        type Ty;
+    }
+
+    impl A for i32 {
+        type Ty = [u8];
+    }
+
+    const GOAL: u8 = {
+        let k: &[u8] = &[1, 2, 3];
+        let k = f::<i32>(k);
+        k[0] + k[1] + k[2]
+    }
+    "#,
+        6,
+    );
+}
+
 #[test]
 fn closure_and_impl_fn() {
     check_number(
@@ -2521,12 +2549,16 @@ fn const_trait_assoc() {
     );
     check_number(
         r#"
-    //- minicore: size_of
+    //- minicore: size_of, fn
     //- /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>();
+        pub const X: usize = {
+            let k: T;
+            let f = || core::mem::size_of::<T>();
+            f()
+        };
     }
     //- /main.rs crate:main deps:a
     use a::{S};
diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs
index 9253e31d77..b068286600 100644
--- a/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -438,6 +438,8 @@ fn atomic() {
             pub fn atomic_nand_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
             pub fn atomic_or_release<T: Copy>(dst: *mut T, src: T) -> T;
             pub fn atomic_xor_seqcst<T: Copy>(dst: *mut T, src: T) -> T;
+            pub fn atomic_fence_seqcst();
+            pub fn atomic_singlethreadfence_acqrel();
         }
 
         fn should_not_reach() {
@@ -452,6 +454,7 @@ fn atomic() {
             if (30, true) != atomic_cxchg_release_seqcst(&mut y, 30, 40) {
                 should_not_reach();
             }
+            atomic_fence_seqcst();
             if (40, false) != atomic_cxchg_release_seqcst(&mut y, 30, 50) {
                 should_not_reach();
             }
@@ -459,6 +462,7 @@ fn atomic() {
                 should_not_reach();
             }
             let mut z = atomic_xsub_seqcst(&mut x, -200);
+            atomic_singlethreadfence_acqrel();
             atomic_xor_seqcst(&mut x, 1024);
             atomic_load_seqcst(&x) + z * 3 + atomic_load_seqcst(&y) * 2
         };
diff --git a/crates/hir-ty/src/tests/display_source_code.rs b/crates/hir-ty/src/tests/display_source_code.rs
index e75b037e38..425432479e 100644
--- a/crates/hir-ty/src/tests/display_source_code.rs
+++ b/crates/hir-ty/src/tests/display_source_code.rs
@@ -227,22 +227,3 @@ fn f(a: impl Foo<i8, Assoc<i16> = i32>) {
         "#,
     );
 }
-
-#[test]
-fn fn_def_is_shown_as_fn_ptr() {
-    check_types_source_code(
-        r#"
-fn foo(_: i32) -> i64 { 42 }
-struct S<T>(T);
-enum E { A(usize) }
-fn test() {
-    let f = foo;
-      //^ fn(i32) -> i64
-    let f = S::<i8>;
-      //^ fn(i8) -> S<i8>
-    let f = E::A;
-      //^ fn(usize) -> E
-}
-"#,
-    );
-}
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/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index 375014d6c7..8b95110233 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1978,23 +1978,3 @@ fn x(a: [i32; 4]) {
         "#,
     );
 }
-
-#[test]
-fn dont_unify_on_casts() {
-    // #15246
-    check_types(
-        r#"
-fn unify(_: [bool; 1]) {}
-fn casted(_: *const bool) {}
-fn default<T>() -> T { loop {} }
-
-fn test() {
-    let foo = default();
-      //^^^ [bool; 1]
-
-    casted(&foo as *const _);
-    unify(foo);
-}
-"#,
-    );
-}
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 2ad7946c8a..a0ff628435 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3513,6 +3513,7 @@ fn func() {
     );
 }
 
+// FIXME
 #[test]
 fn castable_to() {
     check_infer(
@@ -3537,10 +3538,10 @@ fn func() {
             120..122 '{}': ()
             138..184 '{     ...0]>; }': ()
             148..149 'x': Box<[i32; 0]>
-            152..160 'Box::new': fn new<[i32; 0]>([i32; 0]) -> Box<[i32; 0]>
-            152..164 'Box::new([])': Box<[i32; 0]>
+            152..160 'Box::new': fn new<[{unknown}; 0]>([{unknown}; 0]) -> Box<[{unknown}; 0]>
+            152..164 'Box::new([])': Box<[{unknown}; 0]>
             152..181 'Box::n...2; 0]>': Box<[i32; 0]>
-            161..163 '[]': [i32; 0]
+            161..163 '[]': [{unknown}; 0]
         "#]],
     );
 }
@@ -3576,21 +3577,6 @@ fn f<T>(t: Ark<T>) {
     );
 }
 
-#[test]
-fn ref_to_array_to_ptr_cast() {
-    check_types(
-        r#"
-fn default<T>() -> T { loop {} }
-fn foo() {
-    let arr = [default()];
-      //^^^ [i32; 1]
-    let ref_to_arr = &arr;
-    let casted = ref_to_arr as *const i32;
-}
-"#,
-    );
-}
-
 #[test]
 fn const_dependent_on_local() {
     check_types(
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 4dcbfe4eb6..9ed65fbc85 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index bf5505caf3..567ab8ccc1 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
index 0d1b3c1f18..1e4c06df7e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root library">foo</span><span class="semicolon">;</span>
 <span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">iter</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index dd1528ed03..5d66f832da 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">iter</span><span class="semicolon">;</span>
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index d5f92aa5d4..35f240d428 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="comment documentation">//! This is a module to test doc injection.</span>
 <span class="comment documentation">//! ```</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index b15f7bca72..87b9da46e2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span>
 <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root default_library declaration library">abc</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index bdeb09d2f8..6b049f379a 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index f9c33b8a60..d9c3db6fbb 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
index fd3b39855e..3900959bed 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span>
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
index ec39998de2..f98e0b1cda 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index c5fcec7568..2cbbf69641 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="module crate_root library">proc_macros</span><span class="operator">::</span><span class="macro library">mirror</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
     <span class="brace macro">{</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
index 4dcf8e5f01..8a1d69816e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
 <span class="comment documentation">//! This is an intra doc injection test for modules</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
index 084bbf2f74..c4c3e3dc26 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
 <span class="comment documentation">/// This is an intra doc injection test for modules</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index 1af4bcfbd9..2369071ae2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="logical">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">&gt;&gt;</span> <span class="numeric_literal">1</span> <span class="bitwise">&lt;&lt;</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
index ec18c3ea1f..bff35c897e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index dcac8eb736..f4f164aa1d 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="brace">{</span>
@@ -106,8 +105,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\x65</span><span class="char_literal">'</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\x00</span><span class="char_literal">'</span><span class="semicolon">;</span>
 
-    <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="byte_literal">b'</span><span class="escape_sequence">\xFF</span><span class="byte_literal">'</span><span class="semicolon">;</span>
-
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>                 <span class="comment">// =&gt; "Hello"</span>
@@ -162,9 +159,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
-    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="invalid_escape_sequence">\xFF</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// invalid non-UTF8 escape sequences</span>
-    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\xFF</span><span class="invalid_escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, invalid unicodes</span>
-    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
+    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
 
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index c72ea54e94..654d51b8a4 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -40,8 +40,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .control            { font-style: italic; }
 .reference          { font-style: italic; font-weight: bold; }
 
-.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
-.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
     <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 696aa59002..1ee451a06d 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -451,8 +451,6 @@ fn main() {
     let a = '\x65';
     let a = '\x00';
 
-    let a = b'\xFF';
-
     println!("Hello {{Hello}}");
     // from https://doc.rust-lang.org/std/fmt/index.html
     println!("Hello");                 // => "Hello"
@@ -507,9 +505,8 @@ fn main() {
     println!("Hello\nWorld");
     println!("\u{48}\x65\x6C\x6C\x6F World");
 
-    let _ = "\x28\x28\x00\x63\xFF\u{FF}\n"; // invalid non-UTF8 escape sequences
-    let _ = b"\x28\x28\x00\x63\xFF\u{FF}\n"; // valid bytes, invalid unicodes
-    let _ = c"\u{FF}\xFF"; // valid bytes, valid unicodes
+    let _ = "\x28\x28\x00\x63\n";
+    let _ = b"\x28\x28\x00\x63\n";
     let backslash = r"\\";
 
     println!("{\x41}", A = 92);
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(); }