Skip to content

Rework Reflect Constant #9914

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

Merged
merged 1 commit into from
Sep 30, 2020
Merged
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
89 changes: 82 additions & 7 deletions compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2061,16 +2061,91 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext:
type Constant = dotc.core.Constants.Constant

object Constant extends ConstantModule:
def apply(x: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String | Type): Constant =
dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String | Type] =
Some(constant.value.asInstanceOf[Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String | Type])
object ClassTag extends ClassTagModule:
def apply[T](using x: Type): Constant = dotc.core.Constants.Constant(x)

object Boolean extends ConstantBooleanModule:
def apply(x: Boolean): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Boolean] =
if constant.tag == dotc.core.Constants.BooleanTag then Some(constant.booleanValue)
else None
end Boolean

object Byte extends ConstantByteModule:
def apply(x: Byte): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Byte] =
if constant.tag == dotc.core.Constants.ByteTag then Some(constant.byteValue)
else None
end Byte

object Short extends ConstantShortModule:
def apply(x: Short): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Short] =
if constant.tag == dotc.core.Constants.ShortTag then Some(constant.shortValue)
else None
end Short

object Int extends ConstantIntModule:
def apply(x: Int): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Int] =
if constant.tag == dotc.core.Constants.IntTag then Some(constant.intValue)
else None
end Int

object Long extends ConstantLongModule:
def apply(x: Long): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Long] =
if constant.tag == dotc.core.Constants.LongTag then Some(constant.longValue)
else None
end Long

object Float extends ConstantFloatModule:
def apply(x: Float): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Float] =
if constant.tag == dotc.core.Constants.FloatTag then Some(constant.floatValue)
else None
end Float

object Double extends ConstantDoubleModule:
def apply(x: Double): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Double] =
if constant.tag == dotc.core.Constants.DoubleTag then Some(constant.doubleValue)
else None
end Double

object Char extends ConstantCharModule:
def apply(x: Char): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Char] =
if constant.tag == dotc.core.Constants.CharTag then Some(constant.charValue)
else None
end Char

object String extends ConstantStringModule:
def apply(x: String): Constant = dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[String] =
if constant.tag == dotc.core.Constants.StringTag then Some(constant.stringValue)
else None
end String

object Unit extends ConstantUnitModule:
def apply(): Constant = dotc.core.Constants.Constant(())
def unapply(constant: Constant): Boolean =
constant.tag == dotc.core.Constants.UnitTag
end Unit

object Null extends ConstantNullModule:
def apply(): Constant = dotc.core.Constants.Constant(null)
def unapply(constant: Constant): Boolean =
constant.tag == dotc.core.Constants.NullTag
end Null

object ClassOf extends ConstantClassOfModule:
def apply(x: Type): Constant =
// TODO check that the type is a valid class when creating this constant or let Ycheck do it?
dotc.core.Constants.Constant(x)
def unapply(constant: Constant): Option[Type] =
if constant.tag == dotc.core.Constants.ClazzTag then Some(constant.typeValue)
else None
end ClassTag
end ClassOf

end Constant

