@@ -25,6 +25,7 @@ import Decorators._
25
25
import ErrorReporting .{err , errorType }
26
26
import config .Printers .typr
27
27
import NameKinds .DefaultGetterName
28
+ import Applications .unapplyArgs
28
29
29
30
import collection .mutable
30
31
import SymDenotations .{NoCompleter , NoDenotation }
@@ -596,23 +597,46 @@ trait Checking {
596
597
ctx.error(ex " $cls cannot be instantiated since it ${rstatus.msg}" , pos)
597
598
}
598
599
599
- /** Check that pattern definition is either marked @unchecked or has a right
600
- * hand side with a type that conforms to the pattern's type.
600
+ /** Check that pattern `pat` is irrefutable for scrutinee tye `pt`.
601
+ * This means `pat` is either marked @unchecked or `pt` conforms to the
602
+ * pattern's type. If pattern is an UnApply, do the check recursively.
601
603
*/
602
- def checkPatDefMatch (tree : Tree , pt : Type )(implicit ctx : Context ): Unit = tree match {
603
- case Match (_, CaseDef (pat, _, _) :: _)
604
- if ! pat.tpe.widen.hasAnnotation(defn.UncheckedAnnot ) && ! (pt <:< pat.tpe) =>
605
- val pt1 = pt match {
606
- case AnnotatedType (pt1, annot) if annot.matches(defn.UncheckedAnnot ) => pt1
607
- case _ => pt
604
+ def checkIrrefutable (pat : Tree , pt : Type )(implicit ctx : Context ): Boolean = {
605
+ patmatch.println(i " check irrefutable $pat: ${pat.tpe} against $pt" )
606
+
607
+ def check (pat : Tree , pt : Type ): Boolean = {
608
+ if (pt <:< pat.tpe)
609
+ true
610
+ else {
611
+ ctx.errorOrMigrationWarning(
612
+ ex """ pattern's type ${pat.tpe} is more specialized than the right hand side expression's type ${pt.dropAnnot(defn.UncheckedAnnot )}
613
+ |
614
+ |If the narrowing is intentional, this can be communicated by writing `: @unchecked` after the full pattern. ${err.rewriteNotice}""" ,
615
+ pat.sourcePos)
616
+ false
617
+ }
618
+ }
619
+
620
+ ! ctx.settings.strict.value || // only in -strict mode for now since mitigations work only after this PR
621
+ pat.tpe.widen.hasAnnotation(defn.UncheckedAnnot ) || {
622
+ pat match {
623
+ case Bind (_, pat1) =>
624
+ checkIrrefutable(pat1, pt)
625
+ case UnApply (fn, _, pats) =>
626
+ check(pat, pt) && {
627
+ val argPts = unapplyArgs(fn.tpe.finalResultType, fn, pats, pat.sourcePos)
628
+ pats.corresponds(argPts)(checkIrrefutable)
629
+ }
630
+ case Alternative (pats) =>
631
+ pats.forall(checkIrrefutable(_, pt))
632
+ case Typed (arg, tpt) =>
633
+ check(pat, pt) && checkIrrefutable(arg, pt)
634
+ case Ident (nme.WILDCARD ) =>
635
+ true
636
+ case _ =>
637
+ check(pat, pt)
608
638
}
609
- ctx.errorOrMigrationWarning(
610
- ex """ pattern's type ${pat.tpe.widen} is more specialized than the right hand side expression's type $pt1
611
- |
612
- |If the narrowing is intentional, this can be communicated by writing `: @unchecked` after the pattern. ${err.rewriteNotice}""" ,
613
- pat.sourcePos)
614
- if (ctx.scala2Mode) patch(Span (pat.span.end), " : @unchecked" )
615
- case _ =>
639
+ }
616
640
}
617
641
618
642
/** Check that `path` is a legal prefix for an import or export clause */
0 commit comments