Skip to content

Commit d324de5

Browse files
committed
Add missing CaptureSet.ofType case for RetainingTypes
1 parent e5e7eac commit d324de5

File tree

7 files changed

+63
-10
lines changed

7 files changed

+63
-10
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureSet.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,8 @@ object CaptureSet:
13601360
else empty
13611361
case CapturingType(parent, refs) =>
13621362
recur(parent) ++ refs
1363+
case tp @ AnnotatedType(parent, ann) if ann.symbol.isRetains =>
1364+
recur(parent) ++ ann.tree.toCaptureSet
13631365
case tpd @ defn.RefinedFunctionOf(rinfo: MethodType) if followResult =>
13641366
ofType(tpd.parent, followResult = false) // pick up capture set from parent type
13651367
++ recur(rinfo.resType) // add capture set of result

scala2-library-cc/src/scala/collection/Iterable.scala

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import scala.annotation.unchecked.uncheckedVariance
1717
import scala.collection.mutable.Builder
1818
import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped}
1919
import language.experimental.captureChecking
20+
import scala.caps.unsafe.unsafeAssumePure
2021

2122
/** Base trait for generic collections.
2223
*
@@ -302,7 +303,8 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with Iterable
302303
* this.sizeIs > size // this.sizeCompare(size) > 0
303304
* }}}
304305
*/
305-
@inline final def sizeIs: IterableOps.SizeCompareOps^{this} = new IterableOps.SizeCompareOps(this)
306+
@inline final def sizeIs: IterableOps.SizeCompareOps^{this} = new IterableOps.SizeCompareOps(this.unsafeAssumePure)
307+
// CC Problem: unsafeAssumePure needed since we had to change the argument signatire of SizeCompareOps
306308

