From 788232b3551188965d57afce36444fe38b865475 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Thu, 13 Mar 2025 13:38:29 -0400 Subject: [PATCH] internal: don't panic when the crate graph isn't ready #19351 --- crates/base-db/src/lib.rs | 7 +++---- crates/hir-def/src/nameres/tests/macros.rs | 4 ++-- crates/hir-ty/src/consteval/tests.rs | 3 ++- crates/hir/src/semantics.rs | 8 ++++---- crates/hir/src/symbols.rs | 5 ++++- crates/ide-diagnostics/src/lib.rs | 14 +++++++++++--- crates/ide-ssr/src/matching.rs | 8 +++----- crates/ide/src/hover.rs | 2 +- crates/ide/src/inlay_hints.rs | 5 ++++- crates/ide/src/runnables.rs | 5 +++-- crates/ide/src/signature_help.rs | 2 +- crates/ide/src/static_index.rs | 9 +++++++-- crates/ide/src/view_memory_layout.rs | 2 +- crates/rust-analyzer/src/cli/analysis_stats.rs | 6 ++++-- 14 files changed, 50 insertions(+), 30 deletions(-) diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 324979b2e4..0f29abbb54 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -212,22 +212,21 @@ pub trait RootQueryDb: SourceDatabase + salsa::Database { /// Returns the crates in topological order. /// - /// **Warning**: do not use this query in analysis! It kills incrementality across crate metadata modifications. + /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications. #[salsa::input] fn all_crates(&self) -> Arc>; /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. /// - /// **Warning**: do not use this query in analysis! It kills incrementality across crate metadata modifications. - /// + /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications. #[salsa::transparent] fn transitive_deps(&self, crate_id: Crate) -> FxHashSet; /// Returns all transitive reverse dependencies of the given crate, /// including the crate itself. /// - /// **Warning**: Do not use this query in analysis! It kills incrementality across crate metadata modifications. + /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications. #[salsa::invoke(input::transitive_rev_deps)] #[salsa::transparent] fn transitive_rev_deps(&self, of: Crate) -> FxHashSet; diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs index 0348a7076a..5f8a01523d 100644 --- a/crates/hir-def/src/nameres/tests/macros.rs +++ b/crates/hir-def/src/nameres/tests/macros.rs @@ -1095,7 +1095,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream { } "#, ); - let krate = *db.all_crates().last().unwrap(); + let krate = *db.all_crates().last().expect("no crate graph present"); let def_map = db.crate_def_map(krate); assert_eq!(def_map.data.exported_derives.len(), 1); @@ -1445,7 +1445,7 @@ struct TokenStream; fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } "#, ); - let krate = *db.all_crates().last().unwrap(); + let krate = *db.all_crates().last().expect("no crate graph present"); let def_map = db.crate_def_map(krate); let root_module = &def_map[DefMap::ROOT].scope; diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 37e7df6f4b..d679f9dd7c 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -101,7 +101,8 @@ fn check_answer( fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); - let display_target = DisplayTarget::from_crate(&db, *db.all_crates().last().unwrap()); + let display_target = + DisplayTarget::from_crate(&db, *db.all_crates().last().expect("no crate graph present")); match e { ConstEvalError::MirLowerError(e) => { e.pretty_print(&mut err, &db, span_formatter, display_target) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 6378eebd24..15cd69f320 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -314,11 +314,11 @@ impl<'db> SemanticsImpl<'db> { tree } - /// If not crate is found for the file, returns the last crate in topological order. - pub fn first_crate_or_default(&self, file: FileId) -> Crate { + /// If not crate is found for the file, try to return the last crate in topological order. + pub fn first_crate(&self, file: FileId) -> Option { match self.file_to_module_defs(file).next() { - Some(module) => module.krate(), - None => (*self.db.all_crates().last().unwrap()).into(), + Some(module) => Some(module.krate()), + None => self.db.all_crates().last().copied().map(Into::into), } } diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs index cc8aa1f1a1..2a6c15207a 100644 --- a/crates/hir/src/symbols.rs +++ b/crates/hir/src/symbols.rs @@ -77,7 +77,10 @@ impl<'a> SymbolCollector<'a> { symbols: Default::default(), work: Default::default(), current_container_name: None, - display_target: DisplayTarget::from_crate(db, *db.all_crates().last().unwrap()), + display_target: DisplayTarget::from_crate( + db, + *db.all_crates().last().expect("no crate graph present"), + ), } } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index f4ced736b3..dc6fd1f5ea 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -389,9 +389,17 @@ pub fn semantic_diagnostics( module.and_then(|m| db.toolchain_channel(m.krate().into())), Some(ReleaseChannel::Nightly) | None ); - let krate = module - .map(|module| module.krate()) - .unwrap_or_else(|| (*db.all_crates().last().unwrap()).into()); + + let krate = match module { + Some(module) => module.krate(), + None => { + match db.all_crates().last() { + Some(last) => (*last).into(), + // short-circuit, return an empty vec of diagnostics + None => return vec![], + } + } + }; let display_target = krate.to_display_target(db); let ctx = DiagnosticsContext { config, sema, resolve, edition, is_nightly, display_target }; diff --git a/crates/ide-ssr/src/matching.rs b/crates/ide-ssr/src/matching.rs index 48d2431a11..a76516f44f 100644 --- a/crates/ide-ssr/src/matching.rs +++ b/crates/ide-ssr/src/matching.rs @@ -626,11 +626,9 @@ impl<'db, 'sema> Matcher<'db, 'sema> { match_error!("Failed to get receiver type for `{}`", expr.syntax().text()) })? .original; - let krate = self - .sema - .scope(expr.syntax()) - .map(|it| it.krate()) - .unwrap_or_else(|| hir::Crate::from(*self.sema.db.all_crates().last().unwrap())); + let krate = self.sema.scope(expr.syntax()).map(|it| it.krate()).unwrap_or_else(|| { + hir::Crate::from(*self.sema.db.all_crates().last().expect("no crate graph present")) + }); let res = code_type .autoderef(self.sema.db) .enumerate() diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index b00de6ba40..04189ed52a 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -130,7 +130,7 @@ pub(crate) fn hover( let file = sema.parse_guess_edition(file_id).syntax().clone(); let edition = sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); - let display_target = sema.first_crate_or_default(file_id).to_display_target(db); + let display_target = sema.first_crate(file_id)?.to_display_target(db); let mut res = if range.is_empty() { hover_offset( sema, diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 3a709e71fb..57adf3e2a4 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -211,7 +211,10 @@ fn hints( file_id: EditionedFileId, node: SyntaxNode, ) { - let display_target = sema.first_crate_or_default(file_id.file_id()).to_display_target(sema.db); + let Some(krate) = sema.first_crate(file_id.file_id()) else { + return; + }; + let display_target = krate.to_display_target(sema.db); closing_brace::hints(hints, sema, config, file_id, display_target, node.clone()); if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { generic_param::hints(hints, famous_defs, config, any_has_generic_args); diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index baa7ee6897..f2cb3c1f99 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -498,8 +498,9 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { }; let krate = def.krate(db); let edition = krate.map(|it| it.edition(db)).unwrap_or(Edition::CURRENT); - let display_target = - krate.unwrap_or_else(|| (*db.all_crates().last().unwrap()).into()).to_display_target(db); + let display_target = krate + .unwrap_or_else(|| (*db.all_crates().last().expect("no crate graph present")).into()) + .to_display_target(db); if !has_runnable_doc_test(&attrs) { return None; } diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index b5468a5aee..84912f6be6 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -84,7 +84,7 @@ pub(crate) fn signature_help( let token = sema.descend_into_macros_single_exact(token); let edition = sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); - let display_target = sema.first_crate_or_default(file_id).to_display_target(db); + let display_target = sema.first_crate(file_id)?.to_display_target(db); for node in token.parent_ancestors() { match_ast! { diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 5a2b09b513..c156276930 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -119,7 +119,9 @@ fn documentation_for_definition( sema.db, famous_defs.as_ref(), def.krate(sema.db) - .unwrap_or_else(|| (*sema.db.all_crates().last().unwrap()).into()) + .unwrap_or_else(|| { + (*sema.db.all_crates().last().expect("no crate graph present")).into() + }) .to_display_target(sema.db), ) } @@ -175,7 +177,10 @@ impl StaticIndex<'_> { let root = sema.parse_guess_edition(file_id).syntax().clone(); let edition = sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); - let display_target = sema.first_crate_or_default(file_id).to_display_target(self.db); + let display_target = match sema.first_crate(file_id) { + Some(krate) => krate.to_display_target(sema.db), + None => return, + }; let tokens = root.descendants_with_tokens().filter_map(|it| match it { syntax::NodeOrToken::Node(_) => None, syntax::NodeOrToken::Token(it) => Some(it), diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index 34bca7bce1..02e3b1d500 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -83,7 +83,7 @@ pub(crate) fn view_memory_layout( ) -> Option { let sema = Semantics::new(db); let file = sema.parse_guess_edition(position.file_id); - let display_target = sema.first_crate_or_default(position.file_id).to_display_target(db); + let display_target = sema.first_crate(position.file_id)?.to_display_target(db); let token = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { SyntaxKind::IDENT => 3, diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index a391a01fae..1efc242bfb 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -384,8 +384,10 @@ impl flags::AnalysisStats { for &file_id in &file_ids { let sema = hir::Semantics::new(db); - let display_target = - sema.first_crate_or_default(file_id.file_id()).to_display_target(db); + let display_target = match sema.first_crate(file_id.file_id()) { + Some(krate) => krate.to_display_target(sema.db), + None => continue, + }; let parse = sema.parse_guess_edition(file_id.into()); let file_txt = db.file_text(file_id.into());