Skip to content

Remove quoted pattern patterns #8743

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

Merged
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
133 changes: 0 additions & 133 deletions library/src/scala/internal/quoted/Matcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,6 @@ import scala.quoted._
* /* Match def */
* '{ def x0(x1: T1, ..., xn: Tn): T0 = e1; e2 } =?= '{ def y0(y1: P1, ..., yn: Pn): P0 = p1; p2 } ===> withEnv(x0 -> y0, ..., xn -> yn)('[T0] =?= '[P0] &&& ... &&& '[Tn] =?= '[Pn] &&& '{e1} =?= '{p1} &&& '{e2} =?= '{p2})
*
* /* Match match */
* '{ e0 match { case u1 => e1; ...; case un => en } } =?= '{ p0 match { case q1 => p1; ...; case qn => pn } } ===>
* '{e0} =?= '{p0} &&& ... &&& '{en} =?= '{pn} &&& '⟨u1⟩ =?= '⟨q1⟩ &&& ... &&& '⟨un⟩ =?= '⟨qn⟩
*
* /* Match try */
* '{ try e0 catch { case u1 => e1; ...; case un => en } finally ef } =?= '{ try p0 catch { case q1 => p1; ...; case qn => pn } finally pf } ===> '{e0} =?= '{p0} &&& ... &&& '{en} =?= '{pn} &&& '⟨u1⟩ =?= '⟨q1⟩ &&& ... &&& '⟨un⟩ =?= '⟨qn⟩ &&& '{ef} =?= '{pf}
*
* // Types
*
* /* Match type */
Expand All @@ -107,30 +100,6 @@ import scala.quoted._
*
* /* Match annot (b) */
* '[T] =?= '[P @annot] ===> '[T] =?= '[P]
*
* // Patterns
*
* /* Match pattern whildcard */
* '⟨ _ ⟩ =?= '⟨ _ ⟩ ===> matched
*
* /* Match pattern bind */
* '⟨ x @ e ⟩ =?= '⟨ y @ p ⟩ ===> withEnv(x -> y)('⟨e⟩ =?= '⟨p⟩)
*
* /* Match pattern unapply */
* '⟨ e0(e1, ..., en)(using i1, ..., im ) ⟩ =?= '⟨ p0(p1, ..., pn)(using q1, ..., 1m) ⟩ ===> '⟨e0⟩ =?= '⟨p0⟩ &&& ... &&& '⟨en⟩ =?= '⟨pn⟩ &&& '{i1} =?= '{q1} &&& ... &&& '{im} =?= '{qm}
*
* /* Match pattern alternatives */
* '⟨ e1 | ... | en ⟩ =?= '⟨ p1 | ... | pn ⟩ ===> '⟨e1⟩ =?= '⟨p1⟩ &&& ... &&& '⟨en⟩ =?= '⟨pn⟩
*
* /* Match pattern type test */
* '⟨ e: T ⟩ =?= '⟨ p: U ⟩ ===> '⟨e⟩ =?= '⟨p⟩ &&& '[T] =?= [U]
*
* /* Match pattern ref */
* '⟨ `x` ⟩ =?= '⟨ `x` ⟩ ===> matched
*
* /* Match pattern ref splice */
* '⟨ `x` ⟩ =?= '⟨ hole ⟩ ===> matched('{`x`})
*
* ```
*/
private[quoted] object Matcher {
Expand Down Expand Up @@ -409,14 +378,6 @@ private[quoted] object Matcher {
// TODO match tpt1 with tpt2?
matched

/* Match match */
case (Match(scru1, cases1), Match(scru2, cases2)) =>
scru1 =?= scru2 &&& matchLists(cases1, cases2)(caseMatches)

/* Match try */
case (Try(body1, cases1, finalizer1), Try(body2, cases2, finalizer2)) =>
body1 =?= body2 &&& matchLists(cases1, cases2)(caseMatches) &&& treeOptMatches(finalizer1, finalizer2)

// Ignore type annotations
// TODO remove this
/* Match annot (a) */
Expand Down Expand Up @@ -488,86 +449,6 @@ private[quoted] object Matcher {
}
}

private def caseMatches(scrutinee: CaseDef, pattern: CaseDef)(using Context, Env): Matching = {
val (caseEnv, patternMatch) = patternsMatches(scrutinee.pattern, pattern.pattern)
withEnv(caseEnv) {
patternMatch
&&& treeOptMatches(scrutinee.guard, pattern.guard)
&&& scrutinee.rhs =?= pattern.rhs
}
}


/** Check that the pattern trees match and return the contents from the pattern holes.
* Return a tuple with the new environment containing the bindings defined in this pattern and a matching.
* The matching is None if the pattern trees do not match otherwise return Some of a tuple containing all the contents in the holes.
*
* @param scrutinee The pattern tree beeing matched
* @param pattern The pattern tree that the scrutinee should match. Contains `patternHole` holes.
* @param `summon[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
* @return The new environment containing the bindings defined in this pattern tuppled with
* `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
*/
private def patternsMatches(scrutinee: Tree, pattern: Tree)(using Context, Env): (Env, Matching) = (scrutinee, pattern) match {
/* Match pattern ref splice */
case (v1: Term, Unapply(TypeApply(Select(patternHole @ Ident("patternHole"), "unapply"), List(tpt)), Nil, Nil))
if patternHole.symbol.owner == summon[Context].requiredModule("scala.runtime.quoted.Matcher") =>
(summon[Env], matched(v1.seal))

/* Match pattern whildcard */
case (Ident("_"), Ident("_")) =>
(summon[Env], matched)

/* Match pattern bind */
case (Bind(name1, body1), Bind(name2, body2)) =>
val bindEnv = summon[Env] + (scrutinee.symbol -> pattern.symbol)
patternsMatches(body1, body2)(using summon[Context], bindEnv)

/* Match pattern unapply */
case (Unapply(fun1, implicits1, patterns1), Unapply(fun2, implicits2, patterns2)) =>
val (patEnv, patternsMatch) = foldPatterns(patterns1, patterns2)
(patEnv, patternsMatches(fun1, fun2)._2 &&& implicits1 =?= implicits2 &&& patternsMatch)

/* Match pattern alternatives */
case (Alternatives(patterns1), Alternatives(patterns2)) =>
foldPatterns(patterns1, patterns2)

/* Match pattern type test */
case (Typed(Ident("_"), tpt1), Typed(Ident("_"), tpt2)) =>
(summon[Env], tpt1 =?= tpt2)

case (v1: Term, v2: Term) =>
(summon[Env], v1 =?= v2)

case _ =>
if (debug)
println(
s""">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|Scrutinee
| ${scrutinee.show}
|
|${scrutinee.showExtractors}
|
|did not match pattern
| ${pattern.show}
|
|${pattern.showExtractors}
|
|with environment: ${summon[Env]}
|
|
|""".stripMargin)
(summon[Env], notMatched)
}

private def foldPatterns(patterns1: List[Tree], patterns2: List[Tree])(using Context, Env): (Env, Matching) = {
if (patterns1.size != patterns2.size) (summon[Env], notMatched)
else patterns1.zip(patterns2).foldLeft((summon[Env], matched)) { (acc, x) =>
val (env, res) = patternsMatches(x._1, x._2)(using summon[Context], acc._1)
(env, acc._2 &&& res)
}
}

private def isTypeBinding(tree: Tree): Boolean = tree match {
case tree: TypeDef => hasPatternTypeAnnotation(tree.symbol)
case _ => false
Expand Down Expand Up @@ -595,20 +476,6 @@ private[quoted] object Matcher {
case _ => None
}

/** Is this matching the result of a successful match */
def (self: Matching) isMatch: Boolean = self.isDefined

/** Joins the mattchings into a single matching. If any matching is `None` the result is `None`.
* Otherwise the result is `Some` of the concatenation of the tupples.
*/
def foldMatchings(matchings: Matching*): Matching = {
// TODO improve performance
matchings.foldLeft[Matching](Some(())) {
case (Some(acc), Some(holes)) => Some(acc ++ holes)
case (_, _) => None
}
}

}

}
80 changes: 0 additions & 80 deletions tests/run-macros/quote-matcher-runtime.check
Original file line number Diff line number Diff line change
Expand Up @@ -634,86 +634,6 @@ Pattern: {
}
Result: Some(List())

Scrutinee: 1 match {
case _ =>
2
}
Pattern: 1 match {
case _ =>
2
}
Result: Some(List())

Scrutinee: 1 match {
case _ =>
2
}
Pattern: scala.internal.quoted.CompileTime.patternHole[scala.Int] match {
case _ =>
scala.internal.quoted.CompileTime.patternHole[scala.Int]
}
Result: Some(List(Expr(1), Expr(2)))

Scrutinee: scala.Predef.??? match {
case scala.None =>
2
}
Pattern: scala.Predef.??? match {
case scala.None =>
2
}
Result: Some(List())

Scrutinee: scala.Predef.??? match {
case scala.Some(1) =>
2
}
Pattern: scala.Predef.??? match {
case scala.Some(1) =>
2
}
Result: Some(List())

Scrutinee: try 1 catch {
case _ =>
2
}
Pattern: try 1 catch {
case _ =>
2
}
Result: Some(List())

Scrutinee: try 1 finally {
2
()
}
Pattern: try 1 finally {
2
()
}
Result: Some(List())

Scrutinee: try 1 catch {
case _ =>
2
}
Pattern: try scala.internal.quoted.CompileTime.patternHole[scala.Int] catch {
case _ =>
scala.internal.quoted.CompileTime.patternHole[scala.Int]
}
Result: Some(List(Expr(1), Expr(2)))

Scrutinee: try 1 finally {
2
()
}
Pattern: try scala.internal.quoted.CompileTime.patternHole[scala.Int] finally {
scala.internal.quoted.CompileTime.patternHole[scala.Int]
()
}
Result: Some(List(Expr(1), Expr(2)))

Scrutinee: scala.List.apply[scala.Int](1, 2, 3).foreach[scala.Unit](((x: scala.Int) => scala.Predef.println(x)))
Pattern: {
@scala.internal.quoted.CompileTime.patternType type T
Expand Down
11 changes: 0 additions & 11 deletions tests/run-macros/quote-matcher-runtime/quoted_2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,6 @@ object Test {
matches({ def a: Int = a; a + a }, { def a: Int = a; a + a })
matches({ def a: Int = a; a + a }, { def a: Int = patternHole[Int]; a + patternHole[Int] })
matches({ lazy val a: Int = a }, { lazy val b: Int = b })
matches(1 match { case _ => 2 }, 1 match { case _ => 2 })
matches(1 match { case _ => 2 }, patternHole[Int] match { case _ => patternHole[Int] })
matches(??? match { case None => 2 }, ??? match { case None => 2 })
matches(??? match { case Some(1) => 2 }, ??? match { case Some(1) => 2 })
// matches(??? match { case Some(1) => 2 }, ??? match { case Some(patternMatchHole()) => 2 })
// matches(??? match { case Some(n) => 2 }, ??? match { case Some(patternMatchBindHole(n)) => 2 })
// matches(??? match { case Some(n @ Some(m)) => 2 }, ??? match { case Some(patterMatchBindHole(n @ Some(patternMatchBindHole(m)))) => 2 })
matches(try 1 catch { case _ => 2 }, try 1 catch { case _ => 2 })
matches(try 1 finally 2, try 1 finally 2)
matches(try 1 catch { case _ => 2 }, try patternHole[Int] catch { case _ => patternHole[Int] })
matches(try 1 finally 2, try patternHole[Int] finally patternHole[Int])
matches(List(1, 2, 3).foreach(x => println(x)), { @patternType type T; patternHole[List[Int]].foreach[T](patternHole[Int => T]) })
matches(List(1, 2, 3).foreach(x => println(x)), { @patternType type T = Unit; patternHole[List[Int]].foreach[T](patternHole[Int => T]) })
matches(List(1, 2, 3).foreach(x => println(x)), { @patternType type T <: String; patternHole[List[Int]].foreach[T](patternHole[Int => T]) })
Expand Down