Skip to content

Commit eb5360b

Browse files
committed
Split TASTy reflect interface and implementation
Mostly to simplify the maintainability and documentation of distinct parts of the implementation. Abstract types are defined separately in TastyCore to avoid cake pattern (except for Printers). Extracted the `show` extension methods to avoid cakes.
1 parent dbc8d80 commit eb5360b

35 files changed

+2300
-2045
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.ast.tpd
4+
5+
trait CaseDefOpsImpl extends scala.tasty.reflect.CaseDefOps with TastyCoreImpl with Helpers {
6+
7+
def CaseDefDeco(caseDef: CaseDef): CaseDefAPI = new CaseDefAPI {
8+
def pattern(implicit ctx: Context): Pattern = caseDef.pat
9+
def guard(implicit ctx: Context): Option[Term] = optional(caseDef.guard)
10+
def rhs(implicit ctx: Context): Term = caseDef.body
11+
}
12+
13+
object CaseDef extends CaseDefExtractor {
14+
def unapply(x: CaseDef): Option[(Pattern, Option[Term], Term)] = x match {
15+
case x: tpd.CaseDef =>
16+
Some(x.pat, optional(x.guard), x.body)
17+
case _ => None
18+
}
19+
}
20+
21+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.core.Constants
4+
5+
import scala.tasty.util.Show
6+
7+
trait ConstantOpsImpl extends scala.tasty.reflect.ConstantOps with TastyCoreImpl {
8+
9+
def ConstantDeco(const: Constant): ConstantAPI = new ConstantAPI {
10+
def value: Any = const.value
11+
}
12+
13+
object Constant extends ConstantModule {
14+
15+
object Unit extends UnitExtractor {
16+
def unapply(x: Constant): Boolean = x match {
17+
case x: Constants.Constant => x.tag == Constants.UnitTag
18+
case _ => false
19+
}
20+
}
21+
22+
object Null extends NullExtractor {
23+
def unapply(x: Constant): Boolean = x match {
24+
case x: Constants.Constant => x.tag == Constants.NullTag
25+
case _ => false
26+
}
27+
}
28+
29+
object Boolean extends BooleanExtractor {
30+
def unapply(x: Constant): Option[Boolean] = x match {
31+
case x: Constants.Constant if x.tag == Constants.BooleanTag => Some(x.booleanValue)
32+
case _ => None
33+
}
34+
}
35+
36+
object Byte extends ByteExtractor {
37+
def unapply(x: Constant): Option[Byte] = x match {
38+
case x: Constants.Constant if x.tag == Constants.ByteTag => Some(x.byteValue)
39+
case _ => None
40+
}
41+
}
42+
43+
object Short extends ShortExtractor {
44+
def unapply(x: Constant): Option[Short] = x match {
45+
case x: Constants.Constant if x.tag == Constants.ShortTag => Some(x.shortValue)
46+
case _ => None
47+
}
48+
}
49+
50+
object Char extends CharExtractor {
51+
def unapply(x: Constant): Option[Char] = x match {
52+
case x: Constants.Constant if x.tag == Constants.CharTag => Some(x.charValue)
53+
case _ => None
54+
}
55+
}
56+
57+
object Int extends IntExtractor {
58+
def unapply(x: Constant): Option[Int] = x match {
59+
case x: Constants.Constant if x.tag == Constants.IntTag => Some(x.intValue)
60+
case _ => None
61+
}
62+
}
63+
64+
object Long extends LongExtractor {
65+
def unapply(x: Constant): Option[Long] = x match {
66+
case x: Constants.Constant if x.tag == Constants.LongTag => Some(x.longValue)
67+
case _ => None
68+
}
69+
}
70+
71+
object Float extends FloatExtractor {
72+
def unapply(x: Constant): Option[Float] = x match {
73+
case x: Constants.Constant if x.tag == Constants.FloatTag => Some(x.floatValue)
74+
case _ => None
75+
}
76+
}
77+
78+
object Double extends DoubleExtractor {
79+
def unapply(x: Constant): Option[Double] = x match {
80+
case x: Constants.Constant if x.tag == Constants.DoubleTag => Some(x.doubleValue)
81+
case _ => None
82+
}
83+
}
84+
85+
object String extends StringExtractor {
86+
def unapply(x: Constant): Option[String] = x match {
87+
case x: Constants.Constant if x.tag == Constants.StringTag => Some(x.stringValue)
88+
case _ => None
89+
}
90+
}
91+
92+
object ClassTag extends ClassTagExtractor {
93+
def unapply(x: Constant): Option[Type] = x match {
94+
case x: Constants.Constant if x.tag == Constants.ClazzTag => Some(x.typeValue)
95+
case _ => None
96+
}
97+
}
98+
99+
object Symbol extends SymbolExtractor {
100+
def unapply(x: Constant): Option[scala.Symbol] = x match {
101+
case x: Constants.Constant if x.tag == Constants.ScalaSymbolTag => Some(x.scalaSymbolValue)
102+
case _ => None
103+
}
104+
}
105+
}
106+
107+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.core.Contexts
4+
import dotty.tools.dotc.tastyreflect.FromSymbol.definitionFromSym
5+
import dotty.tools.dotc.util.{Positions, SourcePosition}
6+
7+
trait ContextOpsImpl extends scala.tasty.reflect.ContextOps with TastyCoreImpl {
8+
9+
val rootContext: Contexts.Context
10+
11+
def ContextDeco(ctx: Context): ContextAPI = new ContextAPI {
12+
def owner: Definition = definitionFromSym(ctx.owner)(ctx)
13+
14+
def source: java.nio.file.Path = ctx.compilationUnit.source.file.jpath
15+
}
16+
17+
def rootPosition: SourcePosition = SourcePosition(rootContext.source, Positions.NoPosition)
18+
19+
}

compiler/src/dotty/tools/dotc/tastyreflect/FlagSet.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotty.tools.dotc.tastyreflect
33
import dotty.tools.dotc.core.Flags
44
import dotty.tools.dotc.core.Flags._
55

6-
class FlagSet(flags: Flags.FlagSet) extends scala.tasty.FlagSet {
6+
class FlagSet(flags: Flags.FlagSet) extends scala.tasty.reflect.FlagSet {
77

88
def isProtected: Boolean = flags.is(Protected)
99
def isAbstract: Boolean = flags.is(Abstract)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.ast.Trees
4+
5+
trait Helpers {
6+
7+
protected final def optional[T <: Trees.Tree[_]](tree: T): Option[tree.type] =
8+
if (tree.isEmpty) None else Some(tree)
9+
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.core.Decorators._
4+
5+
trait IdOpsImpl extends scala.tasty.reflect.IdOps with TastyCoreImpl {
6+
7+
def IdDeco(id: Id): IdAPI = new IdAPI {
8+
def pos(implicit ctx: Context): Position = id.pos
9+
def name(implicit ctx: Context): String = id.name.toString
10+
}
11+
12+
object Id extends IdExtractor {
13+
def unapply(id: Id): Option[String] = Some(id.name.toString)
14+
}
15+
16+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.ast.{Trees, untpd}
4+
import dotty.tools.dotc.core.StdNames.nme
5+
6+
trait ImportSelectorOpsImpl extends scala.tasty.reflect.ImportSelectorOps with TastyCoreImpl {
7+
8+
object SimpleSelector extends SimpleSelectorExtractor {
9+
def unapply(x: ImportSelector)(implicit ctx: Context): Option[Id] = x match {
10+
case x: untpd.Ident => Some(x)
11+
case _ => None
12+
}
13+
}
14+
15+
object RenameSelector extends RenameSelectorExtractor {
16+
def unapply(x: ImportSelector)(implicit ctx: Context): Option[(Id, Id)] = x match {
17+
case Trees.Thicket((id1: untpd.Ident) :: (id2: untpd.Ident) :: Nil) if id2.name != nme.WILDCARD => Some(id1, id2)
18+
case _ => None
19+
}
20+
}
21+
22+
object OmitSelector extends OmitSelectorExtractor {
23+
def unapply(x: ImportSelector)(implicit ctx: Context): Option[Id] = x match {
24+
case Trees.Thicket((id: untpd.Ident) :: Trees.Ident(nme.WILDCARD) :: Nil) => Some(id)
25+
case _ => None
26+
}
27+
}
28+
29+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.ast.{Trees, tpd}
4+
import dotty.tools.dotc.core.Decorators._
5+
import dotty.tools.dotc.core.Types
6+
7+
import scala.tasty.util.Show
8+
9+
trait PatternOpsImpl extends scala.tasty.reflect.PatternOps with TastyCoreImpl {
10+
11+
// ----- Patterns -------------------------------------------------
12+
13+
def PatternDeco(pattern: Pattern): PatternAPI = new PatternAPI {
14+
def pos(implicit ctx: Context): Position = pattern.pos
15+
def tpe(implicit ctx: Context): Types.Type = pattern.tpe.stripTypeVar
16+
}
17+
18+
object Pattern extends PatternModule {
19+
20+
object Value extends ValueExtractor {
21+
def unapply(x: Pattern)(implicit ctx: Context): Option[Term] = x match {
22+
case lit: tpd.Literal => Some(lit)
23+
case ref: tpd.RefTree if ref.isTerm => Some(ref)
24+
case ths: tpd.This => Some(ths)
25+
case _ => None
26+
}
27+
}
28+
29+
object Bind extends BindExtractor {
30+
def unapply(x: Pattern)(implicit ctx: Context): Option[(String, Pattern)] = x match {
31+
case x: tpd.Bind if x.name.isTermName => Some(x.name.toString, x.body)
32+
case _ => None
33+
}
34+
}
35+
36+
object Unapply extends UnapplyExtractor {
37+
def unapply(x: Pattern)(implicit ctx: Context): Option[(Term, List[Term], List[Pattern])] = x match {
38+
case Trees.UnApply(fun, implicits, patterns) => Some((fun, implicits, effectivePatterns(patterns)))
39+
case Trees.Typed(Trees.UnApply(fun, implicits, patterns), _) => Some((fun, implicits, effectivePatterns(patterns)))
40+
case _ => None
41+
}
42+
private def effectivePatterns(patterns: List[Pattern]): List[Pattern] = patterns match {
43+
case patterns0 :+ Trees.SeqLiteral(elems, _) => patterns0 ::: elems
44+
case _ => patterns
45+
}
46+
}
47+
48+
object Alternative extends AlternativeExtractor {
49+
def unapply(x: Pattern)(implicit ctx: Context): Option[List[Pattern]] = x match {
50+
case x: tpd.Alternative => Some(x.trees)
51+
case _ => None
52+
}
53+
}
54+
55+
object TypeTest extends TypeTestExtractor {
56+
def unapply(x: Pattern)(implicit ctx: Context): Option[TypeTree] = x match {
57+
case Trees.Typed(Trees.UnApply(_, _, _), _) => None
58+
case Trees.Typed(_, tpt) => Some(tpt)
59+
case _ => None
60+
}
61+
}
62+
63+
}
64+
65+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
trait PositionOpsImpl extends scala.tasty.reflect.PositionOps with TastyCoreImpl {
4+
5+
def PositionDeco(pos: Position): PositionAPI = new PositionAPI {
6+
def start: Int = pos.start
7+
def end: Int = pos.end
8+
9+
def sourceFile: java.nio.file.Path = pos.source.file.jpath
10+
11+
def startLine: Int = pos.startLine
12+
def endLine: Int = pos.endLine
13+
14+
def startColumn: Int = pos.startColumn
15+
def endColumn: Int = pos.endColumn
16+
}
17+
18+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.core.Contexts
4+
5+
import scala.tasty.util.{Show, ShowExtractors, ShowSourceCode}
6+
7+
trait PrintersImpl extends scala.tasty.reflect.Printers with scala.tasty.reflect.TastyCore { tasty: TastyImpl =>
8+
9+
def showExtractors: Show[tasty.type] = new ShowExtractors[tasty.type](this)
10+
11+
def showSourceCode: Show[tasty.type] = new ShowSourceCode[tasty.type](this)
12+
13+
/** Adds `show` as an extension method of a `Tree` */
14+
def TreeShowDeco(tree: Tree): ShowAPI = new ShowAPI {
15+
def show(implicit ctx: Contexts.Context, s: Show[tasty.type]): String = s.showTree(tree)
16+
}
17+
18+
/** Adds `show` as an extension method of a `TypeOrBoundsTree` */
19+
def TypeOrBoundsTreeShowDeco(tpt: TypeOrBoundsTree): ShowAPI = new ShowAPI {
20+
def show(implicit ctx: Contexts.Context, s: Show[tasty.type]): String = s.showTypeOrBoundsTree(tpt)
21+
}
22+
23+
/** Adds `show` as an extension method of a `TypeOrBounds` */
24+
def TypeOrBoundsShowDeco(tpe: TypeOrBounds): ShowAPI = new ShowAPI {
25+
def show(implicit ctx: Contexts.Context, s: Show[tasty.type]): String = s.showTypeOrBounds(tpe)
26+
}
27+
28+
/** Adds `show` as an extension method of a `CaseDef` */
29+
def CaseDefShowDeco(caseDef: CaseDef): ShowAPI = new ShowAPI {
30+
def show(implicit ctx: Contexts.Context, s: Show[tasty.type]): String = s.showCaseDef(caseDef)
31+
}
32+
33+
/** Adds `show` as an extension method of a `Pattern` */
34+
def PatternShowDeco(pattern: Pattern): ShowAPI = new ShowAPI {
35+
def show(implicit ctx: Contexts.Context, s: Show[tasty.type]): String = s.showPattern(pattern)
36+
}
37+
38+
/** Adds `show` as an extension method of a `Constant` */
39+
def ConstantShowDeco(const: Constant): ShowAPI = new ShowAPI {
40+
def show(implicit ctx: Contexts.Context, s: Show[tasty.type]): String = s.showConstant(const)
41+
}
42+
43+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package dotty.tools.dotc.tastyreflect
2+
3+
import dotty.tools.dotc.core.Contexts
4+
import dotty.tools.dotc.core.quoted.PickledQuotes
5+
import dotty.tools.dotc.reporting.Reporter
6+
import dotty.tools.dotc.reporting.diagnostic.MessageContainer
7+
8+
trait QuotedOpsImpl extends scala.tasty.reflect.QuotedOps with TastyCoreImpl {
9+
10+
def QuotedExprDeco[T](x: scala.quoted.Expr[T]): QuotedExprAPI = new QuotedExprAPI {
11+
def toTasty(implicit ctx: Context): Term = PickledQuotes.quotedExprToTree(x)
12+
}
13+
14+
def QuotedTypeDeco[T](x: scala.quoted.Type[T]): QuotedTypeAPI = new QuotedTypeAPI {
15+
def toTasty(implicit ctx: Context): TypeTree = PickledQuotes.quotedTypeToTree(x)
16+
}
17+
18+
def TermToQuoteDeco(term: Term): TermToQuotedAPI = new TermToQuotedAPI {
19+
20+
def toExpr[T: scala.quoted.Type](implicit ctx: Context): scala.quoted.Expr[T] = {
21+
typecheck(ctx)
22+
new scala.quoted.Exprs.TastyTreeExpr(term).asInstanceOf[scala.quoted.Expr[T]]
23+
}
24+
25+
private def typecheck[T: scala.quoted.Type](ctx: Contexts.Context): Unit = {
26+
implicit val ctx0: Contexts.FreshContext = ctx.fresh
27+
ctx0.setTyperState(ctx0.typerState.fresh())
28+
ctx0.typerState.setReporter(new Reporter {
29+
def doReport(m: MessageContainer)(implicit ctx: Contexts.Context): Unit = ()
30+
})
31+
val tp = QuotedTypeDeco(implicitly[scala.quoted.Type[T]]).toTasty
32+
ctx0.typer.typed(term, tp.tpe)
33+
if (ctx0.reporter.hasErrors) {
34+
val stack = new Exception().getStackTrace
35+
def filter(elem: StackTraceElement) =
36+
elem.getClassName.startsWith("dotty.tools.dotc.tasty.TastyImpl") ||
37+
!elem.getClassName.startsWith("dotty.tools.dotc")
38+
throw new scala.tasty.TastyTypecheckError(
39+
s"""Error during tasty reflection while typing term
40+
|term: ${term.show}
41+
|with expected type: ${tp.tpe.show}
42+
|
43+
| ${stack.takeWhile(filter).mkString("\n ")}
44+
""".stripMargin
45+
)
46+
}
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)