mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	fix: Fix semantics not always correctly caching file roots
This commit is contained in:
		
							parent
							
								
									d82e1a2472
								
							
						
					
					
						commit
						d32b09dc1b
					
				
					 2 changed files with 36 additions and 40 deletions
				
			
		|  | @ -136,8 +136,6 @@ pub struct Semantics<'db, DB> { | ||||||
| pub struct SemanticsImpl<'db> { | pub struct SemanticsImpl<'db> { | ||||||
|     pub db: &'db dyn HirDatabase, |     pub db: &'db dyn HirDatabase, | ||||||
|     s2d_cache: RefCell<SourceToDefCache>, |     s2d_cache: RefCell<SourceToDefCache>, | ||||||
|     /// Rootnode to HirFileId cache
 |  | ||||||
|     root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, |  | ||||||
|     /// MacroCall to its expansion's MacroFileId cache
 |     /// MacroCall to its expansion's MacroFileId cache
 | ||||||
|     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroFileId>>, |     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroFileId>>, | ||||||
| } | } | ||||||
|  | @ -304,12 +302,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> { | ||||||
| 
 | 
 | ||||||
| impl<'db> SemanticsImpl<'db> { | impl<'db> SemanticsImpl<'db> { | ||||||
|     fn new(db: &'db dyn HirDatabase) -> Self { |     fn new(db: &'db dyn HirDatabase) -> Self { | ||||||
|         SemanticsImpl { |         SemanticsImpl { db, s2d_cache: Default::default(), macro_call_cache: Default::default() } | ||||||
|             db, |  | ||||||
|             s2d_cache: Default::default(), |  | ||||||
|             root_to_file_cache: Default::default(), |  | ||||||
|             macro_call_cache: Default::default(), |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile { |     pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile { | ||||||
|  | @ -483,7 +476,7 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|             Some( |             Some( | ||||||
|                 calls |                 calls | ||||||
|                     .into_iter() |                     .into_iter() | ||||||
|                     .map(|call| macro_call_to_macro_id(self, ctx, call?).map(|id| Macro { id })) |                     .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id })) | ||||||
|                     .collect(), |                     .collect(), | ||||||
|             ) |             ) | ||||||
|         }) |         }) | ||||||
|  | @ -962,7 +955,7 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|             let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { |             let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { | ||||||
|                 Some( |                 Some( | ||||||
|                     ctx.cache |                     ctx.cache | ||||||
|                         .get_or_insert_expansion(self, macro_file) |                         .get_or_insert_expansion(ctx.db, macro_file) | ||||||
|                         .map_range_down(span)? |                         .map_range_down(span)? | ||||||
|                         .map(SmallVec::<[_; 2]>::from_iter), |                         .map(SmallVec::<[_; 2]>::from_iter), | ||||||
|                 ) |                 ) | ||||||
|  | @ -1287,7 +1280,7 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|                     let macro_file = file_id.macro_file()?; |                     let macro_file = file_id.macro_file()?; | ||||||
| 
 | 
 | ||||||
|                     self.with_ctx(|ctx| { |                     self.with_ctx(|ctx| { | ||||||
|                         let expansion_info = ctx.cache.get_or_insert_expansion(self, macro_file); |                         let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); | ||||||
|                         expansion_info.arg().map(|node| node?.parent()).transpose() |                         expansion_info.arg().map(|node| node?.parent()).transpose() | ||||||
|                     }) |                     }) | ||||||
|                 } |                 } | ||||||
|  | @ -1318,8 +1311,8 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> { |     pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> { | ||||||
|         let (parent, label_id) = self |         let src = self.wrap_node_infile(label.clone()); | ||||||
|             .with_ctx(|ctx| ctx.label_ref_to_def(self.wrap_node_infile(label.clone()).as_ref()))?; |         let (parent, label_id) = self.with_ctx(|ctx| ctx.label_ref_to_def(src.as_ref()))?; | ||||||
|         Some(Label { parent, label_id }) |         Some(Label { parent, label_id }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1519,7 +1512,7 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); |         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); | ||||||
|         self.with_ctx(|ctx| { |         self.with_ctx(|ctx| { | ||||||
|             ctx.macro_call_to_macro_call(macro_call) |             ctx.macro_call_to_macro_call(macro_call) | ||||||
|                 .and_then(|call| macro_call_to_macro_id(self, ctx, call)) |                 .and_then(|call| macro_call_to_macro_id(ctx, call)) | ||||||
|                 .map(Into::into) |                 .map(Into::into) | ||||||
|         }) |         }) | ||||||
|         .or_else(|| { |         .or_else(|| { | ||||||
|  | @ -1561,7 +1554,7 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|         let item_in_file = self.wrap_node_infile(item.clone()); |         let item_in_file = self.wrap_node_infile(item.clone()); | ||||||
|         let id = self.with_ctx(|ctx| { |         let id = self.with_ctx(|ctx| { | ||||||
|             let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?; |             let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?; | ||||||
|             macro_call_to_macro_id(self, ctx, macro_call_id) |             macro_call_to_macro_id(ctx, macro_call_id) | ||||||
|         })?; |         })?; | ||||||
|         Some(Macro { id }) |         Some(Macro { id }) | ||||||
|     } |     } | ||||||
|  | @ -1725,10 +1718,11 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { |     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { | ||||||
|         assert!(root_node.parent().is_none()); |         SourceToDefCache::cache( | ||||||
|         let mut cache = self.root_to_file_cache.borrow_mut(); |             &mut self.s2d_cache.borrow_mut().root_to_file_cache, | ||||||
|         let prev = cache.insert(root_node, file_id); |             root_node, | ||||||
|         assert!(prev.is_none() || prev == Some(file_id)); |             file_id, | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn assert_contains_node(&self, node: &SyntaxNode) { |     pub fn assert_contains_node(&self, node: &SyntaxNode) { | ||||||
|  | @ -1736,8 +1730,8 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> { |     fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> { | ||||||
|         let cache = self.root_to_file_cache.borrow(); |         let cache = self.s2d_cache.borrow(); | ||||||
|         cache.get(root_node).copied() |         cache.root_to_file_cache.get(root_node).copied() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> { |     fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> { | ||||||
|  | @ -1761,8 +1755,9 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|                  known nodes: {}\n\n",
 |                  known nodes: {}\n\n",
 | ||||||
|                 node, |                 node, | ||||||
|                 root_node, |                 root_node, | ||||||
|                 self.root_to_file_cache |                 self.s2d_cache | ||||||
|                     .borrow() |                     .borrow() | ||||||
|  |                     .root_to_file_cache | ||||||
|                     .keys() |                     .keys() | ||||||
|                     .map(|it| format!("{it:?}")) |                     .map(|it| format!("{it:?}")) | ||||||
|                     .collect::<Vec<_>>() |                     .collect::<Vec<_>>() | ||||||
|  | @ -1909,7 +1904,6 @@ impl<'db> SemanticsImpl<'db> { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn macro_call_to_macro_id( | fn macro_call_to_macro_id( | ||||||
|     sema: &SemanticsImpl<'_>, |  | ||||||
|     ctx: &mut SourceToDefCtx<'_, '_>, |     ctx: &mut SourceToDefCtx<'_, '_>, | ||||||
|     macro_call_id: MacroCallId, |     macro_call_id: MacroCallId, | ||||||
| ) -> Option<MacroId> { | ) -> Option<MacroId> { | ||||||
|  | @ -1925,7 +1919,7 @@ fn macro_call_to_macro_id( | ||||||
|                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) |                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) | ||||||
|                 } |                 } | ||||||
|                 HirFileIdRepr::MacroFile(macro_file) => { |                 HirFileIdRepr::MacroFile(macro_file) => { | ||||||
|                     let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file); |                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); | ||||||
|                     it.to_ptr(db).to_node(&expansion_info.expanded().value) |                     it.to_ptr(db).to_node(&expansion_info.expanded().value) | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|  | @ -1937,7 +1931,7 @@ fn macro_call_to_macro_id( | ||||||
|                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) |                     it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) | ||||||
|                 } |                 } | ||||||
|                 HirFileIdRepr::MacroFile(macro_file) => { |                 HirFileIdRepr::MacroFile(macro_file) => { | ||||||
|                     let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file); |                     let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); | ||||||
|                     it.to_ptr(db).to_node(&expansion_info.expanded().value) |                     it.to_ptr(db).to_node(&expansion_info.expanded().value) | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|  | @ -110,10 +110,7 @@ use syntax::{ | ||||||
|     AstNode, AstPtr, SyntaxNode, |     AstNode, AstPtr, SyntaxNode, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{db::HirDatabase, semantics::child_by_source::ChildBySource, InFile, InlineAsmOperand}; | ||||||
|     db::HirDatabase, semantics::child_by_source::ChildBySource, InFile, InlineAsmOperand, |  | ||||||
|     SemanticsImpl, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| #[derive(Default)] | #[derive(Default)] | ||||||
| pub(super) struct SourceToDefCache { | pub(super) struct SourceToDefCache { | ||||||
|  | @ -121,9 +118,21 @@ pub(super) struct SourceToDefCache { | ||||||
|     expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>, |     expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>, | ||||||
|     pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>, |     pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>, | ||||||
|     pub(super) included_file_cache: FxHashMap<EditionedFileId, Option<MacroFileId>>, |     pub(super) included_file_cache: FxHashMap<EditionedFileId, Option<MacroFileId>>, | ||||||
|  |     /// Rootnode to HirFileId cache
 | ||||||
|  |     pub(super) root_to_file_cache: FxHashMap<SyntaxNode, HirFileId>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl SourceToDefCache { | impl SourceToDefCache { | ||||||
|  |     pub(super) fn cache( | ||||||
|  |         root_to_file_cache: &mut FxHashMap<SyntaxNode, HirFileId>, | ||||||
|  |         root_node: SyntaxNode, | ||||||
|  |         file_id: HirFileId, | ||||||
|  |     ) { | ||||||
|  |         assert!(root_node.parent().is_none()); | ||||||
|  |         let prev = root_to_file_cache.insert(root_node, file_id); | ||||||
|  |         assert!(prev.is_none() || prev == Some(file_id)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub(super) fn get_or_insert_include_for( |     pub(super) fn get_or_insert_include_for( | ||||||
|         &mut self, |         &mut self, | ||||||
|         db: &dyn HirDatabase, |         db: &dyn HirDatabase, | ||||||
|  | @ -143,14 +152,14 @@ impl SourceToDefCache { | ||||||
| 
 | 
 | ||||||
|     pub(super) fn get_or_insert_expansion( |     pub(super) fn get_or_insert_expansion( | ||||||
|         &mut self, |         &mut self, | ||||||
|         sema: &SemanticsImpl<'_>, |         db: &dyn HirDatabase, | ||||||
|         macro_file: MacroFileId, |         macro_file: MacroFileId, | ||||||
|     ) -> &ExpansionInfo { |     ) -> &ExpansionInfo { | ||||||
|         self.expansion_info_cache.entry(macro_file).or_insert_with(|| { |         self.expansion_info_cache.entry(macro_file).or_insert_with(|| { | ||||||
|             let exp_info = macro_file.expansion_info(sema.db.upcast()); |             let exp_info = macro_file.expansion_info(db.upcast()); | ||||||
| 
 | 
 | ||||||
|             let InMacroFile { file_id, value } = exp_info.expanded(); |             let InMacroFile { file_id, value } = exp_info.expanded(); | ||||||
|             sema.cache(value, file_id.into()); |             Self::cache(&mut self.root_to_file_cache, value, file_id.into()); | ||||||
| 
 | 
 | ||||||
|             exp_info |             exp_info | ||||||
|         }) |         }) | ||||||
|  | @ -520,18 +529,11 @@ impl SourceToDefCtx<'_, '_> { | ||||||
|         node: InFile<&SyntaxNode>, |         node: InFile<&SyntaxNode>, | ||||||
|         mut cb: impl FnMut(&mut Self, InFile<SyntaxNode>) -> Option<T>, |         mut cb: impl FnMut(&mut Self, InFile<SyntaxNode>) -> Option<T>, | ||||||
|     ) -> Option<T> { |     ) -> Option<T> { | ||||||
|         use hir_expand::MacroFileIdExt; |  | ||||||
|         let parent = |this: &mut Self, node: InFile<&SyntaxNode>| match node.value.parent() { |         let parent = |this: &mut Self, node: InFile<&SyntaxNode>| match node.value.parent() { | ||||||
|             Some(parent) => Some(node.with_value(parent)), |             Some(parent) => Some(node.with_value(parent)), | ||||||
|             None => { |             None => { | ||||||
|                 let macro_file = node.file_id.macro_file()?; |                 let macro_file = node.file_id.macro_file()?; | ||||||
| 
 |                 let expansion_info = this.cache.get_or_insert_expansion(this.db, macro_file); | ||||||
|                 let expansion_info = this |  | ||||||
|                     .cache |  | ||||||
|                     .expansion_info_cache |  | ||||||
|                     .entry(macro_file) |  | ||||||
|                     .or_insert_with(|| macro_file.expansion_info(this.db.upcast())); |  | ||||||
| 
 |  | ||||||
|                 expansion_info.arg().map(|node| node?.parent()).transpose() |                 expansion_info.arg().map(|node| node?.parent()).transpose() | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth