Uploaded image for project: 'Scala Programming Language'
  1. Scala Programming Language
  2. SI-10202

Wrong linearization for specialized methods

    Details

      Description

      A specialized trait mixes in two other specialized traits overriding the same specialized method in a common ancestor - here `newBuilder`. When instantiated for a specialized type the method is incorrectly forwarded to the first mixed trait (second in linearization order).
      The same method called on a non-specialized instance correctly calls the method declared
      closer to the top of initialization stack.

      import scala.collection.generic.{GenericCompanion, GenericSetTemplate, GenericTraversableTemplate}
      import scala.collection.{SetLike, mutable}
       
      trait FitBuilder[@specialized E, +That] extends mutable.Builder[E, That]
       
      object FitBuilder {
      	def apply[@specialized E, That](builder :mutable.Builder[E, That]) = new FitBuilder[E, That] {
      		override def +=(elem: E): this.type = { builder += elem; this }
      		override def clear(): Unit = builder.clear()
      		override def result(): That = builder.result()
      	}
       
      	def better[@specialized E, That](builder :mutable.Builder[E, That]) = apply(builder)
      }
       
      trait SpecializableIterable[@specialized +E, +S[@specialized X] <: Iterable[X] with SpecializableIterable[X, S]]
      	extends GenericTraversableTemplate[E, S]
      {
      	override protected[this] def newBuilder: FitBuilder[E, S[E]] = FitBuilder(companion.newBuilder[E])
      }
       
       
       
      trait SetSpecialization[@specialized E, +This <: SetSpecialization[E, This] with FitSet[E]]
      	extends SetLike[E, This]
      {
      	override def newBuilder :FitBuilder[E, This] = FitBuilder.better(new mutable.SetBuilder(empty))
      }
       
      trait FitSet[@specialized E]
      	extends collection.Set[E] with SpecializableIterable[E, FitSet] with SetSpecialization[E, FitSet[E]] //SpecializableSet[E, FitSet]
      {
      	override def empty = companion.empty
      	override def companion = FitSet
      }
       
      object FitSet extends GenericCompanion[FitSet] {
      	override def newBuilder[A]: mutable.Builder[A, FitSet[A]] = Set.newBuilder[A].mapResult(xs => new PlaySet(xs))
      }
       
       
      class PlaySet[@specialized X](var xs :Set[X]) extends FitSet[X] {
      	def this() = this(Set())
      	override def contains(elem: X): Boolean = xs.contains(elem)
       
      	override def +(elem: X) = new PlaySet(xs + elem)
       
      	override def -(elem: X) = new PlaySet(xs - elem)
       
      	override def iterator: Iterator[X] = xs.iterator
      }
       
      class SadSet[X](var xs :Set[X]) extends FitSet[X] {
      	def this() = this(Set())
      	override def contains(elem: X): Boolean = xs.contains(elem)
       
      	override def +(elem: X) = new PlaySet(xs + elem)
       
      	override def -(elem: X) = new PlaySet(xs - elem)
       
      	override def iterator: Iterator[X] = xs.iterator
      }
       
       
      object Playground extends App {
      	val ints = new PlaySet[Int]
      	ints.newBuilder //calls SpecializableIterable.newBuilder !
      	val refs = new PlaySet[AnyRef]
      	refs.newBuilder //calls correctly SetSpecialization.newBuilder
      	val sad = new SadSet[Int]
      	sad.newBuilder //calls correctly SetSpecialization.newBuilder
      }
      

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              mmoscicki Marcin Mościcki
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated: