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

Wrong linearization for specialized methods #10202

Open
scabug opened this issue Feb 22, 2017 · 1 comment
Open

Wrong linearization for specialized methods #10202

scabug opened this issue Feb 22, 2017 · 1 comment

Comments

@scabug
Copy link

scabug commented Feb 22, 2017

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
}
@scabug
Copy link
Author

scabug commented Feb 22, 2017

Imported From: https://issues.scala-lang.org/browse/SI-10202?orig=1
Reporter: Marcin Mościcki (mmoscicki)
Affected Versions: 2.11.8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants