Skip to content
Open
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
4 changes: 4 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ lazy val tastyQuery =
mimaBinaryIssueFilters ++= {
import com.typesafe.tools.mima.core.*
Seq(
// New pattern tree node for named extractor patterns `case Foo(field = pat)`
ProblemFilters.exclude[MissingClassProblem]("tastyquery.Trees$NamedPattern"),
ProblemFilters.exclude[MissingClassProblem]("tastyquery.Trees$NamedPattern$"),
ProblemFilters.exclude[MissingFieldProblem]("tastyquery.Trees.NamedPattern"),
)
},

Expand Down
5 changes: 5 additions & 0 deletions tasty-query/shared/src/main/scala/tastyquery/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,11 @@ private[tastyquery] object Printers:
case ExprPattern(expr) =>
print(expr)

case NamedPattern(name, body) =>
print(name)
print(" = ")
print(body)

case QuotePattern(bindings, body, quotes, patternType) =>
print("'<")
print(quotes)
Expand Down
2 changes: 2 additions & 0 deletions tasty-query/shared/src/main/scala/tastyquery/Traversers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ object Traversers:
traverse(patterns)
case ExprPattern(expr) =>
traverse(expr)
case NamedPattern(name, body) =>
traverse(body)
case WildcardPattern(tpe) =>
()
case QuotePattern(bindings, body, quotes, patternType) =>
Expand Down
6 changes: 6 additions & 0 deletions tasty-query/shared/src/main/scala/tastyquery/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,12 @@ object Trees {
override final def withPos(pos: SourcePosition): ExprPattern = ExprPattern(expr)(pos)
end ExprPattern

/** A named argument pattern `name = body` in an [[Unapply]], as in `case Foo(field = pat)`. */
final case class NamedPattern(name: UnsignedTermName, body: PatternTree)(pos: SourcePosition)
extends PatternTree(pos):
override final def withPos(pos: SourcePosition): NamedPattern = NamedPattern(name, body)(pos)
end NamedPattern

/** A tree representing a quote pattern `'{ type binding1; ...; body }` or `'[ type binding1; ...; body ]`.
*
* The `bindings` contain the list of quote pattern type variable definitions (`TypeTreeBind`s)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,13 @@ private[tasties] class TreeUnpickler private (
reader.readByte()
val shared = forkAt(reader.readAddr()).readPattern
if spn.isUnknown then shared else shared.withPos(spn)
case NAMEDARG =>
// Named extractor patterns (e.g., `case Foo(field = value)`) wrap sub-patterns in NAMEDARG.
val spn = span
reader.readByte()
val name = readUnsignedName()
val body = readPattern
NamedPattern(name, body)(spn)
case _ =>
val expr = readTerm
ExprPattern(expr)(expr.pos)
Expand Down
11 changes: 11 additions & 0 deletions tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,17 @@ class ReadTreeSuite extends RestrictedUnpicklingSuite {
assert(containsSubtree(guardWithAlternatives)(clue(tree)))
}

testUnpickle("named-extractor-pattern", "simple_trees.NamedExtractorPattern") { tree =>
// case Wrapper(value = Some(v)) => v
val namedPatternCheck: StructureCheck = {
case NamedPattern(
SimpleName("value"),
TypeTest(Unapply(_, _, List(Bind(SimpleName("v"), WildcardPattern(_), _))), _)
) =>
}
assert(containsSubtree(namedPatternCheck)(clue(tree)))
}

testUnpickle("assign", "simple_trees.Assign") { tree =>
val assignBlockMatch: StructureCheck = {
case Block(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package simple_trees

case class Wrapper(value: Option[String])

class NamedExtractorPattern {
def extract(items: List[Wrapper]): List[String] =
items.collect { case Wrapper(value = Some(v)) => v }
}
Loading