Skip to content

Commit b67e269

Browse files
Fix #17435: A simpler fix (#17436)
Fix #17435: A simpler fix for #17382
2 parents 14b7aa7 + 4aa062b commit b67e269

File tree

2 files changed

+31
-55
lines changed

2 files changed

+31
-55
lines changed

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ object TypeTestsCasts {
5353
* 6. if `P = T1 | T2` or `P = T1 & T2`, checkable(X, T1) && checkable(X, T2).
5454
* 7. if `P` is a refinement type, "it's a refinement type"
5555
* 8. if `P` is a local class which is not statically reachable from the scope where `X` is defined, "it's a local class"
56-
* 9. if `X` is `T1 | T2`, checkable(T1, P) && checkable(T2, P) or (isCheckDefinitelyFalse(T1, P) && checkable(T2, P)) or (checkable(T1, P) && isCheckDefinitelyFalse(T2, P)).
56+
* 9. if `X` is `T1 | T2`, checkable(T1, P) && checkable(T2, P).
5757
* 10. otherwise, ""
5858
*/
5959
def whyUncheckable(X: Type, P: Type, span: Span)(using Context): String = atPhase(Phases.refchecksPhase.next) {
@@ -132,42 +132,8 @@ object TypeTestsCasts {
132132

133133
}
134134

135-
/** Whether the check X.isInstanceOf[P] is definitely false? */
136-
def isCheckDefinitelyFalse(X: Type, P: Type)(using Context): Boolean = trace(s"isCheckDefinitelyFalse(${X.show}, ${P.show})") {
137-
X.widenDealias match
138-
case AndType(x1, x2) =>
139-
isCheckDefinitelyFalse(x1, P) || isCheckDefinitelyFalse(x2, P)
140-
141-
case x =>
142-
P.widenDealias match
143-
case AndType(p1, p2) =>
144-
isCheckDefinitelyFalse(x, p1) || isCheckDefinitelyFalse(x, p2)
145-
146-
case p =>
147-
val pSpace = Typ(p)
148-
val xSpace = Typ(x)
149-
if pSpace.canDecompose then
150-
val ps = pSpace.decompose.map(_.tp)
151-
ps.forall(p => isCheckDefinitelyFalse(x, p))
152-
else if xSpace.canDecompose then
153-
val xs = xSpace.decompose.map(_.tp)
154-
xs.forall(x => isCheckDefinitelyFalse(x, p))
155-
else
156-
if x.typeSymbol.isClass && p.typeSymbol.isClass then
157-
val xClass = effectiveClass(x)
158-
val pClass = effectiveClass(p)
159-
160-
val bothAreClasses = !xClass.is(Trait) && !pClass.is(Trait)
161-
val notXsubP = !xClass.derivesFrom(pClass)
162-
val notPsubX = !pClass.derivesFrom(xClass)
163-
bothAreClasses && notXsubP && notPsubX
164-
|| xClass.is(Final) && notXsubP
165-
|| pClass.is(Final) && notPsubX
166-
else
167-
false
168-
}
169-
170-
def recur(X: Type, P: Type): String = (X <:< P) ||| (P.dealias match {
135+
def recur(X: Type, P: Type): String = trace(s"recur(${X.show}, ${P.show})") {
136+
(X <:< P) ||| P.dealias.match
171137
case _: SingletonType => ""
172138
case _: TypeProxy
173139
if isAbstract(P) => i"it refers to an abstract type member or type parameter"
@@ -176,32 +142,19 @@ object TypeTestsCasts {
176142
case defn.ArrayOf(tpE) => recur(tpE, tpT)
177143
case _ => recur(defn.AnyType, tpT)
178144
}
179-
case tpe: AppliedType =>
145+
case tpe @ AppliedType(tycon, targs) =>
180146
X.widenDealias match {
181147
case OrType(tp1, tp2) =>
182148
// This case is required to retrofit type inference,
183149
// which cut constraints in the following two cases:
184150
// - T1 <:< T2 | T3
185151
// - T1 & T2 <:< T3
186152
// See TypeComparer#either
187-
val res1 = recur(tp1, P)
188-
val res2 = recur(tp2, P)
189-
190-
if res1.isEmpty && res2.isEmpty then
191-
res1
192-
else if res2.isEmpty then
193-
if isCheckDefinitelyFalse(tp1, P) then res2
194-
else res1
195-
else if res1.isEmpty then
196-
if isCheckDefinitelyFalse(tp2, P) then res1
197-
else res2
198-
else
199-
res1
153+
recur(tp1, P) && recur(tp2, P)
200154

201-
case _ =>
155+
case x =>
202156
// always false test warnings are emitted elsewhere
203-
X.classSymbol.exists && P.classSymbol.exists &&
204-
!X.classSymbol.asClass.mayHaveCommonChild(P.classSymbol.asClass)
157+
TypeComparer.provablyDisjoint(x, tpe.derivedAppliedType(tycon, targs.map(_ => WildcardType)))
205158
|| typeArgsTrivial(X, tpe)
206159
||| i"its type arguments can't be determined from $X"
207160
}
@@ -215,7 +168,7 @@ object TypeTestsCasts {
215168
if P.classSymbol.isLocal && foundClasses(X).exists(P.classSymbol.isInaccessibleChildOf) => // 8
216169
i"it's a local class"
217170
case _ => ""
218-
})
171+
}
219172

220173
val res = recur(X.widen, replaceP(P))
221174

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import scala.collection.mutable
2+
3+
object Test:
4+
type JsonPrimitive = String | Int | Double | Boolean | None.type
5+
6+
type Rec[JA[_], JO[_], A] = A match
7+
case JsonPrimitive => JsonPrimitive | JA[Rec[JA, JO, JsonPrimitive]] | JO[Rec[JA, JO, JsonPrimitive]]
8+
case _ => A | JA[Rec[JA, JO, A]] | JO[Rec[JA, JO, A]]
9+
10+
type Json = Rec[[A] =>> mutable.Buffer[A], [A] =>> mutable.Map[String, A], JsonPrimitive]
11+
12+
type JsonObject = mutable.Map[String, Json]
13+
14+
type JsonArray = mutable.Buffer[Json]
15+
16+
def encode(x: Json): Int = x match
17+
case str: String => 1
18+
case b: Boolean => 2
19+
case i: Int => 3
20+
case d: Double => 4
21+
case arr: JsonArray => 5 // error
22+
case obj: JsonObject => 6 // error
23+
case _ => 7

0 commit comments

Comments
 (0)