@@ -246,7 +246,7 @@ object PatternMatcher {
246246 }
247247
248248 /** Plan for matching `scrutinee` symbol against `tree` pattern */
249- private def patternPlan (scrutinee : Symbol , tree : Tree , onSuccess : Plan , isDefinitelyCatchAll : Boolean ): Plan = {
249+ private def patternPlan (scrutinee : Symbol , tree : Tree , onSuccess : Plan , isDefinitelyCatchAll : Boolean , selectorType : Type ): Plan = {
250250
251251 extension (tree : Tree ) def avoidPatBoundType (): Type =
252252 tree.tpe.widen match
@@ -289,7 +289,7 @@ object PatternMatcher {
289289 ResultPlan (tpd.Throw (tpd.nullLiteral.cast(defn.ThrowableType )))
290290 else
291291 val sym :: syms1 = syms : @ unchecked
292- patternPlan(sym, arg, matchArgsPatternPlan(args1, syms1), isDefinitelyCatchAll)
292+ patternPlan(sym, arg, matchArgsPatternPlan(args1, syms1), isDefinitelyCatchAll, selectorType )
293293 case Nil =>
294294 assert(syms.isEmpty)
295295 onSuccess
@@ -343,7 +343,7 @@ object PatternMatcher {
343343 val matchRemaining =
344344 letAbstract(remaining): remainingResult =>
345345 if trailing.isEmpty then
346- patternPlan(remainingResult, arg, onSuccess, isDefinitelyCatchAll)
346+ patternPlan(remainingResult, arg, onSuccess, isDefinitelyCatchAll, selectorType )
347347 else
348348 val seq = ref(remainingResult)
349349 .select(defn.Seq_dropRight .matchingMember(remainingResult.info))
@@ -355,7 +355,7 @@ object PatternMatcher {
355355 val matchTrailing =
356356 letAbstract(rest): trailingResult =>
357357 matchElemsPlan(trailingResult, trailing, noLengthTest, onSuccess)
358- patternPlan(seqResult, arg, matchTrailing, isDefinitelyCatchAll)
358+ patternPlan(seqResult, arg, matchTrailing, isDefinitelyCatchAll, selectorType )
359359 matchElemsPlan(getResult, leading,
360360 LengthTest (leading.length + trailing.length, exact = false ),
361361 matchRemaining)
@@ -485,10 +485,17 @@ object PatternMatcher {
485485 else tpt.tpe
486486 val body = letAbstract(ref(scrutinee).cast(castTp)) { casted =>
487487 nonNull += casted
488- patternPlan(casted, pat, onSuccess, isDefinitelyCatchAll)
488+ patternPlan(casted, pat, onSuccess, isDefinitelyCatchAll, selectorType )
489489 }
490- if isDefinitelyCatchAll then body
491- else TestPlan (TypeTest (tpt, isTrusted(pat)), scrutinee, tree.span, body)
490+ val patIsTrusted = isTrusted(pat)
491+ if isDefinitelyCatchAll then
492+ // Because we're not inserting a type test, we need to explicitly check for unchecked type conversions
493+ // e.g., `(x: List[Int] | List[String]) match { case l: List[Int] => ??? }` should warn,
494+ // even if it is a catch-all after erasure.
495+ TypeTestsCasts .checkTypePattern(selectorType, castTp, tree.srcPos, patIsTrusted)
496+ body
497+ else
498+ TestPlan (TypeTest (tpt, patIsTrusted), scrutinee, tree.span, body)
492499 case UnApply (extractor, implicits, args) =>
493500 val unappPlan = if (scrutinee.info.isBottomType)
494501 // Generate a throwaway but type-correct plan.
@@ -513,19 +520,19 @@ object PatternMatcher {
513520 if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan
514521 else TestPlan (NonNullTest , scrutinee, tree.span, unappPlan)
515522 case Bind (name, body) =>
516- if (name == nme.WILDCARD ) patternPlan(scrutinee, body, onSuccess, isDefinitelyCatchAll)
523+ if (name == nme.WILDCARD ) patternPlan(scrutinee, body, onSuccess, isDefinitelyCatchAll, selectorType )
517524 else {
518525 // The type of `name` may refer to val in `body`, therefore should come after `body`
519526 val bound = tree.symbol.asTerm
520527 initializer(bound) = ref(scrutinee)
521- patternPlan(scrutinee, body, LetPlan (bound, onSuccess), isDefinitelyCatchAll)
528+ patternPlan(scrutinee, body, LetPlan (bound, onSuccess), isDefinitelyCatchAll, selectorType )
522529 }
523530 case Alternative (alts) =>
524531 altsLabeledAbstract { onf =>
525532 SeqPlan (
526533 altsLabeledAbstract { ons =>
527534 alts.foldRight(onf) { (alt, next) =>
528- SeqPlan (patternPlan(scrutinee, alt, ons, isDefinitelyCatchAll), next)
535+ SeqPlan (patternPlan(scrutinee, alt, ons, isDefinitelyCatchAll, selectorType ), next)
529536 }
530537 },
531538 onSuccess
@@ -542,34 +549,35 @@ object PatternMatcher {
542549 case SeqLiteral (pats, _) =>
543550 matchElemsPlan(scrutinee, pats, LengthTest (pats.length, exact = true ), onSuccess)
544551 case _ =>
545- TestPlan (EqualTest (tree), scrutinee, tree.span, onSuccess)
552+ if isDefinitelyCatchAll then onSuccess
553+ else TestPlan (EqualTest (tree), scrutinee, tree.span, onSuccess)
546554 }
547555 }
548556
549- private def caseDefPlan (scrutinee : Symbol , cdef : CaseDef , isDefinitelyCatchAll : Boolean ): Plan =
557+ private def caseDefPlan (scrutinee : Symbol , cdef : CaseDef , isDefinitelyCatchAll : Boolean , selectorType : Type ): Plan =
550558 val CaseDef (pat, guard, body) = cdef
551559 val caseDefBodyPlan : Plan = body match
552560 case t : SubMatch => subMatchPlan(t)
553561 case _ => ResultPlan (body)
554562 val onSuccess : Plan =
555563 if guard.isEmpty then caseDefBodyPlan
556564 else TestPlan (GuardTest , guard, guard.span, caseDefBodyPlan)
557- patternPlan(scrutinee, pat, onSuccess, isDefinitelyCatchAll)
565+ patternPlan(scrutinee, pat, onSuccess, isDefinitelyCatchAll, selectorType )
558566 end caseDefPlan
559567
560568 // like matchPlan but without a final matchError ResultPlan at the end of SeqPlans
561569 // s.t. we fall back to the outer SeqPlan
562570 private def subMatchPlan (tree : SubMatch ): Plan =
563571 letAbstract(tree.selector) { scrutinee =>
564- tree.cases.map(caseDefPlan(scrutinee, _, false )).reduceRight(SeqPlan (_, _))
572+ tree.cases.map(caseDefPlan(scrutinee, _, false , tree.selector.tpe )).reduceRight(SeqPlan (_, _))
565573 }
566574
567575 private def matchPlan (tree : Match , isExhaustive : Boolean ): Plan =
568576 letAbstract(tree.selector) { scrutinee =>
569577 val matchError : Plan = ResultPlan (Throw (New (defn.MatchErrorClass .typeRef, ref(scrutinee) :: Nil )))
570578 var isCatchAll = isExhaustive
571579 tree.cases.foldRight(matchError) { (cdef, next) =>
572- val casePlan = SeqPlan (caseDefPlan(scrutinee, cdef, isCatchAll), next)
580+ val casePlan = SeqPlan (caseDefPlan(scrutinee, cdef, isCatchAll, tree.selector.tpe ), next)
573581 isCatchAll = false
574582 casePlan
575583 }
0 commit comments