@@ -11,6 +11,7 @@ import util.Spans._
1111import typer .Applications .*
1212import SymUtils ._
1313import TypeUtils .*
14+ import Annotations .*
1415import Flags ._ , Constants ._
1516import Decorators ._
1617import NameKinds .{PatMatStdBinderName , PatMatAltsName , PatMatResultName }
@@ -707,9 +708,9 @@ object PatternMatcher {
707708 // ----- Generating trees from plans ---------------
708709
709710 /** The condition a test plan rewrites to */
710- private def emitCondition (plan : TestPlan ): Tree = {
711+ private def emitCondition (plan : TestPlan ): Tree =
711712 val scrutinee = plan.scrutinee
712- (plan.test: @ unchecked) match {
713+ (plan.test: @ unchecked) match
713714 case NonEmptyTest =>
714715 constToLiteral(
715716 scrutinee
@@ -737,41 +738,49 @@ object PatternMatcher {
737738 case TypeTest (tpt, trusted) =>
738739 val expectedTp = tpt.tpe
739740
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
754745
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
764777
765- expectedTp.dealias match {
778+ expectedTp.dealias match
766779 case expectedTp : SingletonType =>
767780 scrutinee.isInstance(expectedTp) // will be translated to an equality test
768781 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
775784
776785 @ tailrec
777786 private def canFallThrough (plan : Plan ): Boolean = plan match {
0 commit comments