-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Originally posted by @Linyxus in #15175 (comment)
Regarding the soundness holes caused by resetting approx state: yes, we have more soundness holes caused by this. Each time isSubType(S, T) (instead of recur(S, T)) is called inside isSubType, the approx state is reset, and it will be a potential soundness hole. For example, I find another callsite of isSubType here, and we can make a counter-example showing the unsoundness brought by this:
enum SUB[-A, +B]:
case Refl[C]() extends SUB[C, C]
trait Tag { type T }
def foo[A, B, X <: Tag{type T <: A}](e: SUB[X, Tag{type T <: B}], x: A): B = e match {
case SUB.Refl() =>
// unsound GADT constr because of approx state resetting: A <: B
x
}
def bad(x: Int): String =
foo[Int, String, Tag{type T = Nothing}](SUB.Refl(), x) // cast Int to StringIn this example, we are trying to extract necessary constraint from X <: Tag{type T <: B}, where X is known to be a subtype of Tag{type T <: A}. During this we will try upcasting LHS and compare Tag{type T <: A} <: Tag{type T <: B} with LHS approximated. Since when comparing the refinement info the approx state is reset, we derive the unsound constraint A <: B.