Skip to content
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

Add TypedOrTest as super type of Typed in reflection #13362

Merged
merged 1 commit into from
Aug 26, 2021
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
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering about this type test (is my tree a term?) and isTerm (which is also "is my tree a term?"). I infer from the existing match that they don't always give the same answers. That seems wrong or at the very least confusing, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They don't always give the same answer. We aligned the term notation with the one in TastyFormat. The compiler does something slightly different in these cases. I will see if we can align the compiler with TASTy, that would simplify these runtime type tests.

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