@@ -11,6 +11,7 @@ import util.Spans._
11
11
import typer .Applications .*
12
12
import SymUtils ._
13
13
import TypeUtils .*
14
+ import Annotations .*
14
15
import Flags ._ , Constants ._
15
16
import Decorators ._
16
17
import NameKinds .{PatMatStdBinderName , PatMatAltsName , PatMatResultName }
@@ -707,9 +708,9 @@ object PatternMatcher {
707
708
// ----- Generating trees from plans ---------------
708
709
709
710
/** The condition a test plan rewrites to */
710
- private def emitCondition (plan : TestPlan ): Tree = {
711
+ private def emitCondition (plan : TestPlan ): Tree =
711
712
val scrutinee = plan.scrutinee
712
- (plan.test: @ unchecked) match {
713
+ (plan.test: @ unchecked) match
713
714
case NonEmptyTest =>
714
715
constToLiteral(
715
716
scrutinee
@@ -737,41 +738,49 @@ object PatternMatcher {
737
738
case TypeTest (tpt, trusted) =>
738
739
val expectedTp = tpt.tpe
739
740
740
- // An outer test is needed in a situation like `case x: y.Inner => ...`
741
- def outerTestNeeded : Boolean = {
742
- def go (expected : Type ): Boolean = expected match {
743
- case tref @ TypeRef (pre : SingletonType , _) =>
744
- tref.symbol.isClass &&
745
- ExplicitOuter .needsOuterIfReferenced(tref.symbol.asClass)
746
- case AppliedType (tpe, _) => go(tpe)
747
- case _ =>
748
- false
749
- }
750
- // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest`
751
- // generates an outer test based on `patType.prefix` with automatically dealises.
752
- go(expectedTp.dealias)
753
- }
741
+ def typeTest (scrut : Tree , expected : Type ): Tree =
742
+ val ttest = scrut.select(defn.Any_typeTest ).appliedToType(expected)
743
+ if trusted then ttest.pushAttachment(TrustedTypeTestKey , ())
744
+ ttest
754
745
755
- def outerTest : Tree = thisPhase.transformFollowingDeep {
756
- val expectedOuter = singleton(expectedTp.normalizedPrefix)
757
- val expectedClass = expectedTp.dealias.classSymbol.asClass
758
- ExplicitOuter .ensureOuterAccessors(expectedClass)
759
- scrutinee.ensureConforms(expectedTp)
760
- .outerSelect(1 , expectedClass.owner.typeRef)
761
- .select(defn.Object_eq )
762
- .appliedTo(expectedOuter)
763
- }
746
+ /** An outer test is needed in a situation like `case x: y.Inner => ...
747
+ * or like case x: O#Inner if the owner of Inner is not a subclass of O.
748
+ * Outer tests are added here instead of in TypeTestsCasts since they
749
+ * might cause outer accessors to be added to inner classes (via ensureOuterAccessors)
750
+ * and therefore have to run before ExplicitOuter.
751
+ */
752
+ def addOuterTest (tree : Tree , expected : Type ): Tree = expected.dealias match
753
+ case tref @ TypeRef (pre, _) =>
754
+ tref.symbol match
755
+ case expectedCls : ClassSymbol if ExplicitOuter .needsOuterIfReferenced(expectedCls) =>
756
+ def selectOuter =
757
+ ExplicitOuter .ensureOuterAccessors(expectedCls)
758
+ scrutinee.ensureConforms(expected).outerSelect(1 , expectedCls.owner.typeRef)
759
+ if pre.isSingleton then
760
+ val expectedOuter = singleton(pre)
761
+ tree.and(selectOuter.select(defn.Object_eq ).appliedTo(expectedOuter))
762
+ else if ! expectedCls.isStatic
763
+ && expectedCls.owner.isType
764
+ && ! expectedCls.owner.derivesFrom(pre.classSymbol)
765
+ then
766
+ val testPre =
767
+ if expected.hasAnnotation(defn.UncheckedAnnot ) then
768
+ AnnotatedType (pre, Annotation (defn.UncheckedAnnot , tree.span))
769
+ else pre
770
+ tree.and(typeTest(selectOuter, testPre))
771
+ else tree
772
+ case _ => tree
773
+ case AppliedType (tycon, _) =>
774
+ addOuterTest(tree, tycon)
775
+ case _ =>
776
+ tree
764
777
765
- expectedTp.dealias match {
778
+ expectedTp.dealias match
766
779
case expectedTp : SingletonType =>
767
780
scrutinee.isInstance(expectedTp) // will be translated to an equality test
768
781
case _ =>
769
- val typeTest = scrutinee.select(defn.Any_typeTest ).appliedToType(expectedTp)
770
- if (trusted) typeTest.pushAttachment(TrustedTypeTestKey , ())
771
- if (outerTestNeeded) typeTest.and(outerTest) else typeTest
772
- }
773
- }
774
- }
782
+ addOuterTest(typeTest(scrutinee, expectedTp), expectedTp)
783
+ end emitCondition
775
784
776
785
@ tailrec
777
786
private def canFallThrough (plan : Plan ): Boolean = plan match {
0 commit comments