Skip to content

Commit 652092b

Browse files
authored
Merge pull request #4905 from dotty-staging/split-tasty-reflect
Split TASTy reflect interface and implementation
2 parents 9b7721c + cc6646f commit 652092b

35 files changed

+2310
-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)