Skip to content

Commit

Permalink
Merge pull request #13362 from dotty-staging/add-TypedOrTest
Browse files Browse the repository at this point in the history
Add TypedOrTest as super type of Typed in reflection
  • Loading branch information
nicolasstucki authored Aug 26, 2021
2 parents b830af3 + ffbd83d commit daeed81
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 16 deletions.
32 changes: 31 additions & 1 deletion compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
case x: (tpd.SeqLiteral & x.type) => Some(x)
case x: (tpd.Inlined & x.type) => Some(x)
case x: (tpd.NamedArg & x.type) => Some(x)
case x: (tpd.Typed & x.type) =>
TypedTypeTest.unapply(x) // Matches `Typed` but not `TypedOrTest`
case _ => if x.isTerm then Some(x) else None
end TermTypeTest

Expand Down Expand Up @@ -669,7 +671,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object TypedTypeTest extends TypeTest[Tree, Typed]:
def unapply(x: Tree): Option[Typed & x.type] = x match
case x: (tpd.Typed & x.type) => Some(x)
case x: (tpd.Typed & x.type) =>
x.expr match
case TermTypeTest(_) => Some(x)
case _ => None
case _ => None
end TypedTypeTest

Expand All @@ -689,6 +694,31 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
end extension
end TypedMethods

type TypedOrTest = tpd.Typed

object TypedOrTestTypeTest extends TypeTest[Tree, TypedOrTest]:
def unapply(x: Tree): Option[TypedOrTest & x.type] = x match
case x: (tpd.Typed & x.type) => Some(x)
case _ => None
end TypedOrTestTypeTest

object TypedOrTest extends TypedOrTestModule:
def apply(expr: Term, tpt: TypeTree): Typed =
withDefaultPos(tpd.Typed(xCheckMacroValidExpr(expr), tpt))
def copy(original: Tree)(expr: Term, tpt: TypeTree): Typed =
tpd.cpy.Typed(original)(xCheckMacroValidExpr(expr), tpt)
def unapply(x: Typed): (Term, TypeTree) =
(x.expr, x.tpt)
end TypedOrTest

given TypedOrTestMethods: TypedOrTestMethods with
extension (self: Typed)
def tree: Tree = self.expr
def tpt: TypeTree = self.tpt
end extension
end TypedOrTestMethods


type Assign = tpd.Assign

object AssignTypeTest extends TypeTest[Tree, Assign]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ object Extractors {
this += "Unapply(" += fun += ", " ++= implicits += ", " ++= patterns += ")"
case Alternatives(patterns) =>
this += "Alternatives(" ++= patterns += ")"
case TypedOrTest(tree, tpt) =>
this += "TypedOrTest(" += tree += ", " += tpt += ")"
}

