Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement: Base Metals view on indexing information #5622

Merged
merged 7 commits into from
Nov 8, 2023

Conversation

tgodzik
Copy link
Contributor

@tgodzik tgodzik commented Sep 6, 2023

Previously, we would read the classpath to create the metals view, which worked well for Scala 2, but needed a reimplementation for Scala 3. So now, instead of doing this reimplementation, which would probably need to use tasty and might be quite complex, I decided to base it on the same approach we use for inexing.

This makes the feature more reliable since, we now used the same well tested functionaties as things like go to definition.

Unfortunately, we might index the particular files the second time, because the basic indexing caches are reversed and finding all symbols in a file from those maps was much slower than just doing it the second time. We later cache that information the same way we did in the previous tree view implementation. So we won't use more memory and running the benchmarks show that the new approach is similarily fast:

[info] Benchmark                  Mode  Cnt    Score    Error  Units
[info] ClasspathSymbolsBench.run    ss   10  391.553 ± 39.018  ms/op

as compared to the previous:

[info] Benchmark                  Mode  Cnt    Score    Error  Units
[info] ClasspathSymbolsBench.run    ss   10  286.283 ± 81.565  ms/op

Also it seems we index much more information, since mtags index all symbols, which would also explain the slight difference in timings as I think the difference was 1300 symbols previously and 17000 after this change (number of symbols detected in the benchmarks)

Fixes #2859

