Skip to content

Replace immutable and mutable HashSet and HashMap with the legacy Scala 2.12 implementations #125

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

Open
wants to merge 15 commits into
base: 2.13.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion project/MimaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,40 @@ object MimaFilters extends AutoPlugin {
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.concurrent.impl.FutureConvertersImpl#P.accept"),
ProblemFilters.exclude[IncompatibleMethTypeProblem]("scala.concurrent.impl.FutureConvertersImpl#P.andThen"),

ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.AnyChampStepper"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.AnyChampStepper$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.ChampStepperBase"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.DoubleChampStepper"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.DoubleChampStepper$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.IntChampStepper"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.IntChampStepper$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.LongChampStepper"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.convert.impl.LongChampStepper$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.BitmapIndexedMapNode"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.BitmapIndexedSetNode"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.ChampBaseIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.ChampBaseReverseIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashCollisionMapNode"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashCollisionSetNode"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashMap.this"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashMapBuilder"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.collection.immutable.HashSet.this"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.HashSetBuilder"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapKeyIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapKeyValueTupleHashIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapKeyValueTupleIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapKeyValueTupleReverseIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapNode"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapNode$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapNodeRemoveAllSetNodeIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.MapValueIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Node"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.Node$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.SetHashIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.SetIterator"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.SetNode"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.SetNode$"),
ProblemFilters.exclude[MissingClassProblem]("scala.collection.immutable.SetReverseIterator")
)

