@@ -1778,13 +1778,25 @@ func (s *snapshot) clone(ctx, bgCtx context.Context, changes map[span.URI]*fileC
1778
1778
}
1779
1779
1780
1780
// TODO(adonovan): merge loops over "changes".
1781
- for uri := range changes {
1782
- keys , ok := result .parseKeysByURI .Get (uri )
1783
- if ok {
1784
- for _ , key := range keys {
1785
- result .parsedGoFiles .Delete (key )
1781
+ for uri , change := range changes {
1782
+ // Optimization: if the content did not change, we don't need to evict the
1783
+ // parsed file. This is not the case for e.g. the files map, which may
1784
+ // switch from on-disk state to overlay. Parsed files depend only on
1785
+ // content and parse mode (which is captured in the parse key).
1786
+ //
1787
+ // NOTE: This also makes it less likely that we re-parse a file due to a
1788
+ // cache-miss but get a cache-hit for the corresponding package. In the
1789
+ // past, there was code that relied on ParseGo returning the type-checked
1790
+ // syntax tree. That code was wrong, but avoiding invalidation here limits
1791
+ // the blast radius of these types of bugs.
1792
+ if ! change .isUnchanged {
1793
+ keys , ok := result .parseKeysByURI .Get (uri )
1794
+ if ok {
1795
+ for _ , key := range keys {
1796
+ result .parsedGoFiles .Delete (key )
1797
+ }
1798
+ result .parseKeysByURI .Delete (uri )
1786
1799
}
1787
- result .parseKeysByURI .Delete (uri )
1788
1800
}
1789
1801
1790
1802
// Invalidate go.mod-related handles.
0 commit comments