Skip to content

Commit 37b6283

Browse files
committed
Merge EqClassOf and EqClass
Keep just one: EqClass, which is parameterized, like EqClassOf was. Unparameterized EqClass can be expressed as EqClass[_].
1 parent 940ac7a commit 37b6283

File tree

10 files changed

+59
-28
lines changed

10 files changed

+59
-28
lines changed

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,19 @@ class Definitions {
5656
private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") =
5757
newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)
5858

59-
// NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only
60-
// implemented in Dotty and not in Scala 2.
61-
// See <http://docs.scala-lang.org/sips/pending/repeated-byname.html>.
62-
private def specialPolyClass(name: TypeName, paramFlags: FlagSet, parentConstrs: => Seq[Type]): ClassSymbol = {
59+
/** A class following the template
60+
*
61+
* package scala
62+
* class <name>[<paramFlags> $T0] extends <parents>
63+
*
64+
* where <parents> = [constr' | constr <- parentConstrs]
65+
* <constr'> = constr[$T0] of <constr> has a type parameter
66+
* = constr otherwise
67+
*/
68+
private def specialPolyClass(name: TypeName, classFlags: FlagSet, paramFlags: FlagSet, parentConstrs: => Seq[Type]): ClassSymbol = {
69+
// NOTE: Ideally we would write `parentConstrs: => Type*` but SIP-24 is only
70+
// implemented in Dotty and not in Scala 2.
71+
// See <http://docs.scala-lang.org/sips/pending/repeated-byname.html>.
6372
val completer = new LazyType {
6473
def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
6574
val cls = denot.asClass.classSymbol
@@ -73,7 +82,7 @@ class Definitions {
7382
denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls)
7483
}
7584
}
76-
newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer)
85+
newClassSymbol(ScalaPackageClass, name, classFlags, completer)
7786
}
7887

