Skip to content

Fix Reflection wildcard and Typed abstraction (alt 2) #13345

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

Closed
Closed
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
58 changes: 54 additions & 4 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,19 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object TermTypeTest extends TypeTest[Tree, Term]:
def unapply(x: Tree): Option[Term & x.type] = x match
case x: tpd.PatternTree => None
case x: (tpd.Ident & x.type) =>
if x.isTerm && x.name != nme.WILDCARD then Some(x)
else None
case x: (tpd.Typed & x.type) =>
// Matches `Typed` but not `TypedTree`
TypedTypeTest.unapply(x)
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 _ => if x.isTerm then Some(x) else None
case x: tpd.PatternTree => None
case _ =>
if x.isTerm then Some(x)
else None
end TermTypeTest

object Term extends TermModule:
Expand Down Expand Up @@ -429,7 +437,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object IdentTypeTest extends TypeTest[Tree, Ident]:
def unapply(x: Tree): Option[Ident & x.type] = x match
case x: (tpd.Ident & x.type) if x.isTerm => Some(x)
case x: (tpd.Ident & x.type) if x.isTerm && x.name != nme.WILDCARD => Some(x)
case _ => None
end IdentTypeTest

Expand Down Expand Up @@ -655,7 +663,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 Down Expand Up @@ -1406,6 +1417,45 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
end extension
end TypeCaseDefMethods


type WildcardPattern = tpd.Ident

object WildcardPatternTypeTest extends TypeTest[Tree, WildcardPattern]:
def unapply(x: Tree): Option[WildcardPattern & x.type] = x match
case x: (tpd.Ident & x.type) if x.name == nme.WILDCARD => Some(x)
case _ => None
end WildcardPatternTypeTest

object WildcardPattern extends WildcardPatternModule:
def apply(): WildcardPattern =
withDefaultPos(untpd.Ident(nme.WILDCARD).withType(dotc.core.Symbols.defn.AnyType))
def unapply(pattern: WildcardPattern): true = true
end WildcardPattern

type TypedTree = tpd.Typed

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

object TypedTree extends TypedTreeModule:
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 TypedTree

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

type Bind = tpd.Bind

object BindTypeTest extends TypeTest[Tree, Bind]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ object Extractors {
this += "Literal(" += const += ")"
case New(tpt) =>
this += "New(" += tpt += ")"
case Typed(expr, tpt) =>
this += "Typed(" += expr += ", " += tpt += ")"
case TypedTree(tree, tpt) =>
this += "TypedTree(" += tree += ", " += tpt += ")"
case NamedArg(name, arg) =>
this += "NamedArg(\"" += name += "\", " += arg += ")"
case Assign(lhs, rhs) =>
Expand Down Expand Up @@ -166,6 +166,8 @@ object Extractors {
this += "CaseDef(" += pat += ", " += guard += ", " += body += ")"
case TypeCaseDef(pat, body) =>
this += "TypeCaseDef(" += pat += ", " += body += ")"
case WildcardPattern() =>
this += "WildcardPattern()"
case Bind(name, body) =>
this += "Bind(\"" += name += "\", " += body += ")"
case Unapply(fun, implicits, patterns) =>
Expand Down
33 changes: 23 additions & 10 deletions compiler/src/scala/quoted/runtime/impl/printers/SourceCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ object SourceCode {
}
this

case Ident("_") =>
case WildcardPattern() =>
this += "_"

case tree: Ident =>
Expand Down Expand Up @@ -399,7 +399,7 @@ object SourceCode {
case _ => printQualTree(fn)
}
val args1 = args match {
case init :+ Typed(Repeated(Nil, _), _) => init // drop empty var args at the end
case init :+ TypedTree(Repeated(Nil, _), _) => init // drop empty var args at the end
case _ => args
}

Expand Down Expand Up @@ -428,7 +428,7 @@ object SourceCode {
inSquare(this += id)
this

case Typed(term, tpt) =>
case TypedTree(term: Term, tpt) =>
tpt.tpe match {
case Types.Repeated(_) =>
printTree(term)
Expand All @@ -453,6 +453,15 @@ object SourceCode {
printTypeOrAnnots(tpt.tpe)
}
}
case TypedTree(tree1, tpt) =>
printPattern(tree1)
tree1 match
case WildcardPattern() =>
this += ":"
printType(tpt.tpe)
case _ => // Alternatives, Unapply, Bind
this


case Assign(lhs, rhs) =>
printTree(lhs)
Expand Down Expand Up @@ -614,7 +623,7 @@ object SourceCode {
case Select(qual, _) => rec(qual)
case Apply(fn, _) => rec(fn)
case TypeApply(fn, _) => rec(fn)
case Typed(_, _) => this += doubleLineBreak()
case TypedTree(_, _) => this += doubleLineBreak()
case _ => this += lineBreak()
}
next match {
Expand Down Expand Up @@ -896,13 +905,13 @@ object SourceCode {
}

private def printPattern(pattern: Tree): this.type = pattern match {
case Ident("_") =>
case WildcardPattern() =>
this += "_"

case Bind(name, Ident("_")) =>
case Bind(name, WildcardPattern()) =>
this += name

case Bind(name, Typed(Ident("_"), tpt)) =>
case Bind(name, TypedTree(WildcardPattern(), tpt)) =>
this += highlightValDef(name) += ": "
printTypeTree(tpt)

Expand All @@ -928,9 +937,13 @@ object SourceCode {
case Alternatives(trees) =>
inParens(printPatterns(trees, " | "))

case Typed(Ident("_"), tpt) =>
this += "_: "
printTypeTree(tpt)
case TypedTree(tree1, tpt) =>
tree1 match
case WildcardPattern() =>
this += "_: "
printTypeTree(tpt)
case _ =>
printPattern(tree1)

case v: Term =>
printTree(v)
Expand Down
4 changes: 2 additions & 2 deletions library/src/scala/quoted/ExprMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ trait ExprMap:
tree
case New(tpt) =>
New.copy(tree)(transformTypeTree(tpt)(owner))
case Typed(expr, tpt) =>
case TypedTree(expr: Term, tpt) =>
val tp = tpt.tpe match
case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "<repeated>"), List(tp0: TypeRepr)) =>
TypeRepr.of[Seq].appliedTo(tp0)
case tp => tp
Typed.copy(tree)(transformTerm(expr, tp)(owner), transformTypeTree(tpt)(owner))
TypedTree.copy(tree)(transformTerm(expr, tp)(owner), transformTypeTree(tpt)(owner))
case tree: NamedArg =>
NamedArg.copy(tree)(tree.name, transformTerm(tree.value, tpe)(owner))
case Assign(lhs, rhs) =>
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/quoted/FromExpr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ object FromExpr {
def rec(tree: Term): Option[T] = tree match {
case Block(stats, e) => if stats.isEmpty then rec(e) else None
case Inlined(_, bindings, e) => if bindings.isEmpty then rec(e) else None
case Typed(e, _) => rec(e)
case TypedTree(e: Term, _) => rec(e)
case _ =>
tree.tpe.widenTermRefByName match
case ConstantType(c) => Some(c.value.asInstanceOf[T])
Expand Down
91 changes: 78 additions & 13 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* | +- Apply
* | +- TypeApply
* | +- Super
* | +- Typed
* | +- Assign
* | +- Block
* | +- Closure
Expand All @@ -146,7 +145,16 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* | +- Inlined
* | +- SelectOuter
* | +- While
* | +---+- Typed (deprecated)
* | /
* +- TypedTree +------------------·
* +- WildcardPattern
* +- Bind
* +- Unapply
* +- Alternatives
* |
* +- CaseDef
* +- TypeCaseDef
* |
* +- TypeTree ----+- Inferred
* | +- TypeIdent
Expand All @@ -164,13 +172,6 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
* |
* +- TypeBoundsTree
* +- WildcardTypeTree
* |
* +- CaseDef
* |
* +- TypeCaseDef
* +- Bind
* +- Unapply
* +- Alternatives
*
* +- ParamClause -+- TypeParamClause
* +- TermParamClause
Expand Down Expand Up @@ -1118,15 +1119,23 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
end SuperMethods

/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Typed` */
@deprecated("Use TypedTree", "3.1.0")
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 `TypedTree`.
*/
@deprecated("Use TypedTree", "3.1.0")
type Typed <: Term & TypedTree

/** Module object of `type Typed` */
@deprecated("Use TypedTree", "3.1.0")
val Typed: TypedModule

/** Methods of the module object `val Typed` */
@deprecated("Use TypedTree", "3.1.0")
trait TypedModule { this: Typed.type =>

/** Create a type ascription `<x: Term>: <tpt: TypeTree>` */
Expand All @@ -1139,9 +1148,11 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
}

/** Makes extension methods on `Typed` available without any imports */
@deprecated("Use TypedTree", "3.1.0")
given TypedMethods: TypedMethods

/** Extension methods of `Typed` */
@deprecated("Use TypedTree", "3.1.0")
trait TypedMethods:
extension (self: Typed)
def expr: Term
Expand Down Expand Up @@ -2049,6 +2060,56 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>

// ----- Patterns ------------------------------------------------

/** Pattern representing a `_` wildcard. */
type WildcardPattern <: Tree

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

/** Module object of `type WildcardPattern` */
val WildcardPattern: WildcardPatternModule

/** Methods of the module object `val WildcardPattern` */
trait WildcardPatternModule { this: WildcardPattern.type =>
def apply(): WildcardPattern
def unapply(pattern: WildcardPattern): true
}

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

/** Tree representing a type ascription or pattern `x: T` in the source code
*
* The tree `x` may contain a `Constant`, `Ref`, `Wildcard`, `Bind`, `Unapply` or `Alternatives`.
*/
type TypedTree <: Term

/** Module object of `type TypedTree` */
val TypedTree: TypedTreeModule

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

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

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

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

/** Makes extension methods on `TypedTree` available without any imports */
given TypedTreeMethods: TypedTreeMethods

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

/** Pattern representing a `_ @ _` binding. */
type Bind <: Tree

Expand Down Expand Up @@ -4281,7 +4342,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
x
case New(tpt) =>
foldTree(x, tpt)(owner)
case Typed(expr, tpt) =>
case TypedTree(expr, tpt) =>
foldTree(foldTree(x, expr)(owner), tpt)(owner)
case NamedArg(_, arg) =>
foldTree(x, arg)(owner)
Expand Down Expand Up @@ -4341,6 +4402,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
case TypeBoundsTree(lo, hi) => foldTree(foldTree(x, lo)(owner), hi)(owner)
case CaseDef(pat, guard, body) => foldTree(foldTrees(foldTree(x, pat)(owner), guard)(owner), body)(owner)
case TypeCaseDef(pat, body) => foldTree(foldTree(x, pat)(owner), body)(owner)
case WildcardPattern() => x
case Bind(_, body) => foldTree(x, body)(owner)
case Unapply(fun, implicits, patterns) => foldTrees(foldTrees(foldTree(x, fun)(owner), implicits)(owner), patterns)(owner)
case Alternatives(patterns) => foldTrees(x, patterns)(owner)
Expand Down Expand Up @@ -4401,12 +4463,15 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
transformCaseDef(tree)(owner)
case tree: TypeCaseDef =>
transformTypeCaseDef(tree)(owner)
case WildcardPattern() => tree
case pattern: Bind =>
Bind.copy(pattern)(pattern.name, pattern.pattern)
case pattern: Unapply =>
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 TypedTree(expr, tpt) =>
TypedTree.copy(tree)(transformTree(expr)(owner), transformTypeTree(tpt)(owner))
}
}

Expand Down Expand Up @@ -4456,8 +4521,8 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
tree
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))
case TypedTree(expr: Term, tpt) =>
TypedTree.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
Loading