Merge pull request #19457 from Veykril/push-xpmluxlzprpy

chore: Remove salsa dependency from proc-macro server again
diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs
index b5964ff..114b4cb 100644
--- a/crates/base-db/src/change.rs
+++ b/crates/base-db/src/change.rs
@@ -55,7 +55,7 @@
         if let Some(roots) = self.roots {
             for (idx, root) in roots.into_iter().enumerate() {
                 let root_id = SourceRootId(idx as u32);
-                let durability = durability(&root);
+                let durability = source_root_durability(&root);
                 for file_id in root.iter() {
                     db.set_file_source_root_with_durability(file_id, root_id, durability);
                 }
@@ -68,7 +68,7 @@
             let source_root_id = db.file_source_root(file_id);
             let source_root = db.source_root(source_root_id.source_root_id(db));
 
-            let durability = durability(&source_root.source_root(db));
+            let durability = file_text_durability(&source_root.source_root(db));
             // XXX: can't actually remove the file, just reset the text
             let text = text.unwrap_or_default();
             db.set_file_text_with_durability(file_id, &text, durability)
@@ -81,6 +81,10 @@
     }
 }
 
-fn durability(source_root: &SourceRoot) -> Durability {
+fn source_root_durability(source_root: &SourceRoot) -> Durability {
+    if source_root.is_library { Durability::MEDIUM } else { Durability::LOW }
+}
+
+fn file_text_durability(source_root: &SourceRoot) -> Durability {
     if source_root.is_library { Durability::HIGH } else { Durability::LOW }
 }
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 2fe4f68..343aba1 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -491,7 +491,7 @@
         if **old_all_crates != *all_crates {
             db.set_all_crates_with_durability(
                 Arc::new(all_crates.into_boxed_slice()),
-                Durability::HIGH,
+                Durability::MEDIUM,
             );
         }
 
@@ -549,30 +549,30 @@
                 Entry::Occupied(entry) => {
                     let old_crate = *entry.get();
                     if crate_data != *old_crate.data(db) {
-                        old_crate.set_data(db).with_durability(Durability::HIGH).to(crate_data);
+                        old_crate.set_data(db).with_durability(Durability::MEDIUM).to(crate_data);
                     }
                     if krate.extra != *old_crate.extra_data(db) {
                         old_crate
                             .set_extra_data(db)
-                            .with_durability(Durability::HIGH)
+                            .with_durability(Durability::MEDIUM)
                             .to(krate.extra.clone());
                     }
                     if krate.cfg_options != *old_crate.cfg_options(db) {
                         old_crate
                             .set_cfg_options(db)
-                            .with_durability(Durability::HIGH)
+                            .with_durability(Durability::MEDIUM)
                             .to(krate.cfg_options.clone());
                     }
                     if krate.env != *old_crate.env(db) {
                         old_crate
                             .set_env(db)
-                            .with_durability(Durability::HIGH)
+                            .with_durability(Durability::MEDIUM)
                             .to(krate.env.clone());
                     }
                     if krate.ws_data != *old_crate.workspace_data(db) {
                         old_crate
                             .set_workspace_data(db)
-                            .with_durability(Durability::HIGH)
+                            .with_durability(Durability::MEDIUM)
                             .to(krate.ws_data.clone());
                     }
                     old_crate
@@ -585,7 +585,7 @@
                         krate.cfg_options.clone(),
                         krate.env.clone(),
                     )
-                    .durability(Durability::HIGH)
+                    .durability(Durability::MEDIUM)
                     .new(db);
                     entry.insert(input);
                     input
diff --git a/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
index a2dcbf9..fd17231 100644
--- a/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ide-assists/src/handlers/replace_let_with_if_let.rs
@@ -45,19 +45,31 @@
             let mut editor = builder.make_editor(let_stmt.syntax());
             let make = SyntaxFactory::new();
             let ty = ctx.sema.type_of_expr(&init);
-            let happy_variant = ty
-                .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
-                .map(|it| it.happy_case());
-            let pat = match happy_variant {
-                None => original_pat,
-                Some(var_name) => {
-                    make.tuple_struct_pat(make.ident_path(var_name), [original_pat]).into()
+            let pat = if let_stmt.let_else().is_some() {
+                // Do not add the wrapper type that implements `Try`,
+                // since the statement already wraps the pattern.
+                original_pat
+            } else {
+                let happy_variant = ty
+                    .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
+                    .map(|it| it.happy_case());
+                match happy_variant {
+                    None => original_pat,
+                    Some(var_name) => {
+                        make.tuple_struct_pat(make.ident_path(var_name), [original_pat]).into()
+                    }
                 }
             };
 
             let block = make.block_expr([], None);
             block.indent(IndentLevel::from_node(let_stmt.syntax()));
-            let if_expr = make.expr_if(make.expr_let(pat, init).into(), block, None);
+            let if_expr = make.expr_if(
+                make.expr_let(pat, init).into(),
+                block,
+                let_stmt
+                    .let_else()
+                    .and_then(|let_else| let_else.block_expr().map(ast::ElseBranch::from)),
+            );
             let if_stmt = make.expr_stmt(if_expr.into());
 
             editor.replace(let_stmt.syntax(), if_stmt.syntax());
@@ -94,4 +106,25 @@
             ",
         )
     }
+
+    #[test]
+    fn replace_let_else() {
+        check_assist(
+            replace_let_with_if_let,
+            r"
+//- minicore: option
+fn main() {
+    let a = Some(1);
+    $0let Some(_) = a else { unreachable!() };
+}
+            ",
+            r"
+fn main() {
+    let a = Some(1);
+    if let Some(_) = a {
+    } else { unreachable!() }
+}
+            ",
+        )
+    }
 }
diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs
index 36745b0..008b6fd 100644
--- a/crates/ide-db/src/apply_change.rs
+++ b/crates/ide-db/src/apply_change.rs
@@ -29,8 +29,8 @@
                     local_roots.insert(root_id);
                 }
             }
-            self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
-            self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
+            self.set_local_roots_with_durability(Arc::new(local_roots), Durability::MEDIUM);
+            self.set_library_roots_with_durability(Arc::new(library_roots), Durability::MEDIUM);
         }
         change.apply(self);
     }
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index c6bd803..b5b4a9e 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -220,9 +220,9 @@
         // This needs to be here otherwise `CrateGraphBuilder` will panic.
         db.set_all_crates(Arc::new(Box::new([])));
         CrateGraphBuilder::default().set_in_db(&mut db);
-        db.set_proc_macros_with_durability(Default::default(), Durability::HIGH);
-        db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
-        db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
+        db.set_proc_macros_with_durability(Default::default(), Durability::MEDIUM);
+        db.set_local_roots_with_durability(Default::default(), Durability::MEDIUM);
+        db.set_library_roots_with_durability(Default::default(), Durability::MEDIUM);
         db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
         db.update_base_query_lru_capacities(lru_capacity);
         db
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 12894a2..6397b04 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -4,6 +4,7 @@
 
 mod block;
 
+use itertools::Itertools;
 use rowan::Direction;
 use rustc_lexer::unescape::{self, Mode, unescape_mixed, unescape_unicode};
 
@@ -37,7 +38,8 @@
                 ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, errors),
                 ast::MacroRules(it) => validate_macro_rules(it, errors),
                 ast::LetExpr(it) => validate_let_expr(it, errors),
-                ast::ImplTraitType(it) => validate_impl_object_ty(it, errors),
+                ast::DynTraitType(it) => errors.extend(validate_trait_object_ty(it)),
+                ast::ImplTraitType(it) => errors.extend(validate_impl_object_ty(it)),
                 _ => (),
             }
         }
