Skip to content

Commit 9ed7ac5

Browse files
committed
Detect quoted pattern variables in alternatives
Fixes #14696
1 parent 400427d commit 9ed7ac5

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import dotty.tools.dotc.typer.Implicits._
2020
import dotty.tools.dotc.typer.Inferencing._
2121
import dotty.tools.dotc.util.Spans._
2222
import dotty.tools.dotc.util.Stats.record
23-
23+
import dotty.tools.dotc.reporting.IllegalVariableInPatternAlternative
2424
import scala.collection.mutable
2525

2626

@@ -243,6 +243,17 @@ trait QuotesAndSplices {
243243
res
244244
}
245245

246+
def checkAlternativeBinds(pat0: Tree): Unit =
247+
def rec(pat: Tree): Unit =
248+
pat match
249+
case Typed(pat, _) => rec(pat)
250+
case UnApply(_, _, pats) => pats.foreach(rec)
251+
case pat: Bind =>
252+
report.error(IllegalVariableInPatternAlternative(pat.symbol.name), pat.withSpan(pat.nameSpan))
253+
rec(pat.body)
254+
case _ =>
255+
if ctx.mode.is(Mode.InPatternAlternative) then rec(pat0)
256+
246257
val patBuf = new mutable.ListBuffer[Tree]
247258
val freshTypePatBuf = new mutable.ListBuffer[Tree]
248259
val freshTypeBindingsBuff = new mutable.ListBuffer[Tree]
@@ -254,6 +265,7 @@ trait QuotesAndSplices {
254265
val newSplice = ref(defn.QuotedRuntime_exprSplice).appliedToType(tpt1.tpe).appliedTo(Typed(pat, exprTpt))
255266
transform(newSplice)
256267
case Apply(TypeApply(fn, targs), Apply(sp, pat :: Nil) :: args :: Nil) if fn.symbol == defn.QuotedRuntimePatterns_patternHigherOrderHole =>
268+
checkAlternativeBinds(pat)
257269
args match // TODO support these patterns. Possibly using scala.quoted.util.Var
258270
case SeqLiteral(args, _) =>
259271
for arg <- args; if arg.symbol.is(Mutable) do
@@ -266,6 +278,7 @@ trait QuotesAndSplices {
266278
patBuf += pat1
267279
}
268280
case Apply(fn, pat :: Nil) if fn.symbol.isExprSplice =>
281+
checkAlternativeBinds(pat)
269282
try ref(defn.QuotedRuntimePatterns_patternHole.termRef).appliedToType(tree.tpe).withSpan(tree.span)
270283
finally {
271284
val patType = pat.tpe.widen
@@ -321,7 +334,9 @@ trait QuotesAndSplices {
321334
}
322335

323336
private def transformTypeBindingTypeDef(nameOfSyntheticGiven: TermName, tdef: TypeDef, buff: mutable.Builder[Tree, List[Tree]])(using Context): Tree = {
324-
if (variance == -1)
337+
if ctx.mode.is(Mode.InPatternAlternative) then
338+
report.error(IllegalVariableInPatternAlternative(tdef.symbol.name), tdef.srcPos)
339+
if variance == -1 then
325340
tdef.symbol.addAnnotation(Annotation(New(ref(defn.QuotedRuntimePatterns_fromAboveAnnot.typeRef)).withSpan(tdef.span)))
326341
val bindingType = getBinding(tdef.symbol).symbol.typeRef
327342
val bindingTypeTpe = AppliedType(defn.QuotedTypeClass.typeRef, bindingType :: Nil)

tests/neg-macros/i14696.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scala.quoted.*
2+
3+
def test(a: Expr[Any])(using Quotes): Unit = a match
4+
case '{ ${_}: String } | '{ ${_}: Int } =>
5+
case '{ $x1: String } | '{ ${_}: Int } => // error
6+
case '{ $x: String } | '{ $x: Int } => // error // error
7+
case '{ $x1: String } | '{ ${x2: Expr[Int]} } => // error // error
8+
case '{ ${Str(x)}: String } | '{ ${y @ Str(z)}: Int } => // error // error // error
9+
case '{ val x: Int = ???; ${_}(x): String } | '{ '{ val x: String = ???; ${_}(x): String }} =>
10+
case '{ val x: Int = ???; $f(x): String } | '{ val x: String = ???; ${_}(x): String } => // error
11+
case '{ val x: Int = ???; $f(x): String } | '{ val x: String = ???; $f(x): String } => // error // error
12+
case '{ val x: Int = ???; $f(x): String } | '{ val x: String = ???; $g(x): String } => // error // error
13+
case '{ varargs(${_}*) } | '{ varargs(${_}*) } =>
14+
case '{ varargs($args*) } | '{ varargs(${_}*) } => // error
15+
case '{ varargs($args*) } | '{ varargs($args*) } => // error // error
16+
case '{ varargs($args1*) } | '{ varargs($args2*) } => // error // error
17+
case '{ ${_}: t } | '{ ${_}: Int } => // error
18+
case '{ ${_}: t } | '{ ${_}: t } => // error // error
19+
case '{ ${_}: t } | '{ ${_}: u } => // error // error
20+
case '{ type t; () } | '{ 1 } => // error
21+
case '{ type t; () } | '{ type t; () } => // error // error
22+
case '{ type t; () } | '{ type u; () } => // error // error
23+
24+
def varargs(x: Any*): Unit = ()
25+
26+
object Str:
27+
def unapply(x: Any): Option[String] = ???

0 commit comments

Comments
 (0)