Skip to content

Commit

Permalink
Detect non Exp[..] splice patterns
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 scala#19941
  • Loading branch information
nicolasstucki committed Mar 14, 2024
1 parent 4859415 commit 676b250
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"Spice 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
| ^^^^^^^^
| Spice 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 676b250

Please sign in to comment.