@@ -31,7 +31,7 @@ object TypeTestsCasts {
3131 import typer .Inferencing .maximizeType
3232 import typer .ProtoTypes .constrained
3333
34- /** Whether `(x:X).isInstanceOf[P]` can be checked at runtime?
34+ /** Whether `(x: X).isInstanceOf[P]` can be checked at runtime?
3535 *
3636 * First do the following substitution:
3737 * (a) replace `T @unchecked` and pattern binder types (e.g., `_$1`) in P with WildcardType
@@ -48,7 +48,8 @@ object TypeTestsCasts {
4848 * (c) maximize `pre.F[Xs]` and check `pre.F[Xs] <:< P`
4949 * 6. if `P = T1 | T2` or `P = T1 & T2`, checkable(X, T1) && checkable(X, T2).
5050 * 7. if `P` is a refinement type, FALSE
51- * 8. otherwise, TRUE
51+ * 8. if `P` is a local class which is not statically reachable from the scope where `X` is defined, FALSE
52+ * 9. otherwise, TRUE
5253 */
5354 def checkable (X : Type , P : Type , span : Span )(using Context ): Boolean = atPhase(Phases .refchecksPhase.next) {
5455 // Run just before ElimOpaque transform (which follows RefChecks)
@@ -58,7 +59,7 @@ object TypeTestsCasts {
5859 def apply (tp : Type ) = tp match {
5960 case tref : TypeRef if tref.typeSymbol.isPatternBound =>
6061 WildcardType
61- case AnnotatedType (_, annot) if annot.symbol == defn.UncheckedAnnot =>
62+ case tp if tp.hasAnnotation( defn.UncheckedAnnot ) =>
6263 WildcardType
6364 case _ => mapOver(tp)
6465 }
@@ -123,11 +124,6 @@ object TypeTestsCasts {
123124
124125 }
125126
126- lazy val scrutineeIsUnchecked = X .widenTermRefExpr.existsPart {
127- case AnnotatedType (_, annot) if annot.symbol == defn.UncheckedAnnot => true
128- case _ => false
129- }
130-
131127 def recur (X : Type , P : Type ): Boolean = (X <:< P ) || (P .dealias match {
132128 case _ : SingletonType => true
133129 case _ : TypeProxy
@@ -157,26 +153,13 @@ object TypeTestsCasts {
157153 case AnnotatedType (t, _) => recur(X , t)
158154 case tp2 : RefinedType => recur(X , tp2.parent) && TypeComparer .hasMatchingMember(tp2.refinedName, X , tp2)
159155 case tp2 : RecType => recur(X , tp2.parent)
160- case tp2
161- if tp2.typeSymbol.isLocal && ! scrutineeIsUnchecked =>
162- val sym = tp2.typeSymbol
163- val methodSymbol = sym.owner
164- val tpSyms = typer.ErrorReporting .substitutableTypeSymbolsInScope(sym).toSet
165- def isAccessible (sym : Symbol ): Boolean = sym == methodSymbol || sym.isType && isAccessible(sym.owner)
166- val seen = scala.collection.mutable.Set .empty[Type ]
167- def hasPoison (tp : Type ): Boolean =
168- seen += tp
169- tp.baseClasses.filter(isAccessible).exists { sym =>
170- sym.info.decls.exists { sym =>
171- sym.info.existsPart(tp => tpSyms.contains(tp.typeSymbol))
172- || ! seen.contains(sym.info) && isAccessible(sym.info.typeSymbol.maybeOwner) && hasPoison(sym.info)
173- }
174- }
175- ! hasPoison(tp2)
156+ case _
157+ if P .classSymbol.isLocal && P .classSymbol.isInaccessibleChildOf(X .classSymbol) => // 8
158+ false
176159 case _ => true
177160 })
178161
179- val res = recur(X .widen, replaceP(P ))
162+ val res = X .widenTermRefExpr.hasAnnotation(defn. UncheckedAnnot ) || recur(X .widen, replaceP(P ))
180163
181164 debug.println(i " checking ${X .show} isInstanceOf ${P } = $res" )
182165
0 commit comments