override val buildSettings = Seq(
Expand All @@ -47,7 +81,7 @@ object MimaFilters extends AutoPlugin {

val mimaSettings: Seq[Setting[_]] = Def.settings(
mimaPreviousArtifacts := mimaReferenceVersion.value.map(organization.value % name.value % _).toSet,
mimaCheckDirection := "both",
mimaCheckDirection := "backward",
mimaBinaryIssueFilters ++= mimaFilters,
// mimaReportSignatureProblems := true, // TODO: enable
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,6 @@ trait MatchOptimization extends MatchTreeMaking with MatchApproximation {
trait SwitchEmission extends TreeMakers with MatchMonadInterface {
import treeInfo.isGuardedCase

def inAsync: Boolean

abstract class SwitchMaker {
abstract class SwitchableTreeMakerExtractor { def unapply(x: TreeMaker): Option[Tree] }
val SwitchableTreeMaker: SwitchableTreeMakerExtractor
Expand Down Expand Up @@ -482,8 +480,8 @@ trait MatchOptimization extends MatchTreeMaking with MatchApproximation {
def wrapInDefaultLabelDef(cd: CaseDef): CaseDef =
if (needDefaultLabel) deriveCaseDef(cd){ b =>
// TODO: can b.tpe ever be null? can't really use pt, see e.g. pos/t2683 or cps/match1.scala
defaultLabel setInfo MethodType(Nil, if (b.tpe != null) b.tpe.deconst else pt)
LabelDef(defaultLabel, Nil, b)
defaultLabel setInfo MethodType(Nil, UnitTpe)
Block(LabelDef(defaultLabel, Nil, Literal(Constant(()))) :: Nil, b)
} else cd

val last = collapsed.last
Expand All @@ -499,7 +497,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchApproximation {
class RegularSwitchMaker(scrutSym: Symbol, matchFailGenOverride: Option[Tree => Tree], val unchecked: Boolean) extends SwitchMaker { import CODE._
val switchableTpe = Set(ByteTpe, ShortTpe, IntTpe, CharTpe, StringTpe)
val alternativesSupported = true
val canJump = !inAsync
val canJump = true

// Constant folding sets the type of a constant tree to `ConstantType(Constant(folded))`
// The tree itself can be a literal, an ident, a selection, ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,7 @@ trait PatternMatching extends Transform
def newTransformer(unit: CompilationUnit): AstTransformer = new MatchTransformer(unit)

class MatchTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
private var inAsync = false

override def transform(tree: Tree): Tree = tree match {
case dd: DefDef if async.hasAsyncAttachment(dd) =>
val wasInAsync = inAsync
try {
inAsync = true
super.transform(dd)
} finally
inAsync = wasInAsync

case CaseDef(UnApply(Apply(Select(qual, nme.unapply), Ident(nme.SELECTOR_DUMMY) :: Nil), (bind@Bind(b, Ident(nme.WILDCARD))) :: Nil), guard, body)
if guard.isEmpty && qual.symbol == definitions.NonFatalModule =>
Expand Down Expand Up @@ -113,13 +104,13 @@ trait PatternMatching extends Transform
}

def translator(selectorPos: Position): MatchTranslator with CodegenCore = {
new OptimizingMatchTranslator(localTyper, selectorPos, inAsync)
new OptimizingMatchTranslator(localTyper, selectorPos)
}

}


class OptimizingMatchTranslator(val typer: analyzer.Typer, val selectorPos: Position, val inAsync: Boolean)
class OptimizingMatchTranslator(val typer: analyzer.Typer, val selectorPos: Position)
extends MatchTranslator
with MatchOptimizer
with MatchAnalyzer
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1657,7 +1657,7 @@ abstract class RefChecks extends Transform {
sym.name == nme.apply &&
sym.isCase && // only synthetic case apply methods
isClassTypeAccessible &&
!fun.tpe.finalResultType.typeSymbol.primaryConstructor.isLessAccessibleThan(sym)
!sym.tpe.finalResultType.typeSymbol.primaryConstructor.isLessAccessibleThan(sym)
}

private def transformCaseApply(tpe: Type, pos: Position) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,6 @@ trait SyntheticMethods extends ast.TreeDSL {
createMethod(nme.hashCode_, Nil, IntTpe) { m =>
val accumulator = m.newVariable(newTermName("acc"), m.pos, SYNTHETIC) setInfo IntTpe
val valdef = ValDef(accumulator, Literal(Constant(0xcafebabe)))
val mixPrefix =
Assign(
Ident(accumulator),
callStaticsMethod("mix")(Ident(accumulator),
Apply(gen.mkAttributedSelect(gen.mkAttributedSelect(mkThis, Product_productPrefix), Object_hashCode), Nil)))
val mixes = accessors map (acc =>
Assign(
Ident(accumulator),
Expand All @@ -313,7 +308,7 @@ trait SyntheticMethods extends ast.TreeDSL {
)
val finish = callStaticsMethod("finalizeHash")(Ident(accumulator), Literal(Constant(arity)))

Block(valdef :: mixPrefix :: mixes, finish)
Block(valdef :: mixes, finish)
}
}
def chooseHashcode = {
Expand Down
85 changes: 71 additions & 14 deletions src/library/scala/collection/Iterable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import scala.annotation.nowarn
import scala.annotation.unchecked.uncheckedVariance
import scala.collection.mutable.Builder
import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped}
import scala.runtime.AbstractFunction0

/** Base trait for generic collections.
*
Expand Down Expand Up @@ -555,21 +556,77 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable
*
*/
def groupBy[K](f: A => K): immutable.Map[K, C] = {
val m = mutable.Map.empty[K, Builder[A, C]]
val it = iterator
while (it.hasNext) {
val elem = it.next()
val key = f(elem)
val bldr = m.getOrElseUpdate(key, newSpecificBuilder)
bldr += elem
}
var result = immutable.HashMap.empty[K, C]
val mapIt = m.iterator
while (mapIt.hasNext) {
val (k, v) = mapIt.next()
result = result.updated(k, v.result())
object grouper extends AbstractFunction0[Builder[A, C]] with Function1[A, Unit] {
var k0, k1, k2, k3: K = null.asInstanceOf[K]
var v0, v1, v2, v3 = (null : Builder[A, C])
var size = 0
var hashMap: mutable.HashMap[K, Builder[A, C]] = null
override def apply(): mutable.Builder[A, C] = {
size += 1
newSpecificBuilder
}
def apply(elem: A): Unit = {
val key = f(elem)
val bldr = builderFor(key)
bldr += elem
}
def builderFor(key: K): Builder[A, C] =
size match {
case 0 =>
k0 = key
v0 = apply()
v0
case 1 =>
if (k0 == key) v0
else {k1 = key; v1 = apply(); v1 }
case 2 =>
if (k0 == key) v0
else if (k1 == key) v1
else {k2 = key; v2 = apply(); v2 }
case 3 =>
if (k0 == key) v0
else if (k1 == key) v1
else if (k2 == key) v2
else {k3 = key; v3 = apply(); v3 }
case 4 =>
if (k0 == key) v0
else if (k1 == key) v1
else if (k2 == key) v2
else if (k3 == key) v3
else {
hashMap = new mutable.HashMap
hashMap(k0) = v0
hashMap(k1) = v1
hashMap(k2) = v2
hashMap(k3) = v3
val bldr = apply()
hashMap(key) = bldr
bldr
}
case _ =>
hashMap.getOrElseUpdate(key, apply())
}

def result(): immutable.Map[K, C] =
size match {
case 0 => immutable.Map.empty
case 1 => new immutable.Map.Map1(k0, v0.result())
case 2 => new immutable.Map.Map2(k0, v0.result(), k1, v1.result())
case 3 => new immutable.Map.Map3(k0, v0.result(), k1, v1.result(), k2, v2.result())
case 4 => new immutable.Map.Map4(k0, v0.result(), k1, v1.result(), k2, v2.result(), k3, v3.result())
case _ =>
val it = hashMap.entriesIterator
val m1 = immutable.HashMap.newBuilder[K, C]
while (it.hasNext) {
val entry = it.next()
m1.+=((entry.key, entry.value.result()))
}
m1.result()
}

}
result
this.foreach(grouper)
grouper.result()
}

/**
Expand Down
Loading