Skip to content

Commit 58b8aaa

Browse files
authored
Merge pull request #5843 from dotty-staging/derive-multiversal
Base multiversal equality on typeclass derivation
2 parents f04b2ea + 4bc1514 commit 58b8aaa

36 files changed

+450
-351
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -536,45 +536,6 @@ object desugar {
536536
if (isEnum)
537537
parents1 = parents1 :+ ref(defn.EnumType)
538538

539-
// The Eq instance for an Enum class. For an enum class
540-
//
541-
// enum class C[T1, ..., Tn]
542-
//
543-
// we generate:
544-
//
545-
// implicit def eqInstance[T1$1, ..., Tn$1, T1$2, ..., Tn$2](implicit
546-
// ev1: Eq[T1$1, T1$2], ..., evn: Eq[Tn$1, Tn$2]])
547-
// : Eq[C[T1$, ..., Tn$1], C[T1$2, ..., Tn$2]] = Eq
548-
//
549-
// Higher-kinded type arguments `Ti` are omitted as evidence parameters.
550-
//
551-
// FIXME: This is too simplistic. Instead of just generating evidence arguments
552-
// for every first-kinded type parameter, we should look instead at the
553-
// actual types occurring in cases and derive parameters from these. E.g. in
554-
//
555-
// enum HK[F[_]] {
556-
// case C1(x: F[Int]) extends HK[F[Int]]
557-
// case C2(y: F[String]) extends HL[F[Int]]
558-
//
559-
// we would need evidence parameters for `F[Int]` and `F[String]`
560-
// We should generate Eq instances with the techniques
561-
// of typeclass derivation once that is available.
562-
def eqInstance = {
563-
val leftParams = constrTparams.map(derivedTypeParam(_, "$1"))
564-
val rightParams = constrTparams.map(derivedTypeParam(_, "$2"))
565-
val subInstances =
566-
for ((param1, param2) <- leftParams `zip` rightParams if !isHK(param1))
567-
yield appliedRef(ref(defn.EqType), List(param1, param2), widenHK = true)
568-
DefDef(
569-
name = nme.eqInstance,
570-
tparams = leftParams ++ rightParams,
571-
vparamss = if (subInstances.isEmpty) Nil else List(makeImplicitParameters(subInstances)),
572-
tpt = appliedTypeTree(ref(defn.EqType),
573-
appliedRef(classTycon, leftParams) :: appliedRef(classTycon, rightParams) :: Nil),
574-
rhs = ref(defn.EqModule.termRef)).withFlags(Synthetic | Implicit)
575-
}
576-
def eqInstances = if (isEnum) eqInstance :: Nil else Nil
577-
578539
// derived type classes of non-module classes go to their companions
579540
val (clsDerived, companionDerived) =
580541
if (mods.is(Module)) (impl.derived, Nil) else (Nil, impl.derived)
@@ -593,7 +554,7 @@ object desugar {
593554
mdefs
594555
}
595556

596-
val companionMembers = defaultGetters ::: eqInstances ::: enumCases
557+
val companionMembers = defaultGetters ::: enumCases
597558

598559
// The companion object definitions, if a companion is needed, Nil otherwise.
599560
// companion definitions include:
@@ -643,7 +604,7 @@ object desugar {
643604
}
644605
companionDefs(companionParent, applyMeths ::: unapplyMeth :: companionMembers)
645606
}
646-
else if (companionMembers.nonEmpty || companionDerived.nonEmpty)
607+
else if (companionMembers.nonEmpty || companionDerived.nonEmpty || isEnum)
647608
companionDefs(anyRef, companionMembers)
648609
else if (isValueClass) {
649610
impl.constr.vparamss match {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,11 +734,11 @@ class Definitions {
734734
lazy val TastyReflectionModule: TermSymbol = ctx.requiredModule("scala.tasty.Reflection")
735735
lazy val TastyReflection_macroContext: TermSymbol = TastyReflectionModule.requiredMethod("macroContext")
736736

737-
lazy val EqType: TypeRef = ctx.requiredClassRef("scala.Eq")
738-
def EqClass(implicit ctx: Context): ClassSymbol = EqType.symbol.asClass
739-
def EqModule(implicit ctx: Context): Symbol = EqClass.companionModule
737+
lazy val EqlType: TypeRef = ctx.requiredClassRef("scala.Eql")
738+
def EqlClass(implicit ctx: Context): ClassSymbol = EqlType.symbol.asClass
739+
def EqlModule(implicit ctx: Context): Symbol = EqlClass.companionModule
740740

741-
def Eq_eqAny(implicit ctx: Context): TermSymbol = EqModule.requiredMethod(nme.eqAny)
741+
def Eql_eqlAny(implicit ctx: Context): TermSymbol = EqlModule.requiredMethod(nme.eqlAny)
742742

743743
lazy val NotType: TypeRef = ctx.requiredClassRef("scala.implicits.Not")
744744
def NotClass(implicit ctx: Context): ClassSymbol = NotType.symbol.asClass

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ import collection.mutable.ListBuffer
6767
*/
6868
object Denotations {
6969

70-
implicit def eqDenotation: Eq[Denotation, Denotation] = Eq
70+
implicit def eqDenotation: Eql[Denotation, Denotation] = Eql.derived
7171

7272
/** A PreDenotation represents a group of single denotations or a single multi-denotation
7373
* It is used as an optimization to avoid forming MultiDenotations too eagerly.

compiler/src/dotty/tools/dotc/core/Mode.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ object Mode {
5252
/** Allow GADTFlexType labelled types to have their bounds adjusted */
5353
val GADTflexible: Mode = newMode(8, "GADTflexible")
5454

55+
/** Assume -language:strictEquality */
56+
val StrictEquality: Mode = newMode(9, "StrictEquality")
57+
5558
/** We are currently printing something: avoid to produce more logs about
5659
* the printing
5760
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ object Names {
2525
def toTermName: TermName
2626
}
2727

28-
implicit def eqName: Eq[Name, Name] = Eq
28+
implicit def eqName: Eql[Name, Name] = Eql.derived
2929

3030
/** A common superclass of Name and Symbol. After bootstrap, this should be
3131
* just the type alias Name | Symbol

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ object StdNames {
418418
val equals_ : N = "equals"
419419
val error: N = "error"
420420
val eval: N = "eval"
421-
val eqAny: N = "eqAny"
421+
val eqlAny: N = "eqlAny"
422422
val ex: N = "ex"
423423
val experimental: N = "experimental"
424424
val f: N = "f"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ trait Symbols { this: Context =>
406406

407407
object Symbols {
408408

409-
implicit def eqSymbol: Eq[Symbol, Symbol] = Eq
409+
implicit def eqSymbol: Eql[Symbol, Symbol] = Eql.derived
410410

411411
/** Tree attachment containing the identifiers in a tree as a sorted array */
412412
val Ids: Property.Key[Array[String]] = new Property.Key

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ object Types {
4040

4141
@sharable private[this] var nextId = 0
4242

43-
implicit def eqType: Eq[Type, Type] = Eq
43+
implicit def eqType: Eql[Type, Type] = Eql.derived
4444

4545
/** Main class representing types.
4646
*

compiler/src/dotty/tools/dotc/typer/Deriving.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ trait Deriving { this: Typer =>
193193
if (nparams == 0) Nil
194194
else if (nparams == 1) tparam :: Nil
195195
else typeClass.typeParams.map(tcparam =>
196-
tparam.copy(name = s"${tparam.name}_${tcparam.name}".toTypeName)
196+
tparam.copy(name = s"${tparam.name}_$$_${tcparam.name}".toTypeName)
197197
.asInstanceOf[TypeSymbol])
198198
}
199199
val firstKindedParamss = clsParamss.filter {

0 commit comments

Comments
 (0)