307309
/** Compares the size of this $coll to the size of another `Iterable`.
308310
*
@@ -866,8 +868,15 @@ object IterableOps {
866868
* These operations are implemented in terms of
867869
* [[scala.collection.IterableOps.sizeCompare(Int) `sizeCompare(Int)`]].
868870
*/
869-
final class SizeCompareOps private[collection](val it: IterableOps[_, AnyConstr, _]^) extends AnyVal {
870-
this: SizeCompareOps^{it} =>
871+
final class SizeCompareOps private[collection](val it: IterableOps[_, AnyConstr, _]/*^*/) extends AnyVal {
872+
this: SizeCompareOps/*^*/ =>
873+
// CC Problem: if we add the logically needed `^`s to the `it` parameter and the
874+
// self type, separation checking fails in the compiler-generated equals$extends
875+
// method of the value class. There seems to be something wrong how pattern
876+
// matching interacts with separation checking. A minimized test case
877+
// is pending/pos-custom-args/captures/SizeCompareOps-redux.scala.
878+
// Without the `^`s, the `sizeIs` method needs an unsafeAssumePure.
879+
871880
/** Tests if the size of the collection is less than some value. */
872881
@inline def <(size: Int): Boolean = it.sizeCompare(size) < 0
873882
/** Tests if the size of the collection is less than or equal to some value. */

tests/neg-custom-args/captures/capture-vars-subtyping.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import language.experimental.captureChecking
2+
import language.`3.7` // no separation checking, TODO enable
23
import caps.*
34

45
def test[C^] =

tests/neg-custom-args/captures/capture-vars-subtyping2.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ trait BoundsTest:
2525
val ec2: CapSet^{C} = e
2626
val eb: B = e
2727
val eb2: CapSet^{B} = e
28-
val ea: A = e
28+
locally:
29+
val ea: A = e
2930
val ea2: CapSet^{A} = e
3031
val ex: X = e // error
3132
val ex2: CapSet^{X} = e // error

tests/neg-custom-args/captures/lazyref.check

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,46 +39,46 @@
3939
| ^^^^
4040
| Separation failure: Illegal access to {cap1} which is hidden by the previous definition
4141
| of value ref2 with type LazyRef[Int]{val elem: () => Int}^{cap2, ref1}.
42-
| This type hides capabilities {cap1}
42+
| This type hides capabilities {LazyRef.this.elem, cap1}
4343
|
4444
| where: => refers to a fresh root capability in the type of value elem
4545
-- Error: tests/neg-custom-args/captures/lazyref.scala:26:9 ------------------------------------------------------------
4646
26 | if cap1 == cap2 // error: separation failure // error: separation failure
4747
| ^^^^
4848
| Separation failure: Illegal access to {cap1} which is hidden by the previous definition
4949
| of value ref3 with type LazyRef[Int]{val elem: () => Int}^{cap2, ref1}.
50-
| This type hides capabilities {ref2*, cap1}
50+
| This type hides capabilities {LazyRef.this.elem, ref2*, cap1}
5151
|
5252
| where: => refers to a fresh root capability in the type of value elem
5353
-- Error: tests/neg-custom-args/captures/lazyref.scala:26:17 -----------------------------------------------------------
5454
26 | if cap1 == cap2 // error: separation failure // error: separation failure
5555
| ^^^^
5656
| Separation failure: Illegal access to {cap2} which is hidden by the previous definition
5757
| of value ref3 with type LazyRef[Int]{val elem: () => Int}^{cap2, ref1}.
58-
| This type hides capabilities {ref2*, cap1}
58+
| This type hides capabilities {LazyRef.this.elem, ref2*, cap1}
5959
|
6060
| where: => refers to a fresh root capability in the type of value elem
6161
-- Error: tests/neg-custom-args/captures/lazyref.scala:27:11 -----------------------------------------------------------
6262
27 | then ref1 // error: separation failure
6363
| ^^^^
6464
| Separation failure: Illegal access to {cap1, ref1} which is hidden by the previous definition
6565
| of value ref3 with type LazyRef[Int]{val elem: () => Int}^{cap2, ref1}.
66-
| This type hides capabilities {ref2*, cap1}
66+
| This type hides capabilities {LazyRef.this.elem, ref2*, cap1}
6767
|
6868
| where: => refers to a fresh root capability in the type of value elem
6969
-- Error: tests/neg-custom-args/captures/lazyref.scala:28:11 -----------------------------------------------------------
7070
28 | else ref2) // error: separation failure
7171
| ^^^^
7272
| Separation failure: Illegal access to {cap1, cap2, ref1} which is hidden by the previous definition
7373
| of value ref3 with type LazyRef[Int]{val elem: () => Int}^{cap2, ref1}.
74-
| This type hides capabilities {ref2*, cap1}
74+
| This type hides capabilities {LazyRef.this.elem, ref2*, cap1}
7575
|
7676
| where: => refers to a fresh root capability in the type of value elem
7777
-- Error: tests/neg-custom-args/captures/lazyref.scala:29:9 ------------------------------------------------------------
7878
29 | .map(g) // error: separation failure
7979
| ^
8080
| Separation failure: Illegal access to {cap2} which is hidden by the previous definition
8181
| of value ref3 with type LazyRef[Int]{val elem: () => Int}^{cap2, ref1}.
82-
| This type hides capabilities {ref2*, cap1}
82+
| This type hides capabilities {LazyRef.this.elem, ref2*, cap1}
8383
|
8484
| where: => refers to a fresh root capability in the type of value elem
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
class Ref[T](init: T) extends Mutable:
5+
private var value: T = init
6+
def get: T = value
7+
mut def set(newValue: T): Unit = value = newValue
8+
9+
// a library function that assumes that a and b MUST BE separate
10+
def swap[T](a: Ref[Int]^, b: Ref[Int]^): Unit = ???
11+
12+
def test4(): Unit =
13+
val a: Ref[Int]^ = Ref(0)
14+
val foo: (x: Ref[Int]^) -> (y: Ref[Int]^) ->{x} Unit =
15+
x => y => swap(x, y)
16+
val f = foo(a)
17+
f(a) // error
18+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package collection
2+
trait IterableOps[+A, +CC[_], +C] extends Any:
3+
def sizeCompare(size: Int): Int
4+
5+
object IterableOps:
6+
7+
type AnyConstr[X] = Any
8+
9+
final class SizeCompareOps private[collection](val it: IterableOps[_, AnyConstr, _]^) extends AnyVal:
10+
this: SizeCompareOps^{it} =>
11+
/** Tests if the size of the collection is less than some value. */
12+
@inline def <(size: Int): Boolean = it.sizeCompare(size) < 0
13+
/** Tests if the size of the collection is less than or equal to some value. */
14+
@inline def <=(size: Int): Boolean = it.sizeCompare(size) <= 0
15+
/** Tests if the size of the collection is equal to some value. */
16+
@inline def ==(size: Int): Boolean = it.sizeCompare(size) == 0
17+
/** Tests if the size of the collection is not equal to some value. */
18+
@inline def !=(size: Int): Boolean = it.sizeCompare(size) != 0
19+
/** Tests if the size of the collection is greater than or equal to some value. */
20+
@inline def >=(size: Int): Boolean = it.sizeCompare(size) >= 0
21+
/** Tests if the size of the collection is greater than some value. */
22+
@inline def >(size: Int): Boolean = it.sizeCompare(size) > 0

0 commit comments

Comments
 (0)