diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 81a9d4db2e40..8984c87ec8de 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -862,7 +862,9 @@ class Definitions { @tu lazy val QuoteMatchingClass: ClassSymbol = requiredClass("scala.quoted.runtime.QuoteMatching") @tu lazy val QuoteMatching_ExprMatch: Symbol = QuoteMatchingClass.requiredMethod("ExprMatch") + @tu lazy val QuoteMatching_ExprMatchModule: Symbol = QuoteMatchingClass.requiredClass("ExprMatchModule") @tu lazy val QuoteMatching_TypeMatch: Symbol = QuoteMatchingClass.requiredMethod("TypeMatch") + @tu lazy val QuoteMatching_TypeMatchModule: Symbol = QuoteMatchingClass.requiredClass("TypeMatchModule") @tu lazy val ToExprModule: Symbol = requiredModule("scala.quoted.ToExpr") @tu lazy val ToExprModule_BooleanToExpr: Symbol = ToExprModule.requiredMethod("BooleanToExpr") diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index a338df37f358..a5da468f2508 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -322,6 +322,27 @@ object SpaceEngine { case funRef: TermRef => isIrrefutable(funRef, argLen) case _: ErrorType => false } + + /** Is this an `'{..}` or `'[..]` irrefutable quoted patterns? + * @param unapp The unapply function tree + * @param implicits The implicits of the unapply + * @param pt The scrutinee type + */ + def isIrrefutableQuotedPattern(unapp: tpd.Tree, implicits: List[tpd.Tree], pt: Type)(using Context): Boolean = { + implicits.headOption match + // pattern '{ $x: T } + case Some(tpd.Apply(tpd.Select(tpd.Quoted(tpd.TypeApply(fn, List(tpt))), nme.apply), _)) + if unapp.symbol.owner.eq(defn.QuoteMatching_ExprMatchModule) + && fn.symbol.eq(defn.QuotedRuntimePatterns_patternHole) => + pt <:< defn.QuotedExprClass.typeRef.appliedTo(tpt.tpe) + + // pattern '[T] + case Some(tpd.Apply(tpd.TypeApply(fn, List(tpt)), _)) + if unapp.symbol.owner.eq(defn.QuoteMatching_TypeMatchModule) => + pt =:= defn.QuotedTypeClass.typeRef.appliedTo(tpt.tpe) + + case _ => false + } } /** Scala implementation of space logic */ diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 85ee76b8830e..c8ba119131ee 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -33,7 +33,7 @@ import NameOps._ import SymDenotations.{NoCompleter, NoDenotation} import Applications.unapplyArgs import Inferencing.isFullyDefined -import transform.patmat.SpaceEngine.isIrrefutable +import transform.patmat.SpaceEngine.{isIrrefutable, isIrrefutableQuotedPattern} import config.Feature import config.Feature.sourceVersion import config.SourceVersion._ @@ -888,9 +888,9 @@ trait Checking { pat match case Bind(_, pat1) => recur(pat1, pt) - case UnApply(fn, _, pats) => + case UnApply(fn, implicits, pats) => check(pat, pt) && - (isIrrefutable(fn, pats.length) || fail(pat, pt, Reason.RefutableExtractor)) && { + (isIrrefutable(fn, pats.length) || isIrrefutableQuotedPattern(fn, implicits, pt) || fail(pat, pt, Reason.RefutableExtractor)) && { val argPts = unapplyArgs(fn.tpe.widen.finalResultType, fn, pats, pat.srcPos) pats.corresponds(argPts)(recur) } diff --git a/tests/pos-special/fatal-warnings/i16649-irrefutable.scala b/tests/pos-special/fatal-warnings/i16649-irrefutable.scala new file mode 100644 index 000000000000..b9aa6d2acf52 --- /dev/null +++ b/tests/pos-special/fatal-warnings/i16649-irrefutable.scala @@ -0,0 +1,7 @@ +import quoted.* + +def foo(using Quotes)(x: Expr[Int]) = + val '{ $y } = x + val '{ $a: Any } = x + val '{ $b: Int } = x + val '[List[Int]] = Type.of[List[Int]]