@@ -1616,7 +1616,16 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
16161616
16171617 type Const <: AbsConst
16181618 trait AbsConst {
1619+ // when we know V = C, which other equalities must hold
1620+ // in general, equality to some type implies equality to its supertypes
1621+ // (this multi-valued kind of equality is necessary for unreachability)
1622+ // note that we use subtyping as a model for implication between instanceof tests
1623+ // i.e., when S <:< T we assume x.isInstanceOf[S] implies x.isInstanceOf[T]
1624+ // unfortunately this is not true in general (see e.g. SI-6022)
16191625 def implies (other : Const ): Boolean
1626+
1627+ // does V = C preclude V having value `other`? V = null is an exclusive assignment,
1628+ // but V = 1 does not preclude V = Int, or V = Any
16201629 def excludes (other : Const ): Boolean
16211630 }
16221631
@@ -2164,11 +2173,30 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
21642173
21652174 def isAny = wideTp.typeSymbol == AnyClass
21662175
2176+ // we use subtyping as a model for implication between instanceof tests
2177+ // i.e., when S <:< T we assume x.isInstanceOf[S] implies x.isInstanceOf[T]
2178+ // unfortunately this is not true in general:
2179+ // SI-6022 expects instanceOfTpImplies(ProductClass.tpe, AnyRefClass.tpe)
2180+ private def instanceOfTpImplies (tp : Type , tpImplied : Type ) = {
2181+ val tpValue = tp.typeSymbol.isPrimitiveValueClass
2182+
2183+ // pretend we're comparing to Any when we're actually comparing to AnyVal or AnyRef
2184+ // (and the subtype is respectively a value type or not a value type)
2185+ // this allows us to reuse subtyping as a model for implication between instanceOf tests
2186+ // the latter don't see a difference between AnyRef, Object or Any when comparing non-value types -- SI-6022
2187+ val tpImpliedNormalizedToAny =
2188+ if ((tpValue && tpImplied =:= AnyValClass .tpe) ||
2189+ (! tpValue && tpImplied =:= AnyRefClass .tpe)) AnyClass .tpe
2190+ else tpImplied
2191+
2192+ tp <:< tpImpliedNormalizedToAny
2193+ }
2194+
21672195 final def implies (other : Const ): Boolean = {
21682196 val r = (this , other) match {
21692197 case (_ : ValueConst , _ : ValueConst ) => this == other // hashconsed
2170- case (_ : ValueConst , _ : TypeConst ) => tp <:< other.tp
2171- case (_ : TypeConst , _) => tp <:< other.tp
2198+ case (_ : ValueConst , _ : TypeConst ) => instanceOfTpImplies(tp, other.tp)
2199+ case (_ : TypeConst , _) => instanceOfTpImplies(tp, other.tp)
21722200 case _ => false
21732201 }
21742202 // if(r) patmatDebug("implies : "+(this, other))
@@ -2185,12 +2213,12 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
21852213 // this causes false negative for unreachability, but that's ok:
21862214 // example: val X = 1; val Y = 1; (2: Int) match { case X => case Y => /* considered reachable */ }
21872215 case (_ : ValueConst , _ : ValueConst ) => this != other
2188- case (_ : ValueConst , _ : TypeConst ) => ! ((tp <:< other.tp) || (other.tp <:< wideTp))
2189- case (_ : TypeConst , _ : ValueConst ) => ! ((other.tp <:< tp) || (tp <:< other.wideTp))
2190- case (_ : TypeConst , _ : TypeConst ) => ! ((tp <:< other.tp) || (other.tp <:< tp))
2216+ case (_ : ValueConst , _ : TypeConst ) => ! (instanceOfTpImplies (tp, other.tp) || instanceOfTpImplies (other.tp, wideTp))
2217+ case (_ : TypeConst , _ : ValueConst ) => ! (instanceOfTpImplies (other.tp, tp) || instanceOfTpImplies (tp, other.wideTp))
2218+ case (_ : TypeConst , _ : TypeConst ) => ! (instanceOfTpImplies (tp, other.tp) || instanceOfTpImplies (other.tp, tp))
21912219 case _ => false
21922220 }
2193- // if(r) patmatDebug("excludes : "+(this, this.tp, other, other.tp, (tp <:< other.tp), (tp <:< other.wideTp), (other.tp <:< tp), (other.tp <:< wideTp) ))
2221+ // if(r) patmatDebug("excludes : "+(this, this.tp, other, other.tp))
21942222 // else patmatDebug("NOT excludes: "+(this, other))
21952223 r
21962224 }
@@ -2752,7 +2780,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
27522780 def simplify (c : Cond ): Set [Cond ] = c match {
27532781 case AndCond (a, b) => simplify(a) ++ simplify(b)
27542782 case OrCond (_, _) => Set (FalseCond ) // TODO: make more precise
2755- case NonNullCond (_) => Set (TrueCond ) // not worth remembering
2783+ case NonNullCond (_) => Set (TrueCond ) // not worth remembering
27562784 case _ => Set (c)
27572785 }
27582786 val conds = simplify(cond)
@@ -2768,7 +2796,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
27682796 case (priorTest, deps) =>
27692797 ((simplify(priorTest.cond) == nonTrivial) || // our conditions are implied by priorTest if it checks the same thing directly
27702798 (nonTrivial subsetOf deps) // or if it depends on a superset of our conditions
2771- ) && (deps subsetOf tested) // the conditions we've tested when we are here in the match satisfy the prior test, and hence what it tested
2799+ ) && (deps subsetOf tested) // the conditions we've tested when we are here in the match satisfy the prior test, and hence what it tested
27722800 } foreach {
27732801 case (priorTest, _) =>
27742802 // if so, note the dependency in both tests
0 commit comments