object ConstantMethodsImpl extends ConstantMethods:
Expand Down
4 changes: 2 additions & 2 deletions library/src-bootstrapped/scala/internal/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ object Expr {
/** Returns a null expresssion equivalent to `'{null}` */
def `null`: QuoteContext ?=> quoted.Expr[Null] = qctx ?=> {
import qctx.tasty._
Literal(Constant(null)).seal.asInstanceOf[quoted.Expr[Null]]
Literal(Constant.Null()).seal.asInstanceOf[quoted.Expr[Null]]
}

/** Returns a unit expresssion equivalent to `'{}` or `'{()}` */
def Unit: QuoteContext ?=> quoted.Expr[Unit] = qctx ?=> {
import qctx.tasty._
Literal(Constant(())).seal.asInstanceOf[quoted.Expr[Unit]]
Literal(Constant.Unit()).seal.asInstanceOf[quoted.Expr[Unit]]
}

}
58 changes: 43 additions & 15 deletions library/src-bootstrapped/scala/quoted/Liftable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,66 @@ object Liftable {
// IMPORTANT Keep in sync with tests/run-staging/liftables.scala

/** Default liftable for Boolean */
given BooleanLiftable[T <: Boolean] as Liftable[T] = new PrimitiveLiftable
given BooleanLiftable[T <: Boolean] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Boolean(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Byte */
given ByteLiftable[T <: Byte] as Liftable[T] = new PrimitiveLiftable
given ByteLiftable[T <: Byte] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Byte(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Short */
given ShortLiftable[T <: Short] as Liftable[T] = new PrimitiveLiftable
given ShortLiftable[T <: Short] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Short(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Int */
given IntLiftable[T <: Int] as Liftable[T] = new PrimitiveLiftable
given IntLiftable[T <: Int] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Int(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Long */
given LongLiftable[T <: Long] as Liftable[T] = new PrimitiveLiftable
given LongLiftable[T <: Long] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Long(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Float */
given FloatLiftable[T <: Float] as Liftable[T] = new PrimitiveLiftable
given FloatLiftable[T <: Float] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Float(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Double */
given DoubleLiftable[T <: Double] as Liftable[T] = new PrimitiveLiftable
given DoubleLiftable[T <: Double] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Double(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Char */
given CharLiftable[T <: Char] as Liftable[T] = new PrimitiveLiftable
given CharLiftable[T <: Char] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant.Char(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for String */
given StringLiftable[T <: String] as Liftable[T] = new PrimitiveLiftable

/** Lift a literal constant value */
private class PrimitiveLiftable[T <: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends Liftable[T] {
def toExpr(x: T) = qctx ?=> {
given StringLiftable[T <: String] as Liftable[T] {
def toExpr(x: T) =
import qctx.tasty._
Literal(Constant(x)).seal.asInstanceOf[Expr[T]]
}
Literal(Constant.String(x)).seal.asInstanceOf[Expr[T]]
}

/** Default liftable for Class[T] */
Expand Down
139 changes: 129 additions & 10 deletions library/src/scala/tasty/Reflection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2317,25 +2317,144 @@ trait Reflection { reflection =>
/** Constant value represented as the constant itself */
type Constant <: AnyRef

/** Module of Constant literals */
/** Constant value represented as the constant itself */
val Constant: ConstantModule

/** Constant value represented as the constant itself */
trait ConstantModule { this: Constant.type =>

def apply(x: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String | Type): Constant
/** Constant Boolean value */
val Boolean: ConstantBooleanModule

/** Constant Boolean value */
trait ConstantBooleanModule { this: Boolean.type =>
/** Create a constant Boolean value */
def apply(x: Boolean): Constant
/** Match Boolean value constant and extract its value */
def unapply(constant: Constant): Option[Boolean]
}

/** Constant Byte value */
val Byte: ConstantByteModule

/** Constant Byte value */
trait ConstantByteModule { this: Byte.type =>
/** Create a constant Byte value */
def apply(x: Byte): Constant
/** Match Byte value constant and extract its value */
def unapply(constant: Constant): Option[Byte]
}

/** Constant Short value */
val Short: ConstantShortModule

/** Constant Short value */
trait ConstantShortModule { this: Short.type =>
/** Create a constant Short value */
def apply(x: Short): Constant
/** Match Short value constant and extract its value */
def unapply(constant: Constant): Option[Short]
}

/** Constant Int value */
val Int: ConstantIntModule

/** Constant Int value */
trait ConstantIntModule { this: Int.type =>
/** Create a constant Int value */
def apply(x: Int): Constant
/** Match Int value constant and extract its value */
def unapply(constant: Constant): Option[Int]
}

/** Constant Long value */
val Long: ConstantLongModule

/** Constant Long value */
trait ConstantLongModule { this: Long.type =>
/** Create a constant Long value */
def apply(x: Long): Constant
/** Match Long value constant and extract its value */
def unapply(constant: Constant): Option[Long]
}

/** Constant Float value */
val Float: ConstantFloatModule

def unapply(constant: Constant): Option[Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String | Type]
/** Constant Float value */
trait ConstantFloatModule { this: Float.type =>
/** Create a constant Float value */
def apply(x: Float): Constant
/** Match Float value constant and extract its value */
def unapply(constant: Constant): Option[Float]
}

/** Constant Double value */
val Double: ConstantDoubleModule

/** Constant Double value */
trait ConstantDoubleModule { this: Double.type =>
/** Create a constant Double value */
def apply(x: Double): Constant
/** Match Double value constant and extract its value */
def unapply(constant: Constant): Option[Double]
}

/** Constant Char value */
val Char: ConstantCharModule

/** Module of ClassTag literals */
val ClassTag: ClassTagModule
/** Constant Char value */
trait ConstantCharModule { this: Char.type =>
/** Create a constant Char value */
def apply(x: Char): Constant
/** Match Char value constant and extract its value */
def unapply(constant: Constant): Option[Char]
}

/** Constant String value */
val String: ConstantStringModule

/** Constant String value */
trait ConstantStringModule { this: String.type =>
/** Create a constant String value */
def apply(x: String): Constant
/** Match String value constant and extract its value */
def unapply(constant: Constant): Option[String]
}

/** Module of ClassTag literals */
trait ClassTagModule { this: ClassTag.type =>
/** scala.reflect.ClassTag literal */
def apply[T](using x: Type): Constant
/** Extractor for ClassTag literals */
/** Constant Unit value */
val Unit: ConstantUnitModule

/** Constant Unit value */
trait ConstantUnitModule { this: Unit.type =>
/** Create a constant Unit value */
def apply(): Constant
/** Match Unit value constant */
def unapply(constant: Constant): Boolean
}

/** Constant null value */
val Null: ConstantNullModule

/** Constant null value */
trait ConstantNullModule { this: Null.type =>
/** Create a constant null value */
def apply(): Constant
/** Match null value constant */
def unapply(constant: Constant): Boolean
}

/** Constant class value representing a `classOf[T]` */
val ClassOf: ConstantClassOfModule

/** Constant class value representing a `classOf[T]` */
trait ConstantClassOfModule { this: ClassOf.type =>
/** Create a constant class value representing `classOf[<tpe>]` */
def apply(tpe: Type): Constant
/** Match a class value constant representing `classOf[<tpe>]` and extract its type */
def unapply(constant: Constant): Option[Type]
}

}

given ConstantMethods as ConstantMethods = ConstantMethodsImpl
Expand Down
26 changes: 13 additions & 13 deletions library/src/scala/tasty/reflect/ExtractorsPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,19 @@ class ExtractorsPrinter[R <: Reflection & Singleton](val tasty: R) extends Print
}

def visitConstant(x: Constant): Buffer = x match {
case Constant(()) => this += "Constant(())"
case Constant(null) => this += "Constant(null)"
case Constant(value: Boolean) => this += "Constant(" += value += ")"
case Constant(value: Byte) => this += "Constant(" += value += ": Byte)"
case Constant(value: Short) => this += "Constant(" += value += ": Short)"
case Constant(value: Char) => this += "Constant('" += value += "')"
case Constant(value: Int) => this += "Constant(" += value.toString += ")"
case Constant(value: Long) => this += "Constant(" += value += "L)"
case Constant(value: Float) => this += "Constant(" += value += "f)"
case Constant(value: Double) => this += "Constant(" += value += "d)"
case Constant(value: String) => this += "Constant(\"" += value += "\")"
case Constant.ClassTag(value) =>
this += "Constant.ClassTag("
case Constant.Unit() => this += "Constant.Unit()"
case Constant.Null() => this += "Constant.Null()"
case Constant.Boolean(value) => this += "Constant.Boolean(" += value += ")"
case Constant.Byte(value) => this += "Constant.Byte(" += value += ")"
case Constant.Short(value) => this += "Constant.Short(" += value += ")"
case Constant.Int(value) => this += "Constant.Int(" += value += ")"
case Constant.Long(value) => this += "Constant.Long(" += value += "L)"
case Constant.Float(value) => this += "Constant.Float(" += value += "f)"
case Constant.Double(value) => this += "Constant.Double(" += value += "d)"
case Constant.Char(value) => this += "Constant.Char('" += value += "')"
case Constant.String(value) => this += "Constant.String(\"" += value += "\")"
case Constant.ClassOf(value) =>
this += "Constant.ClassOf("
visitType(value) += ")"
}

Expand Down
Loading