@tgodzik tgodzik force-pushed the alternative-tree-view branch 3 times, most recently from bf876d3 to 658291e Compare September 13, 2023 09:34
*/
val expectedLibraries: SortedSet[String] = {
lazy val jdk8Libraries = SortedSet(
"charsets", "jce", "jsse", "resources", "rt",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these sources are contained in src.zip for the JDK

@tgodzik tgodzik marked this pull request as ready for review September 13, 2023 09:36
Copy link
Contributor

@kasiaMarek kasiaMarek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could have some other entity responsible for calculating toplevelsAt and symbolsAt? It just feels like those don't use or change the state of SymbolIndexBucket, so all other things in that class are noise.

// Used for dependencies, is lazy, TopLevel is changed to AllSymbols when needed
private val jarCache = TrieMap.empty[
AbsolutePath,
TrieMap[String, Either[TopLevel, AllSymbols]],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the path here is the path to the jar? Maybe it's a bit more readable to have a separate map, where you have (scala file path -> AllSymbols) for jars too. I also will avoid repeating the same set for all top-levels in the same file.

private def symbolsForPackage(
cached: Either[TopLevel, AllSymbols],
dialect: Dialect,
jarSymbols: TrieMap[String, Either[TopLevel, AllSymbols]],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me passing it and changing it in the method obscures the updates made on jarCache.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I inlined the method back, wasn't sure how to make the method less long.

@tgodzik tgodzik force-pushed the alternative-tree-view branch 2 times, most recently from c077675 to 2cbdc08 Compare October 25, 2023 13:43
@tgodzik
Copy link
Contributor Author

tgodzik commented Oct 25, 2023

Maybe we could have some other entity responsible for calculating toplevelsAt and symbolsAt? It just feels like those don't use or change the state of SymbolIndexBucket, so all other things in that class are noise.

I inlined everything into IndexedSymbols class since it's used only there.

@tgodzik tgodzik force-pushed the alternative-tree-view branch from 2cbdc08 to 36e9926 Compare October 25, 2023 14:47
@tgodzik tgodzik requested a review from kasiaMarek October 25, 2023 14:47
case k.FIELD =>
if (child.properties.isEnum) "enum"
else "field"
case k.OBJECT | k.PACKAGE_OBJECT => "symbol-object"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed these to use the VS Code defaults (which can be replaced by a theme etc.) instead of the custom one. I think it makes sense to use the same everywhere and we were missing some such as type.

@tgodzik
Copy link
Contributor Author

tgodzik commented Oct 25, 2023

Och damn, one test is failing on ubuntu :/

@tgodzik tgodzik force-pushed the alternative-tree-view branch 3 times, most recently from 5ef9193 to fc9cf4a Compare October 25, 2023 18:38
@@ -1831,13 +1835,34 @@ final case class TestingServer(
.toMap
.updated("root", "root")

def label(uri: String, default: String): String =
labelsMap.get(uri) match {
/* fallback for JDK sources since we seem to have issues on CI
Copy link
Contributor Author

@tgodzik tgodzik Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to work around an issue in ubuntu CI jobs. We somehow had two different src.zip for Java in two different java homes. One was produced by reveal and the other from workspace search. Both should use exactly the same JDK homes, but somehow they don't.

I wasn't able to reproduce or figure it out at any point and I think it would be waste of time to fix it since it only influences tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, maybe I will try one more thing.

if (!Character.isLowSurrogate(lo))
readerError("invalid unicode surrogate pair", at = begCharOffset)
else {
if (!Character.isLowSurrogate(lo)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This started failing on some of the sources and I have no idea why. It's not really important as it's only used for indexing.

@tgodzik tgodzik force-pushed the alternative-tree-view branch 7 times, most recently from 82738ec to 26ddcda Compare October 27, 2023 08:34
Previously, we would read the classpath to create the metals view, which worked well for Scala 2, but needed a reimplementation for Scala 3. So now, instead of doing this reimplementation, which would probably need to use tasty and might be quite complex, I decided to base it on the same approach we use for inexing.

This makes the feature more reliable since, we now used the same well tested functionaties as things like go to definition.

Unfortunately, we might index the particular files the second time, because the basic indexing caches are reversed and finding all symbols in a file from those maps was much slower than just doing it the second time. We later cache that information the same way we did in the previous tree view implementation. So we won't use more memory and running the benchmarks show that the new approach is similarily fast:

```
[info] Benchmark                  Mode  Cnt    Score    Error  Units
[info] ClasspathSymbolsBench.run    ss   10  542.090 ± 61.953  ms/op
```

as compared to the previous:
```
[info] Benchmark                  Mode  Cnt    Score    Error  Units
[info] ClasspathSymbolsBench.run    ss   10  477.283 ± 93.933  ms/op
```

Also it seems we index much more information, since mtags index all symbols, which would also explain the slight difference in timings as I think the difference was 1300 symbols previously and 17000 after this change (number of symbols detected in the benchmarks)

Fixes scalameta#2859
Also fix reveal, which didn't work before
@tgodzik tgodzik force-pushed the alternative-tree-view branch 8 times, most recently from 8da5d1a to 55ba37c Compare November 2, 2023 15:03
@tgodzik tgodzik force-pushed the alternative-tree-view branch from 55ba37c to 5f42d60 Compare November 2, 2023 16:25
@tgodzik tgodzik force-pushed the alternative-tree-view branch from 270b7a1 to a4558e8 Compare November 3, 2023 21:29
@tgodzik tgodzik requested a review from kasiaMarek November 3, 2023 21:32
@tgodzik tgodzik force-pushed the alternative-tree-view branch from a4558e8 to 00371af Compare November 5, 2023 16:31
Copy link
Contributor

@kasiaMarek kasiaMarek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good 👍

@tgodzik
Copy link
Contributor Author

tgodzik commented Nov 8, 2023

Double checked, but it seems I managed to get it faster than the previous approach now:

Previous:

[info] Benchmark                  Mode  Cnt    Score     Error  Units
[info] ClasspathSymbolsBench.run    ss   10  804.875 ± 246.653  ms/op

Current:

[info] Benchmark                  Mode  Cnt    Score    Error  Units
[info] ClasspathSymbolsBench.run    ss   10  378.369 ± 18.148  ms/op

@tgodzik tgodzik merged commit b5177c9 into scalameta:main Nov 8, 2023
24 checks passed
@tgodzik tgodzik deleted the alternative-tree-view branch November 8, 2023 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support project view in TVP panel for Scala 3
2 participants