Skip to content

Commit 6f046c4

Browse files
committed
Detect irrefutable quoted patterns
Fixes #16649
1 parent d8b98a0 commit 6f046c4

File tree

4 files changed

+33
-3
lines changed

4 files changed

+33
-3
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,9 @@ class Definitions {
862862

863863
@tu lazy val QuoteMatchingClass: ClassSymbol = requiredClass("scala.quoted.runtime.QuoteMatching")
864864
@tu lazy val QuoteMatching_ExprMatch: Symbol = QuoteMatchingClass.requiredMethod("ExprMatch")
865+
@tu lazy val QuoteMatching_ExprMatchModule: Symbol = QuoteMatchingClass.requiredClass("ExprMatchModule")
865866
@tu lazy val QuoteMatching_TypeMatch: Symbol = QuoteMatchingClass.requiredMethod("TypeMatch")
867+
@tu lazy val QuoteMatching_TypeMatchModule: Symbol = QuoteMatchingClass.requiredClass("TypeMatchModule")
866868

867869
@tu lazy val ToExprModule: Symbol = requiredModule("scala.quoted.ToExpr")
868870
@tu lazy val ToExprModule_BooleanToExpr: Symbol = ToExprModule.requiredMethod("BooleanToExpr")

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,27 @@ object SpaceEngine {
322322
case funRef: TermRef => isIrrefutable(funRef, argLen)
323323
case _: ErrorType => false
324324
}
325+
326+
/** Is this an `'{..}` or `'[..]` irrefutable quoted patterns?
327+
* @param unapp The unapply function tree
328+
* @param implicits The implicits of the unapply
329+
* @param pt The scrutinee type
330+
*/
331+
def isIrrefutableQuotedPattern(unapp: tpd.Tree, implicits: List[tpd.Tree], pt: Type)(using Context): Boolean = {
332+
implicits.headOption match
333+
// pattern '{ $x: T }
334+
case Some(tpd.Apply(tpd.Select(tpd.Quoted(tpd.TypeApply(fn, List(tpt))), nme.apply), _))
335+
if unapp.symbol.owner.eq(defn.QuoteMatching_ExprMatchModule)
336+
&& fn.symbol.eq(defn.QuotedRuntimePatterns_patternHole) =>
337+
pt <:< defn.QuotedExprClass.typeRef.appliedTo(tpt.tpe)
338+
339+
// pattern '[T]
340+
case Some(tpd.Apply(tpd.TypeApply(fn, List(tpt)), _))
341+
if unapp.symbol.owner.eq(defn.QuoteMatching_TypeMatchModule) =>
342+
pt =:= defn.QuotedTypeClass.typeRef.appliedTo(tpt.tpe)
343+
344+
case _ => false
345+
}
325346
}
326347

327348
/** Scala implementation of space logic */

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import NameOps._
3333
import SymDenotations.{NoCompleter, NoDenotation}
3434
import Applications.unapplyArgs
3535
import Inferencing.isFullyDefined
36-
import transform.patmat.SpaceEngine.isIrrefutable
36+
import transform.patmat.SpaceEngine.{isIrrefutable, isIrrefutableQuotedPattern}
3737
import config.Feature
3838
import config.Feature.sourceVersion
3939
import config.SourceVersion._
@@ -888,9 +888,9 @@ trait Checking {
888888
pat match
889889
case Bind(_, pat1) =>
890890
recur(pat1, pt)
891-
case UnApply(fn, _, pats) =>
891+
case UnApply(fn, implicits, pats) =>
892892
check(pat, pt) &&
893-
(isIrrefutable(fn, pats.length) || fail(pat, pt, Reason.RefutableExtractor)) && {
893+
(isIrrefutable(fn, pats.length) || isIrrefutableQuotedPattern(fn, implicits, pt) || fail(pat, pt, Reason.RefutableExtractor)) && {
894894
val argPts = unapplyArgs(fn.tpe.widen.finalResultType, fn, pats, pat.srcPos)
895895
pats.corresponds(argPts)(recur)
896896
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import quoted.*
2+
3+
def foo(using Quotes)(x: Expr[Int]) =
4+
val '{ $y } = x
5+
val '{ $a: Any } = x
6+
val '{ $b: Int } = x
7+
val '[List[Int]] = Type.of[List[Int]]

0 commit comments

Comments
 (0)