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

SI-6623 -Yrepl-use-magic-imports avoids nesting $iw wrappers #79

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b6ba518
[nomerge] Avoid allocations of reusable CanBuildFroms
retronym Oct 31, 2019
f986e03
use existing ClassTag
mkeskells Oct 31, 2019
999239c
[nomerge] ConcatIterator.last advances
som-snytt Nov 23, 2019
4109888
[nomerge] Backport windows test fix
som-snytt Nov 28, 2019
e2ca633
Merge pull request #8560 from som-snytt/backport/t11802
SethTisue Nov 28, 2019
18bf349
review comments
mkeskells Nov 27, 2019
10b635e
two more tests for apparently-fixed issues
hrhino Dec 2, 2019
f0c3dbc
Merge pull request #8569 from hrhino/topic/more-tests
SethTisue Dec 2, 2019
de94b78
Merge pull request #8550 from som-snytt/issue/11807-2.12
lrytz Dec 2, 2019
b21589b
[backport] Import travis caching config and JDK install from scala-dev
lrytz Nov 29, 2019
fc6d511
Merge pull request #8572 from lrytz/travis-import-2.12
lrytz Dec 3, 2019
f9d9136
review comments
mkeskells Dec 5, 2019
de3451d
Merge pull request #8467 from rorygraves/mike/2.12_CanBuildFrom
szeiger Dec 5, 2019
36c6888
Bump Xmx for type-tag-leak
lrytz Nov 18, 2019
e474144
Merge pull request #8585 from retronym/topic/backport-type-tag-leak
retronym Dec 10, 2019
dca6f5a
Refactor Context creation
retronym Dec 3, 2019
317775b
SI-6623 -Yrepl-use-magic-imports avoids nesting $iw wrappers
retronym Dec 3, 2019
9e146e8
Enable magic imports unconditionally to survey test results
retronym Dec 5, 2019
7613d84
Run some completions tests under -Yrepl-classbased and fix completion…
retronym Dec 6, 2019
1659fec
Small improvements to REPL -Yrepl-class-based
retronym Dec 9, 2019
ff991f5
:javap in REPL deals better with nested modules
retronym Dec 10, 2019
f4cb764
Stabilize output in REPL tests between indy and inline lambdas
retronym Dec 10, 2019
cba5394
Enable -Yrepl-class-based to survey test failures
retronym Dec 9, 2019
50c74cd
Revert exploratory changes to default REPL wrappers
retronym Dec 10, 2019
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
28 changes: 5 additions & 23 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
dist: xenial
group: stable
language: scala
version: ~> 1.0 # needed for imports

before_install:
# adding $HOME/.sdkman to cache would create an empty directory, which interferes with the initial installation
- "[[ -d $HOME/.sdkman/bin/ ]] || rm -rf $HOME/.sdkman/"
- curl -sL https://get.sdkman.io | bash
- echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config
- echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config
- source "$HOME/.sdkman/bin/sdkman-init.sh"
import: scala/scala-dev:travis/default.yml

install:
- sdk install java $(sdk list java | grep -o "$ADOPTOPENJDK\.[0-9\.]*hs-adpt" | head -1) | true
- unset JAVA_HOME
- java -Xmx32m -version
- javac -J-Xmx32m -version
language: scala

stages:
- name: build
Expand Down Expand Up @@ -75,16 +63,10 @@ env:
- secure: "dbAvl6KEuLwZ0MVQPZihFsPzCdiLbX0EFk3so+hcfEbksrmLQ1tn4X5ZM7Wy1UDR8uN9lxngEwHch7a7lKqpugzmXMew9Wnikr9WBWbJT77Z+XJ/jHI6YuiCRpRo+nvxXGp9Ry80tSIgx5eju0J83IaJL41BWlBkvyAd7YAHORI=" # GPG_SUBKEY_SECRET
- secure: "ee0z/1jehBjFa2M2JlBHRjeo6OEn/zmVl72ukBP1ISeKqz18Cswc4gDI5tV9RW9SlYFLkIlGsR2qnRCyJ/pqgQLcNdrpsCRFFc79oyLhfEtmPdAHlWfj4RSP68zINRtDdFuJ8iSy8XYP0NaqpVIYpkNdv9I6q7N85ljmMQpHO+U=" # TRAVIS_TOKEN (login with GitHub as lrytz)

