Skip to content

Commit

Permalink
Detect non Expr[..] splice patterns (#19944)
Browse files Browse the repository at this point in the history
We compute the pattern using `Expr[pt]` of the prototype `pt` of the
splice, but this is not enough to reject non-matching patterns. The
quoted splices are encoded away before we get to the pattern matching
phase where we could potentially detect that they will not match.
Instead we check that all quote patterns are `Expr[..]` when typing the
pattern.

Fixes #19941
  • Loading branch information
nicolasstucki authored Mar 19, 2024
2 parents 6586418 + 2bcf0db commit 96faa3e
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 2 deletions.
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/quoted/QuotePatterns.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ object QuotePatterns:
/** Check for restricted patterns */
def checkPattern(quotePattern: QuotePattern)(using Context): Unit = new tpd.TreeTraverser {
def traverse(tree: Tree)(using Context): Unit = tree match {
case _: SplicePattern =>
case tree: SplicePattern =>
if !tree.body.typeOpt.derivesFrom(defn.QuotedExprClass) then
report.error(i"Splice pattern must match an Expr[...]", tree.body.srcPos)
case tdef: TypeDef if tdef.symbol.isClass =>
val kind = if tdef.symbol.is(Module) then "objects" else "classes"
report.error(em"Implementation restriction: cannot match $kind", tree.srcPos)
Expand Down
4 changes: 4 additions & 0 deletions tests/neg-macros/i19941.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Error: tests/neg-macros/i19941.scala:7:14 ---------------------------------------------------------------------------
7 | case '{ ${hd *: tl} : *:[Int, EmptyTuple] } => '{ ??? } // error
| ^^^^^^^^
| Splice pattern must match an Expr[...]
7 changes: 7 additions & 0 deletions tests/neg-macros/i19941.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import scala.quoted.*

inline def expandMacro(inline from: Tuple): Any = ${ expandMacroImpl }

def expandMacroImpl(using Quotes): Expr[?] =
'{ 1 *: EmptyTuple } match
case '{ ${hd *: tl} : *:[Int, EmptyTuple] } => '{ ??? } // error
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ object Test {
def impl(receiver: Expr[StringContext])(using qctx: scala.quoted.Quotes) = {
import quotes.reflect.Repeated
receiver match {
case '{ StringContext(${Repeated(parts, tpt)}*) } => // now OK
case '{ StringContext(${Repeated(parts, tpt)}*) } => // error: Repeated is not an Expr pattern
}
}
}

0 comments on commit 96faa3e

Please sign in to comment.