-
Notifications
You must be signed in to change notification settings - Fork 3.1k
reifyTree shouldn't emit plain TypeTree()'s, but rather their reified versions #5
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
Conversation
… versions Related to SI-5230, review by @odersky.
It is confusing having a pull request open which is clearly not ready for submission. Closing; please reopen with a rebased branch when it's ready. |
Oh!! So it picked up the updates to the branch automatically! Actually, that was only the first commit I wanted to pull to scala/scala (one day ago). Today Martin and I did some development, so the branch got into this messy state. Sorry, didn't know that GitHub works that way. |
Now it copies in the current versions of BoxesRunTime and ScalaRunTime and applies patches to them, and the whole build is automated. # This is the only thing I actually typed, the rest is fancy echo. $ test/instrumented/mkinstrumented.sh build % rm -rf /scratch/trunk1/test/instrumented/classes % cp /scratch/trunk1/test/instrumented/../../src/library/scala/runtime/BoxesRunTime.java /scratch/trunk1/test/instrumented/../../src/library/scala/runtime/ScalaRunTime.scala /scratch/trunk1/test/instrumented/library/scala/runtime % patch BoxesRunTime.java /scratch/trunk1/test/instrumented/boxes.patch patching file BoxesRunTime.java % patch ScalaRunTime.scala /scratch/trunk1/test/instrumented/srt.patch patching file ScalaRunTime.scala Hunk #3 succeeded at 63 (offset 23 lines). Hunk #4 succeeded at 78 (offset 23 lines). Hunk #5 succeeded at 81 (offset 23 lines). Hunk #6 succeeded at 96 (offset 23 lines). % /scratch/trunk1/test/instrumented/../../build/pack/bin/scalac -d /scratch/trunk1/test/instrumented/classes /scratch/trunk1/test/instrumented/library/scala/runtime/BoxesRunTime.java /scratch/trunk1/test/instrumented/library/scala/runtime/ScalaRunTime.scala % javac -cp /scratch/trunk1/test/instrumented/../../build/pack/lib/scala-library.jar -d /scratch/trunk1/test/instrumented/classes /scratch/trunk1/test/instrumented/library/scala/runtime/BoxesRunTime.java % cd /scratch/trunk1/test/instrumented/classes % jar cf instrumented.jar . % mv -f instrumented.jar /scratch/trunk1/test/instrumented/../../test/files/speclib /scratch/trunk1/test/files/speclib/instrumented.jar has been created.
Fixing the usecase suggested by Jason
Specific optimizations to findMember that have become possible because findMembers is its own function now.
Specific optimizations to findMember that have become possible because findMembers is its own function now.
Swathes of important logic are duplicated between `findMember` and `findMembers` after they separated on grounds of irreconcilable differences about how fast they should run: d905558 Variation #10 to optimze findMember fcb0c01 Attempt #9 to opimize findMember. 71d2ceb Attempt #8 to opimize findMember. 77e5692 Attempty #7 to optimize findMember 275115e Fixing problem that caused fingerprints to fail in e94252e Attemmpt #6 to optimize findMember 73e61b8 Attempt #5 to optimize findMember. 04f0b65 Attempt #4 to optimize findMember 0e3c70f Attempt #3 to optimize findMember 41f4497 Attempt #2 to optimize findMember 1a73aa0 Attempt #1 to optimize findMember This didn't actually bear fruit, and the intervening years have seen the implementations drift. Now is the time to reunite them under the banner of `FindMemberBase`. Each has a separate subclass to customise the behaviour. This is primarily used by `findMember` to cache member types and to assemble the resulting list of symbols in an low-allocation manner. While there I have introduced some polymorphic calls, the call sites are only bi-morphic, and our typical pattern of compilation involves far more `findMember` calls, so I expect that JIT will keep the virtual call cost to an absolute minimum. Test results have been updated now that `findMembers` correctly excludes constructors and doesn't inherit privates. Coming up next: we can actually fix SI-7475!
Cut number of errors almost in half
Sip-23 unit tests
Manually tested with: ``` % cat sandbox/test.scala package p { object X { def f(i: Int) = ??? ; def f(s: String) = ??? } object Main { val res = X.f(3.14) } } % qscalac -Ytyper-debug sandbox/test.scala |-- p EXPRmode-POLYmode-QUALmode (site: package <root>) | \-> p.type |-- object X BYVALmode-EXPRmode (site: package p) | |-- super EXPRmode-POLYmode-QUALmode (silent: <init> in X) | | |-- this EXPRmode (silent: <init> in X) | | | \-> p.X.type | | \-> p.X.type | |-- def f BYVALmode-EXPRmode (site: object X) | | |-- $qmark$qmark$qmark EXPRmode (site: method f in X) | | | \-> Nothing | | |-- Int TYPEmode (site: value i in X) | | | \-> Int | | |-- Int TYPEmode (site: value i in X) | | | \-> Int | | \-> [def f] (i: Int)Nothing | |-- def f BYVALmode-EXPRmode (site: object X) | | |-- $qmark$qmark$qmark EXPRmode (site: method f in X) | | | \-> Nothing | | |-- String TYPEmode (site: value s in X) | | | [adapt] String is now a TypeTree(String) | | | \-> String | | |-- String TYPEmode (site: value s in X) | | | [adapt] String is now a TypeTree(String) | | | \-> String | | \-> [def f] (s: String)Nothing | \-> [object X] p.X.type |-- object Main BYVALmode-EXPRmode (site: package p) | |-- X.f(3.14) EXPRmode (site: value res in Main) | | |-- X.f BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value res in Main) | | | |-- X EXPRmode-POLYmode-QUALmode (silent: value res in Main) | | | | \-> p.X.type | | | \-> (s: String)Nothing <and> (i: Int)Nothing | | |-- 3.14 BYVALmode-EXPRmode (silent: value res in Main) | | | \-> Double(3.14) | | [search #1] start `<?>`, searching for adaptation to pt=Double => String (silent: value res in Main) implicits disabled | | [search #2] start `<?>`, searching for adaptation to pt=(=> Double) => String (silent: value res in Main) implicits disabled | | [search #3] start `<?>`, searching for adaptation to pt=Double => Int (silent: value res in Main) implicits disabled | | 1 implicits in companion scope | | [search #4] start `<?>`, searching for adaptation to pt=(=> Double) => Int (silent: value res in Main) implicits disabled | | 1 implicits in companion scope | | second try: <error> and 3.14 | | [search #5] start `p.X.type`, searching for adaptation to pt=p.X.type => ?{def f(x$1: ? >: Double(3.14)): ?} (silent: value res in Main) implicits disabled | | [search #6] start `p.X.type`, searching for adaptation to pt=(=> p.X.type) => ?{def f(x$1: ? >: Double(3.14)): ?} (silent: value res in Main) implicits disabled sandbox/test.scala:4: error: overloaded method value f with alternatives: (s: String)Nothing <and> (i: Int)Nothing cannot be applied to (Double) val res = X.f(3.14) ^ ```
avoid using macro-based StringContext.f to ease bootstrap
The following commit message is a squash of several commit messages. - This is the 1st commit message: Add position to stub error messages Stub errors happen when we've started the initialization of a symbol but key information of this symbol is missing (the information cannot be found in any entry of the classpath not sources). When this error happens, we better have a good error message with a position to the place where the stub error came from. This commit goes into this direction by adding a `pos` value to `StubSymbol` and filling it in in all the use sites (especifically `UnPickler`). This commit also changes some tests that test stub errors-related issues. Concretely, `t6440` is using special Partest infrastructure and doens't pretty print the position, while `t5148` which uses the conventional infrastructure does. Hence the difference in the changes for both tests. - This is the commit message scala#2: Add partest infrastructure to test stub errors `StubErrorMessageTest` is the friend I introduce in this commit to help state stub errors. The strategy to test them is easy and builds upon previous concepts: we reuse `StoreReporterDirectTest` and add some methods that will compile the code and simulate a missing classpath entry by removing the class files from the class directory (the folder where Scalac compiles to). This first iteration allow us to programmatically check that stub errors are emitted under certain conditions. - This is the commit message scala#3: Improve contents of stub error message This commit does three things: * Keep track of completing symbol while unpickling First, it removes the previous `symbolOnCompletion` definition to be more restrictive/clear and use only positions, since only positions are used to report the error (the rest of the information comes from the context of the `UnPickler`). Second, it adds a new variable called `lazyCompletingSymbol` that is responsible for keeping a reference to the symbol that produces the stub error. This symbol will usually (always?) come from the classpath entries and therefore we don't have its position (that's why we keep track of `symbolOnCompletion` as well). This is the one that we have to explicitly use in the stub error message, the culprit so to speak. Aside from these two changes, this commit modifies the existing tests that are affected by the change in the error message, which is more precise now, and adds new tests for stub errors that happen in complex inner cases and in return type of `MethodType`. * Check that order of initialization is correct With the changes introduced previously to keep track of position of symbols coming from source files, we may ask ourselves: is this going to work always? What happens if two symbols the initialization of two symbols is intermingled and the stub error message gets the wrong position? This commit adds a test case and modifications to the test infrastructure to double check empirically that this does not happen. Usually, this interaction in symbol initialization won't happen because the `UnPickler` will lazily load all the buckets necessary for a symbol to be truly initialized, with the pertinent addresses from which this information has to be deserialized. This ensures that this operation is atomic and no other symbol initialization can happen in the meantime. Even though the previous paragraph is the feeling I got from reading the sources, this commit creates a test to double-check it. My attempt to be better safe than sorry. * Improve contents of the stub error message This commit modifies the format of the previous stub error message by being more precise in its formulation. It follows the structured format: ``` s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath. |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'. ``` This format has the advantage that is more readable and explicit on what's happening. First, we report what is missing. Then, why it was required. Hopefully, people working on direct dependencies will find the new message friendlier. Having a good test suite to check the previously added code is important. This commit checks that stub errors happen in presence of well-known and widely used Scala features. These include: * Higher kinded types. * Type definitions. * Inheritance and subclasses. * Typeclasses and implicits. - This is the commit message scala#4: Use `lastTreeToTyper` to get better positions The previous strategy to get the last user-defined position for knowing what was the root cause (the trigger) of stub errors relied on instrumenting `def info`. This instrumentation, while easy to implement, is inefficient since we register the positions for symbols that are already completed. However, we cannot do it only for uncompleted symbols (!hasCompleteInfo) because the positions won't be correct anymore -- definitions using stub symbols (val b = new B) are for the compiler completed, but their use throws stub errors. This means that if we initialize symbols between a definition and its use, we'll use their positions instead of the position of `b`. To work around this we use `lastTreeToTyper`. We assume that stub errors will be thrown by Typer at soonest. The benefit of this approach is better error messages. The positions used in them are now as concrete as possible since they point to the exact tree that **uses** a symbol, instead of the one that **defines** it. Have a look at `StubErrorComplexInnerClass` for an example. This commit removes the previous infrastructure and replaces it by the new one. It also removes the fields positions from the subclasses of `StubSymbol`s. - This is the commit message scala#5: Keep track of completing symbols Make sure that cycles don't happen by keeping track of all the symbols that are being completed by `completeInternal`. Stub errors only need the last completing symbols, but the whole stack of symbols may be useful to reporting other error like cyclic initialization issues. I've added this per Jason's suggestion. I've implemented with a list because `remove` in an array buffer is linear. Array was not an option because I would need to resize it myself. I think that even though list is not as efficient memory-wise, it probably doesn't matter since the stack will usually be small. - This is the commit message scala#6: Remove `isPackage` from `newStubSymbol` Remove `isPackage` since in 2.12.x its value is not used.
The following commit message is a squash of several commit messages. - This is the 1st commit message: Add position to stub error messages Stub errors happen when we've started the initialization of a symbol but key information of this symbol is missing (the information cannot be found in any entry of the classpath not sources). When this error happens, we better have a good error message with a position to the place where the stub error came from. This commit goes into this direction by adding a `pos` value to `StubSymbol` and filling it in in all the use sites (especifically `UnPickler`). This commit also changes some tests that test stub errors-related issues. Concretely, `t6440` is using special Partest infrastructure and doens't pretty print the position, while `t5148` which uses the conventional infrastructure does. Hence the difference in the changes for both tests. - This is the commit message scala#2: Add partest infrastructure to test stub errors `StubErrorMessageTest` is the friend I introduce in this commit to help state stub errors. The strategy to test them is easy and builds upon previous concepts: we reuse `StoreReporterDirectTest` and add some methods that will compile the code and simulate a missing classpath entry by removing the class files from the class directory (the folder where Scalac compiles to). This first iteration allow us to programmatically check that stub errors are emitted under certain conditions. - This is the commit message scala#3: Improve contents of stub error message This commit does three things: * Keep track of completing symbol while unpickling First, it removes the previous `symbolOnCompletion` definition to be more restrictive/clear and use only positions, since only positions are used to report the error (the rest of the information comes from the context of the `UnPickler`). Second, it adds 10000 a new variable called `lazyCompletingSymbol` that is responsible for keeping a reference to the symbol that produces the stub error. This symbol will usually (always?) come from the classpath entries and therefore we don't have its position (that's why we keep track of `symbolOnCompletion` as well). This is the one that we have to explicitly use in the stub error message, the culprit so to speak. Aside from these two changes, this commit modifies the existing tests that are affected by the change in the error message, which is more precise now, and adds new tests for stub errors that happen in complex inner cases and in return type of `MethodType`. * Check that order of initialization is correct With the changes introduced previously to keep track of position of symbols coming from source files, we may ask ourselves: is this going to work always? What happens if two symbols the initialization of two symbols is intermingled and the stub error message gets the wrong position? This commit adds a test case and modifications to the test infrastructure to double check empirically that this does not happen. Usually, this interaction in symbol initialization won't happen because the `UnPickler` will lazily load all the buckets necessary for a symbol to be truly initialized, with the pertinent addresses from which this information has to be deserialized. This ensures that this operation is atomic and no other symbol initialization can happen in the meantime. Even though the previous paragraph is the feeling I got from reading the sources, this commit creates a test to double-check it. My attempt to be better safe than sorry. * Improve contents of the stub error message This commit modifies the format of the previous stub error message by being more precise in its formulation. It follows the structured format: ``` s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath. |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'. ``` This format has the advantage that is more readable and explicit on what's happening. First, we report what is missing. Then, why it was required. Hopefully, people working on direct dependencies will find the new message friendlier. Having a good test suite to check the previously added code is important. This commit checks that stub errors happen in presence of well-known and widely used Scala features. These include: * Higher kinded types. * Type definitions. * Inheritance and subclasses. * Typeclasses and implicits. - This is the commit message scala#4: Use `lastTreeToTyper` to get better positions The previous strategy to get the last user-defined position for knowing what was the root cause (the trigger) of stub errors relied on instrumenting `def info`. This instrumentation, while easy to implement, is inefficient since we register the positions for symbols that are already completed. However, we cannot do it only for uncompleted symbols (!hasCompleteInfo) because the positions won't be correct anymore -- definitions using stub symbols (val b = new B) are for the compiler completed, but their use throws stub errors. This means that if we initialize symbols between a definition and its use, we'll use their positions instead of the position of `b`. To work around this we use `lastTreeToTyper`. We assume that stub errors will be thrown by Typer at soonest. The benefit of this approach is better error messages. The positions used in them are now as concrete as possible since they point to the exact tree that **uses** a symbol, instead of the one that **defines** it. Have a look at `StubErrorComplexInnerClass` for an example. This commit removes the previous infrastructure and replaces it by the new one. It also removes the fields positions from the subclasses of `StubSymbol`s. - This is the commit message scala#5: Keep track of completing symbols Make sure that cycles don't happen by keeping track of all the symbols that are being completed by `completeInternal`. Stub errors only need the last completing symbols, but the whole stack of symbols may be useful to reporting other error like cyclic initialization issues. I've added this per Jason's suggestion. I've implemented with a list because `remove` in an array buffer is linear. Array was not an option because I would need to resize it myself. I think that even though list is not as efficient memory-wise, it probably doesn't matter since the stack will usually be small. - This is the commit message scala#6: Remove `isPackage` from `newStubSymbol` Remove `isPackage` since in 2.12.x its value is not used.
The following commit message is a squash of several commit messages. - This is the 1st commit message: Add position to stub error messages Stub errors happen when we've started the initialization of a symbol but key information of this symbol is missing (the information cannot be found in any entry of the classpath not sources). When this error happens, we better have a good error message with a position to the place where the stub error came from. This commit goes into this direction by adding a `pos` value to `StubSymbol` and filling it in in all the use sites (especifically `UnPickler`). This commit also changes some tests that test stub errors-related issues. Concretely, `t6440` is using special Partest infrastructure and doens't pretty print the position, while `t5148` which uses the conventional infrastructure does. Hence the difference in the changes for both tests. - This is the commit message scala#2: Add partest infrastructure to test stub errors `StubErrorMessageTest` is the friend I introduce in this commit to help state stub errors. The strategy to test them is easy and builds upon previous concepts: we reuse `StoreReporterDirectTest` and add some methods that will compile the code and simulate a missing classpath entry by removing the class files from the class directory (the folder where Scalac compiles to). This first iteration allow us to programmatically check that stub errors are emitted under certain conditions. - This is the commit message scala#3: Improve contents of stub error message This commit does three things: * Keep track of completing symbol while unpickling First, it removes the previous `symbolOnCompletion` definition to be more restrictive/clear and use only positions, since only positions are used to report the error (the rest of the information comes from the context of the `UnPickler`). Second, it adds a new variable called `lazyCompletingSymbol` that is responsible for keeping a reference to the symbol that produces the stub error. This symbol will usually (always?) come from the classpath entries and therefore we don't have its position (that's why we keep track of `symbolOnCompletion` as well). This is the one that we have to explicitly use in the stub error message, the culprit so to speak. Aside from these two changes, this commit modifies the existing tests that are affected by the change in the error message, which is more precise now, and adds new tests for stub errors that happen in complex inner cases and in return type of `MethodType`. * Check that order of initialization is correct With the changes introduced previously to keep track of position of symbols coming from source files, we may ask ourselves: is this going to work always? What happens if two symbols the initialization of two symbols is intermingled and the stub error message gets the wrong position? This commit adds a test case and modifications to the test infrastructure to double check empirically that this does not happen. Usually, this interaction in symbol initialization won't happen because the `UnPickler` will lazily load all the buckets necessary for a symbol to be truly initialized, with the pertinent addresses from which this information has to be deserialized. This ensures that this operation is atomic and no other symbol initialization can happen in the meantime. Even though the previous paragraph is the feeling I got from reading the sources, this commit creates a test to double-check it. My attempt to be better safe than sorry. * Improve contents of the stub error message This commit modifies the format of the previous stub error message by being more precise in its formulation. It follows the structured format: ``` s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath. |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'. ``` This format has the advantage that is more readable and explicit on what's happening. First, we report what is missing. Then, why it was required. Hopefully, people working on direct dependencies will find the new message friendlier. Having a good test suite to check the previously added code is important. This commit checks that stub errors happen in presence of well-known and widely used Scala features. These include: * Higher kinded types. * Type definitions. * Inheritance and subclasses. * Typeclasses and implicits. - This is the commit message scala#4: Use `lastTreeToTyper` to get better positions The previous strategy to get the last user-defined position for knowing what was the root cause (the trigger) of stub errors relied on instrumenting `def info`. This instrumentation, while easy to implement, is inefficient since we register the positions for symbols that are already completed. However, we cannot do it only for uncompleted symbols (!hasCompleteInfo) because the positions won't be correct anymore -- definitions using stub symbols (val b = new B) are for the compiler completed, but their use throws stub errors. This means that if we initialize symbols between a definition and its use, we'll use their positions instead of the position of `b`. To work around this we use `lastTreeToTyper`. We assume that stub errors will be thrown by Typer at soonest. The benefit of this approach is better error messages. The positions used in them are now as concrete as possible since they point to the exact tree that **uses** a symbol, instead of the one that **defines** it. Have a look at `StubErrorComplexInnerClass` for an example. This commit removes the previous infrastructure and replaces it by the new one. It also removes the fields positions from the subclasses of `StubSymbol`s. - This is the commit message scala#5: Keep track of completing symbols Make sure that cycles don't happen by keeping track of all the symbols that are being completed by `completeInternal`. Stub errors only need the last completing symbols, but the whole stack of symbols may be useful to reporting other error like cyclic initialization issues. I've added this per Jason's suggestion. I've implemented with a list because `remove` in an array buffer is linear. Array was not an option because I would need to resize it myself. I think that even though list is not as efficient memory-wise, it probably doesn't matter since the stack will usually be small. - This is the commit message scala#6: Remove `isPackage` from `newStubSymbol` Remove `isPackage` since in 2.12.x its value is not used.
The following commit message is a squash of several commit messages. - This is the 1st commit message: Add position to stub error messages Stub errors happen when we've started the initialization of a symbol but key information of this symbol is missing (the information cannot be found in any entry of the classpath not sources). When this error happens, we better have a good error message with a position to the place where the stub error came from. This commit goes into this direction by adding a `pos` value to `StubSymbol` and filling it in in all the use sites (especifically `UnPickler`). This commit also changes some tests that test stub errors-related issues. Concretely, `t6440` is using special Partest infrastructure and doens't pretty print the position, while `t5148` which uses the conventional infrastructure does. Hence the difference in the changes for both tests. - This is the commit message scala#2: Add partest infrastructure to test stub errors `StubErrorMessageTest` is the friend I introduce in this commit to help state stub errors. The strategy to test them is easy and builds upon previous concepts: we reuse `StoreReporterDirectTest` and add some methods that will compile the code and simulate a missing classpath entry by removing the class files from the class directory (the folder where Scalac compiles to). This first iteration allow us to programmatically check that stub errors are emitted under certain conditions. - This is the commit message scala#3: Improve contents of stub error message This commit does three things: * Keep track of completing symbol while unpickling First, it removes the previous `symbolOnCompletion` definition to be more restrictive/clear and use only positions, since only positions are used to report the error (the rest of the information comes from the context of the `UnPickler`). Second, it adds a new variable called `lazyCompletingSymbol` that is responsible for keeping a reference to the symbol that produces the stub error. This symbol will usually (always?) come from the classpath entries and therefore we don't have its position (that's why we keep track of `symbolOnCompletion` as well). This is the one that we have to explicitly use in the stub error message, the culprit so to speak. Aside from these two changes, this commit modifies the existing tests that are affected by the change in the error message, which is more precise now, and adds new tests for stub errors that happen in complex inner cases and in return type of `MethodType`. * Check that order of initialization is correct With the changes introduced previously to keep track of position of symbols coming from source files, we may ask ourselves: is this going to work always? What happens if two symbols the initialization of two symbols is intermingled and the stub error message gets the wrong position? This commit adds a test case and modifications to the test infrastructure to double check empirically that this does not happen. Usually, this interaction in symbol initialization won't happen because the `UnPickler` will lazily load all the buckets necessary for a symbol to be truly initialized, with the pertinent addresses from which this information has to be deserialized. This ensures that this operation is atomic and no other symbol initialization can happen in the meantime. Even though the previous paragraph is the feeling I got from reading the sources, this commit creates a test to double-check it. My attempt to be better safe than sorry. * Improve contents of the stub error message This commit modifies the format of the previous stub error message by being more precise in its formulation. It follows the structured format: ``` s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath. |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'. ``` This format has the advantage that is more readable and explicit on what's happening. First, we report what is missing. Then, why it was required. Hopefully, people working on direct dependencies will find the new message friendlier. Having a good test suite to check the previously added code is important. This commit checks that stub errors happen in presence of well-known and widely used Scala features. These include: * Higher kinded types. * Type definitions. * Inheritance and subclasses. * Typeclasses and implicits. - This is the commit message scala#4: Use `lastTreeToTyper` to get better positions The previous strategy to get the last user-defined position for knowing what was the root cause (the trigger) of stub errors relied on instrumenting `def info`. This instrumentation, while easy to implement, is inefficient since we register the positions for symbols that are already completed. However, we cannot do it only for uncompleted symbols (!hasCompleteInfo) because the positions won't be correct anymore -- definitions using stub symbols (val b = new B) are for the compiler completed, but their use throws stub errors. This means that if we initialize symbols between a definition and its use, we'll use their positions instead of the position of `b`. To work around this we use `lastTreeToTyper`. We assume that stub errors will be thrown by Typer at soonest. The benefit of this approach is better error messages. The positions used in them are now as concrete as possible since they point to the exact tree that **uses** a symbol, instead of the one that **defines** it. Have a look at `StubErrorComplexInnerClass` for an example. This commit removes the previous infrastructure and replaces it by the new one. It also removes the fields positions from the subclasses of `StubSymbol`s. - This is the commit message scala#5: Keep track of completing symbols Make sure that cycles don't happen by keeping track of all the symbols that are being completed by `completeInternal`. Stub errors only need the last completing symbols, but the whole stack of symbols may be useful to reporting other error like cyclic initialization issues. I've added this per Jason's suggestion. I've implemented with a list because `remove` in an array buffer is linear. Array was not an option because I would need to resize it myself. I think that even though list is not as efficient memory-wise, it probably doesn't matter since the stack will usually be small. - This is the commit message scala#6: Remove `isPackage` from `newStubSymbol` Remove `isPackage` since in 2.12.x its value is not used.
The following commit message is a squash of several commit messages. - This is the 1st commit message: Add position to stub error messages Stub errors happen when we've started the initialization of a symbol but key information of this symbol is missing (the information cannot be found in any entry of the classpath not sources). When this error happens, we better have a good error message with a position to the place where the stub error came from. This commit goes into this direction by adding a `pos` value to `StubSymbol` and filling it in in all the use sites (especifically `UnPickler`). This commit also changes some tests that test stub errors-related issues. Concretely, `t6440` is using special Partest infrastructure and doens't pretty print the position, while `t5148` which uses the conventional infrastructure does. Hence the difference in the changes for both tests. - This is the commit message scala#2: Add partest infrastructure to test stub errors `StubErrorMessageTest` is the friend I introduce in this commit to help state stub errors. The strategy to test them is easy and builds upon previous concepts: we reuse `StoreReporterDirectTest` and add some methods that will compile the code and simulate a missing classpath entry by removing the class files from the class directory (the folder where Scalac compiles to). This first iteration allow us to programmatically check that stub errors are emitted under certain conditions. - This is the commit message scala#3: Improve contents of stub error message This commit does three things: * Keep track of completing symbol while unpickling First, it removes the previous `symbolOnCompletion` definition to be more restrictive/clear and use only positions, since only positions are used to report the error (the rest of the information comes from the context of the `UnPickler`). Second, it adds a new variable called `lazyCompletingSymbol` that is responsible for keeping a reference to the symbol that produces the stub error. This symbol will usually (always?) come from the classpath entries and therefore we don't have its position (that's why we keep track of `symbolOnCompletion` as well). This is the one that we have to explicitly use in the stub error message, the culprit so to speak. Aside from these two changes, this commit modifies the existing tests that are affected by the change in the error message, which is more precise now, and adds new tests for stub errors that happen in complex inner cases and in return type of `MethodType`. * Check that order of initialization is correct With the changes introduced previously to keep track of position of symbols coming from source files, we may ask ourselves: is this going to work always? What happens if two symbols the initialization of two symbols is intermingled and the stub error message gets the wrong position? This commit adds a test case and modifications to the test infrastructure to double check empirically that this does not happen. Usually, this interaction in symbol initialization won't happen because the `UnPickler` will lazily load all the buckets necessary for a symbol to be truly initialized, with the pertinent addresses from which this information has to be deserialized. This ensures that this operation is atomic and no other symbol initialization can happen in the meantime. Even though the previous paragraph is the feeling I got from reading the sources, this commit creates a test to double-check it. My attempt to be better safe than sorry. * Improve contents of the stub error message This commit modifies the format of the previous stub error message by being more precise in its formulation. It follows the structured format: ``` s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath. |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'. ``` This format has the advantage that is more readable and explicit on what's happening. First, we report what is missing. Then, why it was required. Hopefully, people working on direct dependencies will find the new message friendlier. Having a good test suite to check the previously added code is important. This commit checks that stub errors happen in presence of well-known and widely used Scala features. These include: * Higher kinded types. * Type definitions. * Inheritance and subclasses. * Typeclasses and implicits. - This is the commit message scala#4: Use `lastTreeToTyper` to get better positions The previous strategy to get the last user-defined position for knowing what was the root cause (the trigger) of stub errors relied on instrumenting `def info`. This instrumentation, while easy to implement, is inefficient since we register the positions for symbols that are already completed. However, we cannot do it only for uncompleted symbols (!hasCompleteInfo) because the positions won't be correct anymore -- definitions using stub symbols (val b = new B) are for the compiler completed, but their use throws stub errors. This means that if we initialize symbols between a definition and its use, we'll use their positions instead of the position of `b`. To work around this we use `lastTreeToTyper`. We assume that stub errors will be thrown by Typer at soonest. The benefit of this approach is better error messages. The positions used in them are now as concrete as possible since they point to the exact tree that **uses** a symbol, instead of the one that **defines** it. Have a look at `StubErrorComplexInnerClass` for an example. This commit removes the previous infrastructure and replaces it by the new one. It also removes the fields positions from the subclasses of `StubSymbol`s. - This is the commit message scala#5: Keep track of completing symbols Make sure that cycles don't happen by keeping track of all the symbols that are being completed by `completeInternal`. Stub errors only need the last completing symbols, but the whole stack of symbols may be useful to reporting other error like cyclic initialization issues. I've added this per Jason's suggestion. I've implemented with a list because `remove` in an array buffer is linear. Array was not an option because I would need to resize it myself. I think that even though list is not as efficient memory-wise, it probably doesn't matter since the stack will usually be small. - This is the commit message scala#6: Remove `isPackage` from `newStubSymbol` Remove `isPackage` since in 2.12.x its value is not used.
Make it clearer that the `iterator` method will return a fresh Iterator at each call
Rewritten from sbt/zinc@bba1b3f
Reify Tasty Names, which allows to reduce coupling
- Avoid lambda allocation in getOrElseUpdate call - Avoid intermediate Tuple2 instances when iterating through the mutable map. - Avoid allocating Map1-4 during building the result if the size of the grouped exceeds 4. Intead build a HashMap directly. ``` ./benchdb list --limit 2 && ./benchdb results --run 5 --run 6 --pivot size && ./benchdb results --run 5 --run 6 --pivot size --metric "·gc.alloc.rate.norm" ┏━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ ┃ ID ┃ Timestamp ┃ Msg ┃ ┣━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━┫ ┃ 6 ┃ 2020-08-24 07:14:36 ┃ PR 8948 ┃ ┃ 5 ┃ 2020-08-24 07:06:47 ┃ PR 8948 Baseline ┃ ┗━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛ 2 test runs found (limit reached). ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━┫ ┃ scala#5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8631.963 ┃ 116.790 ┃ 30969.939 ┃ 456.711 ┃ 119820.013 ┃ 1741.671 ┃ 480813.306 ┃ 7268.723 ┃ ns/op ┃ ┃ scala#6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8287.717 ┃ 135.038 ┃ 30672.551 ┃ 540.409 ┃ 119356.530 ┃ 1592.624 ┃ 477570.346 ┃ 6365.010 ┃ ns/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark [·gc.alloc.rate.norm] ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━┫ ┃ scala#5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 2192.014 ┃ 0.022 ┃ 13712.051 ┃ 0.076 ┃ 50949.533 ┃ 56.381 ┃ 198544.803 ┃ 1.213 ┃ B/op ┃ ┃ scala#6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 1896.014 ┃ 0.021 ┃ 5224.051 ┃ 0.077 ┃ 17768.204 ┃ 0.305 ┃ 67176.786 ┃ 1.180 ┃ B/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━┛ ```
- Avoid lambda allocation in getOrElseUpdate call - Avoid intermediate Tuple2 instances when iterating through the mutable map. - Avoid allocating Map1-4 during building the result if the size of the grouped exceeds 4. Intead build a HashMap directly. ``` ./benchdb list --limit 2 && ./benchdb results --run 5 --run 6 --pivot size && ./benchdb results --run 5 --run 6 --pivot size --metric "·gc.alloc.rate.norm" ┏━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ ┃ ID ┃ Timestamp ┃ Msg ┃ ┣━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━┫ ┃ 6 ┃ 2020-08-24 07:14:36 ┃ PR 8948 ┃ ┃ 5 ┃ 2020-08-24 07:06:47 ┃ PR 8948 Baseline ┃ ┗━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛ 2 test runs found (limit reached). ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━┫ ┃ #5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8631.963 ┃ 116.790 ┃ 30969.939 ┃ 456.711 ┃ 119820.013 ┃ 1741.671 ┃ 480813.306 ┃ 7268.723 ┃ ns/op ┃ ┃ #6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8287.717 ┃ 135.038 ┃ 30672.551 ┃ 540.409 ┃ 119356.530 ┃ 1592.624 ┃ 477570.346 ┃ 6365.010 ┃ ns/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark [·gc.alloc.rate.norm] ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━┫ ┃ #5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 2192.014 ┃ 0.022 ┃ 13712.051 ┃ 0.076 ┃ 50949.533 ┃ 56.381 ┃ 198544.803 ┃ 1.213 ┃ B/op ┃ ┃ #6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 1896.014 ┃ 0.021 ┃ 5224.051 ┃ 0.077 ┃ 17768.204 ┃ 0.305 ┃ 67176.786 ┃ 1.180 ┃ B/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━┛ ```
- Avoid lambda allocation in getOrElseUpdate call - Avoid intermediate Tuple2 instances when iterating through the mutable map. - Avoid allocating Map1-4 during building the result if the size of the grouped exceeds 4. Intead build a HashMap directly. ``` ./benchdb list --limit 2 && ./benchdb results --run 5 --run 6 --pivot size && ./benchdb results --run 5 --run 6 --pivot size --metric "·gc.alloc.rate.norm" ┏━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ ┃ ID ┃ Timestamp ┃ Msg ┃ ┣━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━┫ ┃ 6 ┃ 2020-08-24 07:14:36 ┃ PR 8948 ┃ ┃ 5 ┃ 2020-08-24 07:06:47 ┃ PR 8948 Baseline ┃ ┗━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛ 2 test runs found (limit reached). ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━┫ ┃ scala/scala#5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8631.963 ┃ 116.790 ┃ 30969.939 ┃ 456.711 ┃ 119820.013 ┃ 1741.671 ┃ 480813.306 ┃ 7268.723 ┃ ns/op ┃ ┃ scala/scala#6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8287.717 ┃ 135.038 ┃ 30672.551 ┃ 540.409 ┃ 119356.530 ┃ 1592.624 ┃ 477570.346 ┃ 6365.010 ┃ ns/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark [·gc.alloc.rate.norm] ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━┫ ┃ scala/scala#5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 2192.014 ┃ 0.022 ┃ 13712.051 ┃ 0.076 ┃ 50949.533 ┃ 56.381 ┃ 198544.803 ┃ 1.213 ┃ B/op ┃ ┃ scala/scala#6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 1896.014 ┃ 0.021 ┃ 5224.051 ┃ 0.077 ┃ 17768.204 ┃ 0.305 ┃ 67176.786 ┃ 1.180 ┃ B/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━┛ ```
- Avoid lambda allocation in getOrElseUpdate call - Avoid intermediate Tuple2 instances when iterating through the mutable map. - Avoid allocating Map1-4 during building the result if the size of the grouped exceeds 4. Intead build a HashMap directly. ``` ./benchdb list --limit 2 && ./benchdb results --run 5 --run 6 --pivot size && ./benchdb results --run 5 --run 6 --pivot size --metric "·gc.alloc.rate.norm" ┏━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ ┃ ID ┃ Timestamp ┃ Msg ┃ ┣━━━━╋━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━┫ ┃ 6 ┃ 2020-08-24 07:14:36 ┃ PR 8948 ┃ ┃ 5 ┃ 2020-08-24 07:06:47 ┃ PR 8948 Baseline ┃ ┗━━━━┻━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛ 2 test runs found (limit reached). ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━┫ ┃ scala/scala#5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8631.963 ┃ 116.790 ┃ 30969.939 ┃ 456.711 ┃ 119820.013 ┃ 1741.671 ┃ 480813.306 ┃ 7268.723 ┃ ns/op ┃ ┃ scala/scala#6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 8287.717 ┃ 135.038 ┃ 30672.551 ┃ 540.409 ┃ 119356.530 ┃ 1592.624 ┃ 477570.346 ┃ 6365.010 ┃ ns/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┓ ┃ (size) ┃ ┃ ┃ ┃ ┃ 128 ┃ 512 ┃ 2048 ┃ 8192 ┃ ┃ ┃ Benchmark [·gc.alloc.rate.norm] ┃ (hashCodeCost) ┃ (maxNumGroups) ┃ Mode ┃ Cnt ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Score ┃ Error ┃ Units ┃ ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━╋━━━━━╋━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━╋━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━┫ ┃ scala/scala#5:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 2192.014 ┃ 0.022 ┃ 13712.051 ┃ 0.076 ┃ 50949.533 ┃ 56.381 ┃ 198544.803 ┃ 1.213 ┃ B/op ┃ ┃ scala/scala#6:scala.collection.GroupByBenchmark.buildArrayBuffer ┃ 32 ┃ 8 ┃ avgt ┃ 30 ┃ 1896.014 ┃ 0.021 ┃ 5224.051 ┃ 0.077 ┃ 17768.204 ┃ 0.305 ┃ 67176.786 ┃ 1.180 ┃ B/op ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━┻━━━━━┻━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━┻━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━┛ ```
Related to SI-5230, review by @odersky.