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