Skip to content

Commit 1910479

Browse files
committed
Fix quote pattern irrefutability checks
1 parent ed21e27 commit 1910479

File tree

3 files changed

+22
-31
lines changed

3 files changed

+22
-31
lines changed

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

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -305,23 +305,13 @@ object SpaceEngine {
305305
}
306306

307307
/** Is this an `'{..}` or `'[..]` irrefutable quoted patterns?
308-
* @param unapp The unapply function tree
309-
* @param implicits The implicits of the unapply
310-
* @param pt The scrutinee type
308+
* @param body The body of the quoted pattern
309+
* @param bodyPt The scrutinee body type
311310
*/
312-
def isIrrefutableQuotedPattern(unapp: tpd.Tree, implicits: List[tpd.Tree], pt: Type)(using Context): Boolean = {
313-
implicits.headOption match
314-
// pattern '{ $x: T }
315-
case Some(tpd.Apply(tpd.Select(tpd.Quote(tpd.TypeApply(fn, List(tpt)), _), nme.apply), _))
316-
if unapp.symbol.owner.eq(defn.QuoteMatching_ExprMatchModule)
317-
&& fn.symbol.eq(defn.QuotedRuntimePatterns_patternHole) =>
318-
pt <:< defn.QuotedExprClass.typeRef.appliedTo(tpt.tpe)
319-
320-
// pattern '[T]
321-
case Some(tpd.Apply(tpd.TypeApply(fn, List(tpt)), _))
322-
if unapp.symbol.owner.eq(defn.QuoteMatching_TypeMatchModule) =>
323-
pt =:= defn.QuotedTypeClass.typeRef.appliedTo(tpt.tpe)
324-
311+
def isIrrefutableQuotePattern(pat: tpd.QuotePattern, pt: Type)(using Context): Boolean = {
312+
if pat.body.isType then pat.bindings.isEmpty && pt =:= pat.tpe
313+
else pat.body match
314+
case _: SplicePattern => pat.bindings.isEmpty && pt <:< pat.tpe
325315
case _ => false
326316
}
327317

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

Lines changed: 13 additions & 15 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, isIrrefutableQuotedPattern}
36+
import transform.patmat.SpaceEngine.{isIrrefutable, isIrrefutableQuotePattern}
3737
import config.Feature
3838
import config.Feature.sourceVersion
3939
import config.SourceVersion._
@@ -846,19 +846,15 @@ trait Checking {
846846
val problem = if pat.tpe <:< reportedPt then "is more specialized than" else "does not match"
847847
em"pattern's type ${pat.tpe} $problem the right hand side expression's type $reportedPt"
848848
case RefutableExtractor =>
849-
val extractor =
850-
val UnApply(fn, _, _) = pat: @unchecked
851-
tpd.funPart(fn) match
852-
case Select(id, _) => id
853-
case _ => EmptyTree
854-
if extractor.isEmpty then
855-
em"pattern binding uses refutable extractor"
856-
else if extractor.symbol eq defn.QuoteMatching_ExprMatch then
857-
em"pattern binding uses refutable extractor `'{...}`"
858-
else if extractor.symbol eq defn.QuoteMatching_TypeMatch then
859-
em"pattern binding uses refutable extractor `'[...]`"
860-
else
861-
em"pattern binding uses refutable extractor `$extractor`"
849+
val extractor = pat match
850+
case UnApply(fn, _, _) =>
851+
tpd.funPart(fn) match
852+
case Select(id, _) if !id.isEmpty => id.show
853+
case _ => ""
854+
case QuotePattern(_, body, _) =>
855+
if body.isTerm then "'{...}" else "'[...]"
856+
if extractor.isEmpty then em"pattern binding uses refutable extractor"
857+
else em"pattern binding uses refutable extractor `$extractor`"
862858

863859
val fix =
864860
if isPatDef then "adding `: @unchecked` after the expression"
@@ -897,7 +893,7 @@ trait Checking {
897893
recur(pat1, pt)
898894
case UnApply(fn, implicits, pats) =>
899895
check(pat, pt) &&
900-
(isIrrefutable(fn, pats.length) || isIrrefutableQuotedPattern(fn, implicits, pt) || fail(pat, pt, Reason.RefutableExtractor)) && {
896+
(isIrrefutable(fn, pats.length) || fail(pat, pt, Reason.RefutableExtractor)) && {
901897
val argPts = unapplyArgs(fn.tpe.widen.finalResultType, fn, pats, pat.srcPos)
902898
pats.corresponds(argPts)(recur)
903899
}
@@ -907,6 +903,8 @@ trait Checking {
907903
check(pat, pt) && recur(arg, pt)
908904
case Ident(nme.WILDCARD) =>
909905
true
906+
case pat: QuotePattern =>
907+
isIrrefutableQuotePattern(pat, pt) || fail(pat, pt, Reason.RefutableExtractor)
910908
case _ =>
911909
check(pat, pt)
912910
}

tests/neg-custom-args/fatal-warnings/i16649-refutable.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ import quoted.*
22

33
def foo(using Quotes)(x: Expr[Int]) =
44
val '{ ($y: Int) + ($z: Int) } = x // error
5+
val '{ $a: Int } = x
6+
val '{ $b: Any } = x
7+
val '{ $c } = x

0 commit comments

Comments
 (0)