7988
private def newMethod(cls: ClassSymbol, name: TermName, info: Type, flags: FlagSet = EmptyFlags): TermSymbol =
@@ -204,8 +213,8 @@ class Definitions {
204213
*
205214
* trait EqClass {
206215
* /** Comparison operations between values in the same equality class */
207-
* final def == [T >: this.type <: EqClass](other: T)(implicit ce: Eq[T]): Boolean = this.equals(other)
208-
* final def != [T >: this.type <: EqClass](other: T)(implicit ce: Eq[T]): Boolean = this.equals(other)
216+
* final def == [T >: this.type <: EqClass[_](other: T)(implicit ce: Eq[T]): Boolean = this.equals(other)
217+
* final def != [T >: this.type <: EqClass[_](other: T)(implicit ce: Eq[T]): Boolean = this.equals(other)
209218
* }
210219
*
211220
* The reason we define this here rather than as a source file is that these definitions
@@ -215,13 +224,12 @@ class Definitions {
215224
* Exception in thread "main" scala.reflect.internal.Types$NoCommonType: lub/glb of incompatible types: => core.this.Names.TypeName and scala.this.Nothing
216225
*/
217226
lazy val EqClassClass: ClassSymbol = {
218-
val ecc = newCompleteClassSymbol(
219-
ScalaPackageClass, tpnme.EqClass, PureInterfaceCreationFlags, List(AnyClass.typeRef))
227+
val ecc = specialPolyClass(tpnme.EqClass, PureInterfaceCreationFlags, Contravariant, List(AnyClass.typeRef))
220228
val completer = new LazyType {
221229
override def complete(denot: SymDenotation)(implicit ctx: Context): Unit = {
222230
denot.info =
223231
PolyType(tpnme.syntheticTypeParamNames(1))(
224-
pt => List(TypeBounds(ecc.thisType, ecc.typeRef)),
232+
pt => List(TypeBounds(ecc.thisType, ecc.typeRef.appliedTo(TypeBounds.empty))),
225233
pt => MethodType(List(PolyParam(pt, 0)),
226234
ImplicitMethodType(List(EqType.appliedTo(PolyParam(pt, 0))),
227235
BooleanType)))
@@ -393,10 +401,10 @@ class Definitions {
393401
lazy val BoxedDoubleModule = ctx.requiredModule("java.lang.Double")
394402
lazy val BoxedUnitModule = ctx.requiredModule("java.lang.Void")
395403

396-
lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, Seq(AnyType))
397-
lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, Seq(AnyType))
404+
lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, EmptyFlags, Covariant, Seq(AnyType))
405+
lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, EmptyFlags, Seq(AnyType))
398406

399-
lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, Seq(ObjectType, SeqType))
407+
lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, EmptyFlags, Covariant, Seq(ObjectType, SeqType))
400408

401409
// fundamental classes
402410
lazy val StringClass = ctx.requiredClass("java.lang.String")

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ object Denotations {
9797
*
9898
* @param symbol The referencing symbol, or NoSymbol is none exists
9999
*/
100-
abstract class Denotation(val symbol: Symbol) extends util.DotClass with printing.Showable with EqClassOf[Denotation] {
100+
abstract class Denotation(val symbol: Symbol) extends util.DotClass with printing.Showable with EqClass[Denotation] {
101101

102102
/** The type info of the denotation, exists only for non-overloaded denotations */
103103
def info(implicit ctx: Context): Type

src/dotty/tools/dotc/core/Names.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ object Names {
3535
* 3. Names are intended to be encoded strings. @see dotc.util.NameTransformer.
3636
* The encoding will be applied when converting a string to a name.
3737
*/
38-
abstract class Name extends DotClass with EqClassOf[Name]
38+
abstract class Name extends DotClass with EqClass[Name]
3939
with PreName
4040
with collection.immutable.Seq[Char]
4141
with IndexedSeqOptimized[Char, Name] {

src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ object Symbols {
365365
* @param coord The coordinates of the symbol (a position or an index)
366366
* @param id A unique identifier of the symbol (unique per ContextBase)
367367
*/
368-
class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with printing.Showable with EqClassOf[Symbol] {
368+
class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with printing.Showable with EqClass[Symbol] {
369369

370370
type ThisName <: Name
371371

src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ object Types {
7070
* +- ErrorType
7171
* +- WildcardType
7272
*/
73-
abstract class Type extends DotClass with Hashable with printing.Showable with EqClassOf[Type] {
73+
abstract class Type extends DotClass with Hashable with printing.Showable with EqClass[Type] {
7474

7575
// ----- Tests -----------------------------------------------------
7676

src/scala/Eq.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ object Eq extends Eq[Any] {
1212
/** An implicit that provides an `Eq` instance for all types `T` that have
1313
* a base type `U` such that `U <: EqClass[U]`.
1414
*/
15-
implicit def eqEq[U, T <: EqClassOf[U] with U]: Eq[T] = Eq
15+
implicit def eqEq[U, T <: EqClass[U] with U]: Eq[T] = Eq
1616
}
1717

src/scala/EqClass.scala

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@ package scala
22

33
/** A class providing a specialized notion of equality, allowing
44
* only values in the same equality class to be compared.
5+
* To be used in one of two ways:
6+
*
7+
* 1st way: When defining a class or trait `C`, simply write:
8+
*
9+
* class C extends ... EqClass[T]
10+
*
11+
* This makes `C` the root of a separate equality class. Any subtype
12+
* of `C` can then be compared with any other subtype of `C`, but it cannot
13+
* be compared with types that are not subtypes of `C`.
14+
*
15+
* 2nd way: Define `C` like this
16+
*
17+
* class C extends ... EqClass[_]
18+
*
19+
* or, equivalently:
20+
*
21+
* class C extends ... EqClass[Nothing]
22+
*
23+
* This creates a new equality class for `C`, but makes subtypes of `C` not automatically
24+
* comparable with other subtypes of `C`. Instead, the rules of what is comparable to what can
25+
* be encoded by giving `Eq` implicits in the companion object of `C`. Here is an example
26+
* that makes `Optional` values only be comparable if their element types are comparable:
27+
*
28+
* trait Optional[+T] extends EqClass[_]
29+
* case class Some[+T](x: T) extends Optional[T]
30+
* case object None extends Optional[T]
31+
*
32+
* object Optional {
33+
* def optEq[T](implicit ee: Eq[T]): Eq[Optional[T]] = Eq
34+
* }
535
*/
6-
trait EqClass extends Any
36+
trait EqClass[-T] extends Any
737

src/scala/EqClassOf.scala

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/neg/equality-posttyper.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ object equality {
33

44
case class Str(str: String) extends EqClass
55

6-
case class Num(x: Int) extends EqClassOf[Num]
6+
case class Num(x: Int) extends EqClass[Num]
77

88
case class Other(x: Int)
99

tests/neg/equality.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ object equality {
33

44
case class Str(str: String) extends EqClass
55

6-
case class Num(x: Int) extends EqClassOf[Num]
6+
case class Num(x: Int) extends EqClass[Num]
77

88
case class Other(x: Int)
99

0 commit comments

Comments
 (0)