Fixes for pattern matching under separation checking#26580
Conversation
|
|
||
| def par[A, B](x: A^, y: B^): Unit = () | ||
|
|
||
| def Test = |
There was a problem hiding this comment.
Can we find a representation that permits consume tails and a unique Nil object?
Without a fresh tail, it's fairly easy to subvert the system:
def Test0 =
val r1 = Ref()
val r2 = Ref()
val r3 = Ref()
val xs0 = FreshNil
val xs1 = FreshCons(r1, xs0)
val xs2 = FreshCons(r2, xs1)
val xs3 = FreshCons(r3, xs1)
val r1_2 = xs2.tail.decons.head
val r1_3 = xs3.tail.decons.head
par(r1_2, r1_3) // oopsThere was a problem hiding this comment.
this looks like a soundness bug if accepted. xs3.tail.decons should be allowed since it uses a consumed thing.
There was a problem hiding this comment.
The question is what do we expect from decons?
Right now it's
consume def decons: FreshCons[A]^ = thisSince the tail isn't marked consume I read it as
"sharing of tails is allowed".
We probably need a "deep" consume? Looking at the inferred capture sets:
val xs2: FreshCons[Ref^{}]{val tail: FreshList[Ref^{}]^{}}^{} =
FreshCons.apply[Ref^'s2](r2, xs1)All those lists are pure, but shouldn't we make FreshList trackable? Then I could see how decons also affects the tails.
But then we have the problem that a singleton Nil list can't be supported? I'd imagine the superclass FreshList should be an ExclusiveCapability.
|
A minimization of the snippet posted by Oliver, which is clearly a soundness bug (double-consume): def Test0 =
val r1 = Ref()
val xs0 = FreshNil
val xs1 = FreshCons(r1, xs0)
val ys1 = xs1.decons // ok
val ys2 = xs1.decons // should be error, but still ok |
|
This crashes the compiler: import language.experimental.separationChecking
import caps.*
class Ref extends Mutable:
var x = 0
def get: Int = x
update def put(y: Int): Unit = x = y
trait FreshList[+A]
case class FreshCons[+A](val head: A^, val tail: FreshList[A]^) extends FreshList[A]
def Test1(xs1: FreshList[Ref^{}]^) =
val ys = xs1 match
case FreshCons(h, t) => FreshCons(h, t) |
|
The problem is in the type produced by def Test0 =
val r1: Ref^ = Ref()
val xs0 = FreshNil
val xs1: FreshCons[Ref^{}]^ = FreshCons(r1, xs0)
val ys1 = xs1.decons // ok
val ys2 = xs1.decons // error
par(ys1, ys2) |
|
The crash is gone now as well. |
|
another soundness issue: import language.experimental.separationChecking
import caps.*
class Ref extends Mutable:
var x = 0
def get: Int = x
update def put(y: Int): Unit = x = y
consume def dealloc(): Unit = ()
case class FreshRef(consume val a: Ref^):
a.dealloc() // should be error, but ok
def boom(consume x: FreshRef^): Unit =
x match
case FreshRef(core) => core.dealloc() // boom! double-free |
We already don't do that when forming CapturingTypes. We now also do not merge
capture sets if the carrier type is of the form
(Box T^C1)^C2
There is a new variant stripOneCapturing that strips only C2 in this case.
This now supports the pos test splits.scala without resorting to the `[A <: Any^{}]` trick
that forces type variables to be shape types.
Accept unboxed -> boxed widenings without constrains. boxed -> unboxed are the only widenings that would be unsound if we did not constrain the capture set to be empty.
Two possibilities: - `hasBoxedCapsets`: contains boxed capsets (even under unboxed ones) - `isBoxed`: Has a boxed capset that can only be wrapped by empty capsets
- More precise typing - Avoids an unsoundness because _i accessor functions return pure results. This causes an additional test failure in caseclass/Test_2.scala.
Propagate consume parameters in case classes to - apply method parameters - copy methods and their parameters, - the unapply parameter, - case field selectors.
_icase selectors to the original case accessors. This gives more precise typing and avoids an unsoundness because_iaccessor functions return pure results.consumeparameters into synthesized parts of case classes.Based on #26569
With the changes there and in this PR we can now define recursive generic data structures of fresh elements and use these date structures in a natural way, including using pattern matching.