@@ -316,87 +318,104 @@
 }
 
 fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) {
-    if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
-        if let Some(err) = validate_trait_object_ty(ty) {
-            errors.push(err);
+    match ty.ty() {
+        Some(ast::Type::DynTraitType(ty)) => {
+            if let Some(err) = validate_trait_object_ty_plus(ty) {
+                errors.push(err);
+            }
         }
+        Some(ast::Type::ImplTraitType(ty)) => {
+            if let Some(err) = validate_impl_object_ty_plus(ty) {
+                errors.push(err);
+            }
+        }
+        _ => (),
     }
 }
 
 fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) {
-    if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
-        if let Some(err) = validate_trait_object_ty(ty) {
-            errors.push(err);
+    match ty.ty() {
+        Some(ast::Type::DynTraitType(ty)) => {
+            if let Some(err) = validate_trait_object_ty_plus(ty) {
+                errors.push(err);
+            }
         }
+        Some(ast::Type::ImplTraitType(ty)) => {
+            if let Some(err) = validate_impl_object_ty_plus(ty) {
+                errors.push(err);
+            }
+        }
+        _ => (),
     }
 }
 
 fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) {
-    if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) {
-        if let Some(err) = validate_trait_object_ty(ty) {
-            errors.push(err);
+    match ty.ret_type().and_then(|ty| ty.ty()) {
+        Some(ast::Type::DynTraitType(ty)) => {
+            if let Some(err) = validate_trait_object_ty_plus(ty) {
+                errors.push(err);
+            }
         }
+        Some(ast::Type::ImplTraitType(ty)) => {
+            if let Some(err) = validate_impl_object_ty_plus(ty) {
+                errors.push(err);
+            }
+        }
+        _ => (),
     }
 }
 
 fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
     let tbl = ty.type_bound_list()?;
-    let bounds_count = tbl.bounds().count();
+    let no_bounds = tbl.bounds().filter_map(|it| it.ty()).next().is_none();
 
-    match bounds_count {
-        0 => Some(SyntaxError::new(
+    match no_bounds {
+        true => Some(SyntaxError::new(
             "At least one trait is required for an object type",
             ty.syntax().text_range(),
         )),
-        _ if bounds_count > 1 => {
-            let dyn_token = ty.dyn_token()?;
-            let preceding_token =
-                algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
-
-            if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
-                return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
-            }
-            None
-        }
-        _ => None,
+        false => None,
     }
 }
 
-fn validate_impl_object_ty(ty: ast::ImplTraitType, errors: &mut Vec<SyntaxError>) {
-    let Some(bound_list) = ty.type_bound_list() else {
-        errors.push(SyntaxError::new(
-            "At least one trait must be specified",
+fn validate_impl_object_ty(ty: ast::ImplTraitType) -> Option<SyntaxError> {
+    let tbl = ty.type_bound_list()?;
+    let no_bounds = tbl.bounds().filter_map(|it| it.ty()).next().is_none();
+
+    match no_bounds {
+        true => Some(SyntaxError::new(
+            "At least one trait is required for an object type",
             ty.syntax().text_range(),
-        ));
-        return;
-    };
-
-    let bounds: Vec<_> = bound_list.bounds().collect();
-
-    if !bounds.iter().any(|b| !matches!(b.kind(), ast::TypeBoundKind::Lifetime(_))) {
-        errors.push(SyntaxError::new(
-            "At least one trait must be specified",
-            ty.syntax().text_range(),
-        ));
-        return;
+        )),
+        false => None,
     }
+}
 
-    if bounds.len() == 1 {
-        return;
+// FIXME: This is not a validation error, this is a context dependent parse error
+fn validate_trait_object_ty_plus(ty: ast::DynTraitType) -> Option<SyntaxError> {
+    let dyn_token = ty.dyn_token()?;
+    let preceding_token = algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
+    let tbl = ty.type_bound_list()?;
+    let more_than_one_bound = tbl.bounds().next_tuple::<(_, _)>().is_some();
+
+    if more_than_one_bound && !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
+        Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()))
+    } else {
+        None
     }
+}
 
-    let Some(preceding_token) = ty
-        .impl_token()
-        .and_then(|token| token.prev_token())
-        .and_then(|prev| algo::skip_trivia_token(prev, Direction::Prev))
-    else {
-        return;
-    };
+// FIXME: This is not a validation error, this is a context dependent parse error
+fn validate_impl_object_ty_plus(ty: ast::ImplTraitType) -> Option<SyntaxError> {
+    let dyn_token = ty.impl_token()?;
+    let preceding_token = algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
+    let tbl = ty.type_bound_list()?;
+    let more_than_one_bound = tbl.bounds().next_tuple::<(_, _)>().is_some();
 
-    if !matches!(preceding_token.kind(), T!['('] | T![<] | T![=])
-        && matches!(preceding_token.kind(), T![&])
-    {
-        errors.push(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
+    if more_than_one_bound && !matches!(preceding_token.kind(), T!['('] | T![<] | T![=]) {
+        Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()))
+    } else {
+        None
     }
 }
 
diff --git a/crates/syntax/test_data/parser/validation/dangling_impl.rast b/crates/syntax/test_data/parser/validation/dangling_impl.rast
index 2db07ae..c337ee8 100644
--- a/crates/syntax/test_data/parser/validation/dangling_impl.rast
+++ b/crates/syntax/test_data/parser/validation/dangling_impl.rast
@@ -20,4 +20,4 @@
       STMT_LIST@14..16
         L_CURLY@14..15 "{"
         R_CURLY@15..16 "}"
-error 8..12: At least one trait must be specified
+error 8..12: At least one trait is required for an object type
diff --git a/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast b/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
index dbe6535..cb73cb4 100644
--- a/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
+++ b/crates/syntax/test_data/parser/validation/dangling_impl_reference.rast
@@ -22,4 +22,4 @@
       STMT_LIST@15..17
         L_CURLY@15..16 "{"
         R_CURLY@16..17 "}"
-error 9..13: At least one trait must be specified
+error 9..13: At least one trait is required for an object type
diff --git a/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast b/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast
index 98aa862..ed938d6 100644
--- a/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast
+++ b/crates/syntax/test_data/parser/validation/impl_trait_lifetime_only.rast
@@ -26,4 +26,4 @@
       STMT_LIST@18..20
         L_CURLY@18..19 "{"
         R_CURLY@19..20 "}"
-error 9..16: At least one trait must be specified
+error 9..16: At least one trait is required for an object type