before_cache:
# Cleanup the cached directories to avoid unnecessary cache updates
- find $HOME/.ivy2/cache -name "ivydata-*.properties" -print -delete
- find $HOME/.sbt -name "*.lock" -print -delete
# caching for sdkman / sbt / ivy / coursier imported from scala-dev
cache:
directories:
- $HOME/.ivy2/cache
- $HOME/.sbt
- $HOME/.rvm/
- $HOME/.sdkman
- $HOME/.rvm

notifications:
webhooks: https://scala-ci.typesafe.com/benchq/webhooks/travis
1 change: 1 addition & 0 deletions src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ trait ScalaSettings extends AbsScalaSettings
val YmacroFresh = BooleanSetting ("-Ymacro-global-fresh-names", "Should fresh names in macros be unique across all compilation units")
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
val Yreplclassbased = BooleanSetting ("-Yrepl-class-based", "Use classes to wrap REPL snippets instead of objects")
val YreplMagicImport = BooleanSetting ("-Yrepl-use-magic-imports", "In the code the wraps REPL snippes, use magic imports to rather than nesting wrapper object/classes")
val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "")
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overridden methods.")
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
Expand Down
47 changes: 30 additions & 17 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@ trait Contexts { self: Analyzer =>
object NoContext
extends Context(EmptyTree, NoSymbol, EmptyScope, NoCompilationUnit,
// We can't pass the uninitialized `this`. Instead, we treat null specially in `Context#outer`
null) {
null, 0) {
enclClass = this
enclMethod = this

override val depth = 0
override def nextEnclosing(p: Context => Boolean): Context = this
override def enclosingContextChain: List[Context] = Nil
override def implicitss: List[List[ImplicitInfo]] = Nil
Expand Down Expand Up @@ -191,7 +190,7 @@ trait Contexts { self: Analyzer =>
* @param _outer The next outer context.
*/
class Context private[typechecker](val tree: Tree, val owner: Symbol, val scope: Scope,
val unit: CompilationUnit, _outer: Context,
val unit: CompilationUnit, _outer: Context, val depth: Int,
private[this] var _reporter: ContextReporter = new ThrowingReporter) {
private def outerIsNoContext = _outer eq null
final def outer: Context = if (outerIsNoContext) NoContext else _outer
Expand Down Expand Up @@ -237,16 +236,12 @@ trait Contexts { self: Analyzer =>

protected def outerDepth = if (outerIsNoContext) 0 else outer.depth

val depth: Int = {
val increasesDepth = isRootImport || outerIsNoContext || (outer.scope != scope)
( if (increasesDepth) 1 else 0 ) + outerDepth
}

/** The currently visible imports */
/** The currently visible imports, from innermost to outermost. */
def imports: List[ImportInfo] = outer.imports
/** Equivalent to `imports.headOption`, but more efficient */
def firstImport: Option[ImportInfo] = outer.firstImport
protected[Contexts] def importOrNull: ImportInfo = null
/** A root import is never unused and always bumps context depth. (e.g scala._ / Predef._ and magic REPL imports) */
def isRootImport: Boolean = false

/** Types for which implicit arguments are currently searched */
Expand Down Expand Up @@ -488,11 +483,17 @@ trait Contexts { self: Analyzer =>
else if (!sameOwner && owner.isTerm) NoPrefix
else prefix

def innerDepth(isRootImport: Boolean) = {
val increasesDepth = isRootImport || (this == NoContext) || (this.scope != scope)
depth + (if (increasesDepth) 1 else 0)
}

// The blank canvas
val c = if (isImport)
new Context(tree, owner, scope, unit, this, reporter) with ImportContext
else
new Context(tree, owner, scope, unit, this, reporter)
val c = if (isImport) {
val isRootImport = !tree.pos.isDefined || isReplImportWrapperImport(tree)
new ImportContext(tree, owner, scope, unit, this, isRootImport, innerDepth(isRootImport), reporter)
} else
new Context(tree, owner, scope, unit, this, innerDepth(isRootImport = false), reporter)

// Fields that are directly propagated
c.variance = variance
Expand Down Expand Up @@ -1100,6 +1101,16 @@ trait Contexts { self: Analyzer =>
}
}


private def isReplImportWrapperImport(tree: Tree): Boolean = {
tree match {
case Import(expr, selector :: Nil) =>
// Just a syntactic check to avoid forcing typechecking of imports
selector.name.string_==(nme.INTERPRETER_IMPORT_LEVEL_UP) && owner.enclosingTopLevelClass.isInterpreterWrapper
case _ => false
}
}

} //class Context

/** Find the symbol of a simple name starting from this context.
Expand Down Expand Up @@ -1307,8 +1318,11 @@ trait Contexts { self: Analyzer =>
}

/** A `Context` focussed on an `Import` tree */
trait ImportContext extends Context {
private val impInfo: ImportInfo = {
final class ImportContext(tree: Tree, owner: Symbol, scope: Scope,
unit: CompilationUnit, outer: Context,
override val isRootImport: Boolean, depth: Int,
reporter: ContextReporter) extends Context(tree, owner, scope, unit, outer, depth, reporter) {
private[this] val impInfo: ImportInfo = {
val info = new ImportInfo(tree.asInstanceOf[Import], outerDepth)
if (settings.warnUnusedImport && openMacros.isEmpty && !isRootImport) // excludes java.lang/scala/Predef imports
allImportInfos(unit) ::= info
Expand All @@ -1317,7 +1331,7 @@ trait Contexts { self: Analyzer =>
override final def imports = impInfo :: super.imports
override final def firstImport = Some(impInfo)
override final def importOrNull = impInfo
override final def isRootImport = !tree.pos.isDefined

override final def toString = s"${super.toString} with ImportContext { $impInfo; outer.owner = ${outer.owner} }"
}

Expand Down Expand Up @@ -1467,7 +1481,6 @@ trait Contexts { self: Analyzer =>
protected def handleError(pos: Position, msg: String): Unit = reporter.error(pos, msg)
}


private[typechecker] class BufferingReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
override def isBuffering = true

Expand Down
7 changes: 4 additions & 3 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,10 @@ trait Namers extends MethodSynthesis {
val Import(expr, selectors) = tree
val base = expr.tpe

def checkNotRedundant(pos: Position, from: Name, to0: Name) {
def check(to: Name) = {
// warn proactively if specific import loses to definition in scope,
// since it may result in desired implicit not imported into scope.
def checkNotRedundant(pos: Position, from: Name, to0: Name): Unit = {
def check(to: Name): Unit = {
val e = context.scope.lookupEntry(to)

if (e != null && e.owner == context.scope && e.sym.exists)
Expand Down Expand Up @@ -1820,7 +1822,6 @@ trait Namers extends MethodSynthesis {
}
}


/** Given a case class
* case class C[Ts] (ps: Us)
* Add the following methods to toScope:
Expand Down
74 changes: 71 additions & 3 deletions src/library/scala/Array.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,78 @@ object Array extends FallbackArrayBuilding {
val emptyShortArray = new Array[Short](0)
val emptyObjectArray = new Array[Object](0)

implicit def canBuildFrom[T](implicit t: ClassTag[T]): CanBuildFrom[Array[_], T, Array[T]] =
implicit def canBuildFrom[T](implicit tag: ClassTag[T]): CanBuildFrom[Array[_], T, Array[T]] = {
val cls = tag.runtimeClass
(if (cls.isPrimitive) {
cls match {
case java.lang.Integer.TYPE => cbfIntArray
case java.lang.Double.TYPE => cbfDoubleArray
case java.lang.Long.TYPE => cbfLongArray
case java.lang.Float.TYPE => cbfFloatArray
case java.lang.Character.TYPE => cbfCharArray
case java.lang.Byte.TYPE => cbfByteArray
case java.lang.Short.TYPE => cbfShortArray
case java.lang.Boolean.TYPE => cbfBooleanArray
case java.lang.Void.TYPE => cbfUnitArray
}
} else if (cls == ObjectClass) {
cbfObjectArray
} else {
refCBF[T with AnyRef](tag.asInstanceOf[ClassTag[T with AnyRef]])
}).asInstanceOf[CanBuildFrom[Array[_], T, Array[T]]]
}
private[this] val ObjectClass = classOf[Object]

private[this] val cbfBooleanArray = new CanBuildFrom[Array[_], Boolean, Array[Boolean]] {
def apply(from: Array[_]) = new ArrayBuilder.ofBoolean()
def apply() = new ArrayBuilder.ofBoolean()
}

private[this] val cbfByteArray = new CanBuildFrom[Array[_], Byte, Array[Byte]] {
def apply(from: Array[_]) = new ArrayBuilder.ofByte()
def apply() = new ArrayBuilder.ofByte()
}

private[this] val cbfCharArray = new CanBuildFrom[Array[_], Char, Array[Char]] {
def apply(from: Array[_]) = new ArrayBuilder.ofChar()
def apply() = new ArrayBuilder.ofChar()
}

private[this] val cbfDoubleArray = new CanBuildFrom[Array[_], Double, Array[Double]] {
def apply(from: Array[_]) = new ArrayBuilder.ofDouble()
def apply() = new ArrayBuilder.ofDouble()
}

private[this] val cbfFloatArray = new CanBuildFrom[Array[_], Float, Array[Float]] {
def apply(from: Array[_]) = new ArrayBuilder.ofFloat()
def apply() = new ArrayBuilder.ofFloat()
}

private[this] val cbfIntArray = new CanBuildFrom[Array[_], Int, Array[Int]] {
def apply(from: Array[_]) = new ArrayBuilder.ofInt()
def apply() = new ArrayBuilder.ofInt()
}

private[this] val cbfLongArray = new CanBuildFrom[Array[_], Long, Array[Long]] {
def apply(from: Array[_]) = new ArrayBuilder.ofLong()
def apply() = new ArrayBuilder.ofLong()
}

private[this] val cbfShortArray = new CanBuildFrom[Array[_], Short, Array[Short]] {
def apply(from: Array[_]) = new ArrayBuilder.ofShort()
def apply() = new ArrayBuilder.ofShort()
}

private[this] val cbfUnitArray = new CanBuildFrom[Array[_], Unit, Array[Unit]] {
def apply(from: Array[_]) = new ArrayBuilder.ofUnit()
def apply() = new ArrayBuilder.ofUnit()
}

private[this] val cbfObjectArray = refCBF[Object]
private[this] def refCBF[T <: AnyRef](implicit t: ClassTag[T]): CanBuildFrom[Array[_], T, Array[T]] =
new CanBuildFrom[Array[_], T, Array[T]] {
def apply(from: Array[_]) = ArrayBuilder.make[T]()(t)
def apply() = ArrayBuilder.make[T]()(t)
def apply(from: Array[_]) = new ArrayBuilder.ofRef[T]()(t)
def apply() = new ArrayBuilder.ofRef[T]()(t)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ object BitSet extends BitSetFactory[BitSet] {
def newBuilder = immutable.BitSet.newBuilder

/** $canBuildFromInfo */
implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
implicit val canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
}

5 changes: 4 additions & 1 deletion src/library/scala/collection/GenMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@ object GenMap extends GenMapFactory[GenMap] {
def empty[K, V]: immutable.Map[K, V] = immutable.Map.empty

/** $mapCanBuildFromInfo */
implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), GenMap[K, V]] = new MapCanBuildFrom[K, V]
implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), GenMap[K, V]] =
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, (K, V), GenMap[K, V]]]
private[this] val ReusableCBF = new MapCanBuildFrom[Nothing, Nothing]

}
2 changes: 2 additions & 0 deletions src/library/scala/collection/Iterator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ object Iterator {
}
else {
current = tail.headIterator
if (last eq tail) last = last.tail
tail = tail.tail
merge()
if (currentHasNextChecked) true
Expand All @@ -210,6 +211,7 @@ object Iterator {
current = c.current
currentHasNextChecked = c.currentHasNextChecked
if (c.tail ne null) {
if (last eq null) last = c.last
c.last.tail = tail
tail = c.tail
}
Expand Down
4 changes: 3 additions & 1 deletion src/library/scala/collection/Map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ object Map extends MapFactory[Map] {
def empty[K, V]: immutable.Map[K, V] = immutable.Map.empty

/** $mapCanBuildFromInfo */
implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[K, V]
implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] =
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, (K, V), Map[K, V]]]
private[this] val ReusableCBF = new MapCanBuildFrom[Nothing, Nothing]

/** An abstract shell used by { mutable, immutable }.Map but not by collection.Map
* because of variance issues.
Expand Down
4 changes: 3 additions & 1 deletion src/library/scala/collection/Set.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ trait Set[A] extends (A => Boolean)
object Set extends SetFactory[Set] {
def newBuilder[A] = immutable.Set.newBuilder[A]
override def empty[A]: Set[A] = immutable.Set.empty[A]
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A]
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] =
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, A, Set[A]]]
private[this] val ReusableCBF = setCanBuildFrom[Any]
}

/** Explicit instantiation of the `Set` trait to reduce class file size in subclasses. */
Expand Down
4 changes: 3 additions & 1 deletion src/library/scala/collection/concurrent/TrieMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,9 @@ extends scala.collection.concurrent.Map[K, V]
object TrieMap extends MutableMapFactory[TrieMap] {
val inodeupdater = AtomicReferenceFieldUpdater.newUpdater(classOf[INodeBase[_, _]], classOf[MainNode[_, _]], "mainnode")

implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), TrieMap[K, V]] = new MapCanBuildFrom[K, V]
implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), TrieMap[K, V]] =
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, (K, V), TrieMap[K, V]]]
private[this] val ReusableCBF = new MapCanBuildFrom[Nothing, Nothing]

