Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ object desugar {
*/
val DerivingCompanion: Property.Key[SourcePosition] = Property.Key()

val DerivingName: Property.Key[TermName] = Property.Key()

/** An attachment for match expressions generated from a PatDef or GenFrom.
* Value of key == one of IrrefutablePatDef, IrrefutableGenFrom
*/
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import config.Feature.{sourceVersion, migrateTo3}
import config.SourceVersion.*
import config.SourceVersion
import dotty.tools.dotc.config.MigrationVersion
import dotty.tools.dotc.ast.desugar

object Parsers {

Expand Down Expand Up @@ -4453,7 +4454,13 @@ object Parsers {
val derived =
if (isIdent(nme.derives)) {
in.nextToken()
commaSeparated(() => convertToTypeId(qualId()))
commaSeparated { () =>
val qual = convertToTypeId(qualId())
if isIdent(nme.as) then
in.nextToken()
qual.putAttachment(desugar.DerivingName, ident())
qual
}
}
else Nil
possibleTemplateStart()
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ trait Deriving {
* an instance with the same name does not exist already.
* @param reportErrors Report an error if an instance with the same name exists already
*/
private def addDerivedInstance(clsName: Name, info: Type, pos: SrcPos): Unit = {
val instanceName = "derived$".concat(clsName)
private def addDerivedInstance(clsName: Name, info: Type, pos: SrcPos, name: Option[TermName]): Unit = {
val instanceName = name.getOrElse("derived$".concat(clsName))
if (ctx.denotNamed(instanceName).exists)
report.error(em"duplicate type class derivation for $clsName", pos)
else
Expand Down Expand Up @@ -100,7 +100,7 @@ trait Deriving {
val derivedInfo =
if derivedParams.isEmpty then monoInfo
else PolyType.fromParams(derivedParams, monoInfo)
addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.srcPos)
addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.srcPos, derived.removeAttachment(desugar.DerivingName))
}

def deriveSingleParameter: Unit = {
Expand Down
73 changes: 73 additions & 0 deletions tests/pos/as-in-derives/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import scala.deriving.*

import scala.compiletime.*

// =============== Typeclass definition
trait YesNoEnum[A] {
extension (self: A) def toBoolean: Boolean

def apply(bool: Boolean): A
}

object YesNoEnum {

inline def derived[A <: scala.reflect.Enum](using
A: Mirror.SumOf[A],
ev1: A.MirroredElemLabels <:< ("Yes", "No")
): YesNoEnum[A] =
new {
private val instances = summonInstances[A.MirroredElemTypes, A]
private val yes = instances(0)
private val no = instances(1)

extension (self: A) def toBoolean: Boolean = A.ordinal(self) == 0

def apply(bool: Boolean): A =
if bool then yes else no

}

private inline def summonInstances[A <: Tuple, Parent <: scala.reflect.Enum]: List[Parent] =
inline erasedValue[A] match {
case _: (h *: t) =>
inline valueOf[h] match {
case parent: Parent => parent :: summonInstances[t, Parent]
}

case _: EmptyTuple => Nil
}
}


// =============== usage (current) ===============

enum DecisionCurrent derives YesNoEnum {
case Yes, No
}

object DecisionCurrent {
export derived$YesNoEnum.{apply as fromBoolean}
}


// =============== usage (new) ===============

enum Decision derives YesNoEnum as fromBoolean {
case Yes, No
}

enum DecisionAlternate derives YesNoEnum as yesNoEnum {
case Yes, No
}

object DecisionAlternate {
export yesNoEnum.{apply as fromBoolean}
}

@main def test = {
Decision.fromBoolean(true) // Yes
Decision.fromBoolean(false) // No

DecisionAlternate.fromBoolean(true) // Yes
DecisionAlternate.fromBoolean(false) // No
}