Skip to content

Commit

Permalink
Keep annotation order
Browse files Browse the repository at this point in the history
This change makes sure non-repeated annotations are kept in the order
they were found in the source code.

The motivation is not necessarily to have them in the original order,
but to have them in an order that is deterministic across rebuilds
(potentially even across different machines), for reasons discussed
further in scala#7661 and the corresponding scala/scala-dev#405

I tried adding an 'integration test' in `tests/pos` to be picked up by
`IdempotencyCheck.scala`, but unfortunately couldn't reproduce the
nondeterminism that way, so didn't end up including it in this commit.

I didn't see an obvious place for a 'unit test' of this code, I'd be
happy to add one when someone can recommend a good place to put it.

This is basically the dotty equivalent of
scala/scala@954c5d3

Fixes scala#14743
  • Loading branch information
raboof committed Apr 28, 2022
1 parent 9d6e87a commit e5a22d2
Showing 1 changed file with 12 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Constants._
import Types._
import Decorators._

import scala.collection.mutable

class RepeatableAnnotations extends MiniPhase:

override def phaseName: String = RepeatableAnnotations.name
Expand All @@ -28,8 +30,8 @@ class RepeatableAnnotations extends MiniPhase:
tree

private def aggregateAnnotations(annotations: Seq[Annotation])(using Context): List[Annotation] =
val annsByType = annotations.groupBy(_.symbol)
annsByType.flatMap {
val annsByType = stableGroupBy[Annotation, Symbols.Symbol](annotations, _.symbol)
annsByType.flatMap[Annotation] {
case (_, a :: Nil) => a :: Nil
case (sym, anns) if sym.derivesFrom(defn.ClassfileAnnotationClass) =>
sym.getAnnotation(defn.JavaRepeatableAnnot).flatMap(_.argumentConstant(0)) match
Expand All @@ -50,6 +52,14 @@ class RepeatableAnnotations extends MiniPhase:
case (_, anns) => anns
}.toList

private def stableGroupBy[A, K](ins: Seq[A], f: A => K): scala.collection.MapView[K, List[A]] =
val out = new mutable.LinkedHashMap[K, mutable.ListBuffer[A]]()
for (in <- ins) {
val buffer = out.getOrElseUpdate(f(in), new mutable.ListBuffer)
buffer += in
}
out.view.mapValues(_.toList)

object RepeatableAnnotations:
val name: String = "repeatableAnnotations"
val description: String = "aggregate repeatable annotations"

0 comments on commit e5a22d2

Please sign in to comment.