def empty[K, V]: TrieMap[K, V] = new TrieMap[K, V]

Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/immutable/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ object BitSet extends BitSetFactory[BitSet] {
}

/** $bitsetCanBuildFrom */
implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom
implicit val canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom

/** A bitset containing all the bits in an array */
def fromBitMask(elems: Array[Long]): BitSet = {
Expand Down
4 changes: 3 additions & 1 deletion src/library/scala/collection/immutable/HashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ sealed class HashSet[A] extends AbstractSet[A]
object HashSet extends ImmutableSetFactory[HashSet] {

/** $setCanBuildFromInfo */
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A]
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] =
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, A, HashSet[A]]]
private[this] val ReusableCBF = setCanBuildFrom[Any]

private object EmptyHashSet extends HashSet[Any] {
override def head: Any = throw new NoSuchElementException("Empty Set")
Expand Down
12 changes: 7 additions & 5 deletions src/library/scala/collection/immutable/IntMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ package scala
package collection
package immutable

import scala.collection.generic.{ CanBuildFrom, BitOperations }
import scala.collection.mutable.{ Builder, MapBuilder }
import scala.collection.generic.{BitOperations, CanBuildFrom}
import scala.collection.mutable.{Builder, MapBuilder}
import scala.annotation.tailrec

/** Utility class for integer maps.
Expand Down Expand Up @@ -50,9 +50,11 @@ import IntMapUtils._
*/
object IntMap {
/** $mapCanBuildFromInfo */
implicit def canBuildFrom[A, B] = new CanBuildFrom[IntMap[A], (Int, B), IntMap[B]] {
def apply(from: IntMap[A]): Builder[(Int, B), IntMap[B]] = apply()
def apply(): Builder[(Int, B), IntMap[B]] = new MapBuilder[Int, B, IntMap[B]](empty[B])
implicit def canBuildFrom[A, B]: CanBuildFrom[IntMap[A], (Int, B), IntMap[B]] =
ReusableCBF.asInstanceOf[CanBuildFrom[IntMap[A], (Int, B), IntMap[B]]]
private val ReusableCBF = new CanBuildFrom[IntMap[Any], (Int, Any), IntMap[Any]] {
def apply(from: IntMap[Any]): Builder[(Int, Any), IntMap[Any]] = apply()
def apply(): Builder[(Int, Any), IntMap[Any]] = new MapBuilder[Int, Any, IntMap[Any]](empty[Any])
}

def empty[T] : IntMap[T] = IntMap.Nil
Expand Down
3 changes: 2 additions & 1 deletion src/library/scala/collection/immutable/ListMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ object ListMap extends ImmutableMapFactory[ListMap] {
* $mapCanBuildFromInfo
*/
implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), ListMap[A, B]] =
new MapCanBuildFrom[A, B]
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, (A, B), ListMap[A, B]]]
private[this] val ReusableCBF = new MapCanBuildFrom[Any, Any]

def empty[A, B]: ListMap[A, B] = EmptyListMap.asInstanceOf[ListMap[A, B]]

Expand Down
3 changes: 2 additions & 1 deletion src/library/scala/collection/immutable/ListSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ object ListSet extends ImmutableSetFactory[ListSet] {
* $setCanBuildFromInfo
*/
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] =
setCanBuildFrom[A]
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, A, ListSet[A]]]
private[this] val ReusableCBF = setCanBuildFrom[Any]

@SerialVersionUID(5010379588739277132L)
private object EmptyListSet extends ListSet[Any]
Expand Down
Loading