@@ -62,6 +62,8 @@ type file struct {
6262 objectInfo storage.ObjectInfo // Info in the context of the workspace.
6363
6464 ir * ir.File
65+ irQuery queries.IR
66+ fileQuery queries.File
6567 referenceableSymbols map [ir.FullName ]* symbol
6668 referenceSymbols []* symbol
6769 symbols []* symbol
@@ -97,6 +99,11 @@ func (f *file) Reset(ctx context.Context) {
9799 f .workspace .Release ()
98100 f .workspace = nil
99101 }
102+ // Evict the query key if there is a query cached on the file. We cache the [queries.File]
103+ // query since this allows the executor to evict all dependent queries, e.g. AST and IR.
104+ if f .fileQuery .Path != "" {
105+ f .lsp .queryExecutor .Evict (f .fileQuery .Key ())
106+ }
100107 // Clear the file as nothing should use it after reset. This asserts that.
101108 * f = file {}
102109}
@@ -229,21 +236,46 @@ func (f *file) RefreshIR(ctx context.Context) {
229236 // Opener creates a cached view of all files in the workspace.
230237 pathToFiles := f .workspace .PathToFile ()
231238 files := make ([]* file , 0 , len (pathToFiles ))
232- openerMap := make (map [string ]* source.File , len (pathToFiles ))
239+ var evictQueryKeys []any
240+
241+ openerMap := f .lsp .opener .Get ()
233242 for path , file := range pathToFiles {
234- openerMap [path ] = file .file
243+ current := openerMap [path ]
244+ // If there is no entry for the current path or if the file content has changed, we
245+ // update the opener and set a new query.
246+ if current == nil || current .Text () != file .file .Text () {
247+ openerMap [path ] = file .file
248+ // Add the query key for eviction if there is a query cached on the file. We cache
249+ // the [queries.File] query since this allows the executor to evict all dependent
250+ // queries, e.g. AST and IR.
251+ if file .fileQuery .Path != "" {
252+ evictQueryKeys = append (evictQueryKeys , file .fileQuery .Key ())
253+ }
254+ file .fileQuery = queries.File {
255+ Opener : file .lsp .opener ,
256+ Path : path ,
257+ ReportError : true , // [queries.AST] sets this to be true.
258+ }
259+ file .irQuery = queries.IR {
260+ Opener : file .lsp .opener ,
261+ Path : file .objectInfo .Path (),
262+ Session : file .lsp .irSession ,
263+ }
264+ }
235265 files = append (files , file )
236266 }
237- opener := source .NewMap (openerMap )
267+ // Remove paths that are no longer in the current workspace and evict stale query keys.
268+ for path := range openerMap {
269+ if _ , ok := pathToFiles [path ]; ! ok {
270+ delete (openerMap , path )
271+ }
272+ }
273+ f .lsp .queryExecutor .Evict (evictQueryKeys ... )
238274
239- session := new (ir.Session )
240275 queries := xslices .Map (files , func (file * file ) incremental.Query [* ir.File ] {
241- return queries.IR {
242- Opener : opener ,
243- Path : file .objectInfo .Path (),
244- Session : session ,
245- }
276+ return file .irQuery
246277 })
278+
247279 results , diagnosticReport , err := incremental .Run (
248280 ctx ,
249281 f .lsp .queryExecutor ,
0 commit comments