def visitConstant(x: Constant): this.type = x match {
Expand Down
10 changes: 7 additions & 3 deletions compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -928,9 +928,13 @@ object SourceCode {
case Alternatives(trees) =>
inParens(printPatterns(trees, " | "))

case Typed(Wildcard(), tpt) =>
this += "_: "
printTypeTree(tpt)
case TypedOrTest(tree1, tpt) =>
tree1 match
case Wildcard() =>
this += "_: "
printTypeTree(tpt)
case _ =>
printPattern(tree1)

case v: Term =>
printTree(v)
Expand Down
60 changes: 49 additions & 11 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* | +- Apply
* | +- TypeApply
* | +- Super
* | +- Typed
* | +- Assign
* | +- Block
* | +- Closure
Expand All @@ -144,7 +143,15 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* | +- Inlined
* | +- SelectOuter
* | +- While
* | +---+- Typed
* | /
* +- TypedOrTest +----------------·
* +- Bind
* +- Unapply
* +- Alternatives
* |
* +- CaseDef
* +- TypeCaseDef
* |
* +- TypeTree ----+- Inferred
* | +- TypeIdent
Expand All @@ -162,13 +169,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* |
* +- TypeBoundsTree
* +- WildcardTypeTree
* |
* +- CaseDef
* |
* +- TypeCaseDef
* +- Bind
* +- Unapply
* +- Alternatives
*
* +- ParamClause -+- TypeParamClause
* +- TermParamClause
Expand Down Expand Up @@ -1135,8 +1135,12 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Typed` */
given TypedTypeTest: TypeTest[Tree, Typed]

/** Tree representing a type ascription `x: T` in the source code */
type Typed <: Term
/** Tree representing a type ascription `x: T` in the source code.
*
* Also represents a pattern that contains a term `x`.
* Other `: T` patterns use the more general `TypedOrTest`.
*/
type Typed <: Term & TypedOrTest

/** Module object of `type Typed` */
val Typed: TypedModule
Expand Down Expand Up @@ -1583,6 +1587,38 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
end extension
end WhileMethods

/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `TypedOrTest` */
given TypedOrTestTypeTest: TypeTest[Tree, TypedOrTest]

/** Tree representing a type ascription or type test pattern `x: T` in the source code. */
type TypedOrTest <: Tree

/** Module object of `type TypedOrTest` */
val TypedOrTest: TypedOrTestModule

/** Methods of the module object `val TypedOrTest` */
trait TypedOrTestModule { this: TypedOrTest.type =>

/** Create a type ascription `<x: Tree>: <tpt: TypeTree>` */
def apply(expr: Tree, tpt: TypeTree): TypedOrTest

def copy(original: Tree)(expr: Tree, tpt: TypeTree): TypedOrTest

/** Matches `<expr: Tree>: <tpt: TypeTree>` */
def unapply(x: TypedOrTest): (Tree, TypeTree)
}

/** Makes extension methods on `TypedOrTest` available without any imports */
given TypedOrTestMethods: TypedOrTestMethods

/** Extension methods of `TypedOrTest` */
trait TypedOrTestMethods:
extension (self: TypedOrTest)
def tree: Tree
def tpt: TypeTree
end extension
end TypedOrTestMethods

// ----- TypeTrees ------------------------------------------------

/** Type tree representing a type written in the source */
Expand Down Expand Up @@ -4414,6 +4450,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
Unapply.copy(pattern)(transformTerm(pattern.fun)(owner), transformSubTrees(pattern.implicits)(owner), transformTrees(pattern.patterns)(owner))
case pattern: Alternatives =>
Alternatives.copy(pattern)(transformTrees(pattern.patterns)(owner))
case TypedOrTest(inner, tpt) =>
TypedOrTest.copy(tree)(transformTree(inner)(owner), transformTypeTree(tpt)(owner))
}
}

Expand Down Expand Up @@ -4464,7 +4502,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
case New(tpt) =>
New.copy(tree)(transformTypeTree(tpt)(owner))
case Typed(expr, tpt) =>
Typed.copy(tree)(/*FIXME #12222: transformTerm(expr)(owner)*/transformTree(expr)(owner).asInstanceOf[Term], transformTypeTree(tpt)(owner))
Typed.copy(tree)(transformTerm(expr)(owner), transformTypeTree(tpt)(owner))
case tree: NamedArg =>
NamedArg.copy(tree)(tree.name, transformTerm(tree.value)(owner))
case Assign(lhs, rhs) =>
Expand Down
3 changes: 3 additions & 0 deletions project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ object MiMaFilters {
exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SourceFileMethods.path"),
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#UnapplyModule.apply"),
exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#UnapplyModule.apply"),
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.TypedOrTestTypeTest"),
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.TypedOrTest"),
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule.TypedOrTestMethods"),
)
}
2 changes: 1 addition & 1 deletion tests/run-staging/i5161.check
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
run : Some(2)
show : scala.Tuple2.apply[scala.Option[scala.Int], scala.Option[scala.Int]](scala.Some.apply[scala.Int](1), scala.Some.apply[scala.Int](1)) match {
case scala.Tuple2((scala.Some(x): scala.Some[scala.Int]), (scala.Some(y): scala.Some[scala.Int])) =>
case scala.Tuple2(scala.Some(x), scala.Some(y)) =>
scala.Some.apply[scala.Int](x.+(y))
case _ =>
scala.None
Expand Down

0 comments on commit daeed81

Please sign in to comment.