-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Refine rules for capture parameters and members #22000
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
921e9e0
c996062
8a15af3
092b358
acde5c0
ed7eed6
bf8dccc
1fb05b2
82c5512
0750d5c
1ed08de
c1a0835
6866bd1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,12 +93,19 @@ trait CaptureRef extends TypeProxy, ValueType: | |
final def invalidateCaches() = | ||
myCaptureSetRunId = NoRunId | ||
|
||
/** x subsumes x | ||
* this subsumes this.f | ||
/** x subsumes x | ||
* x =:= y ==> x subsumes y | ||
* x subsumes y ==> x subsumes y.f | ||
* x subsumes y ==> x* subsumes y, x subsumes y? | ||
* x subsumes y ==> x* subsumes y*, x? subsumes y? | ||
* x: x1.type /\ x1 subsumes y ==> x subsumes y | ||
* TODO: Document path cases | ||
* X = CapSet^cx, exists rx in cx, rx subsumes y ==> X subsumes y | ||
* Y = CapSet^cy, forall ry in cy, x subsumes ry ==> x subsumes Y | ||
* X: CapSet^c1...CapSet^c2, (CapSet^c1) subsumes y ==> X subsumes y | ||
* Y: CapSet^c1...CapSet^c2, x subsumes (CapSet^c2) ==> x subsumes Y | ||
* Contains[X, y] ==> X subsumes y | ||
* | ||
* TODO: Document cases with more comments. | ||
*/ | ||
final def subsumes(y: CaptureRef)(using Context): Boolean = | ||
|
||
|
@@ -135,14 +142,29 @@ trait CaptureRef extends TypeProxy, ValueType: | |
case _ => false | ||
|| viaInfo(y.info)(subsumingRefs(this, _)) | ||
case MaybeCapability(y1) => this.stripMaybe.subsumes(y1) | ||
case y: TypeRef if y.derivesFrom(defn.Caps_CapSet) => | ||
// The upper and lower bounds don't have to be in the form of `CapSet^{...}`. | ||
// They can be other capture set variables, which are bounded by `CapSet`, | ||
// like `def test[X^, Y^, Z >: X <: Y]`. | ||
y.info match | ||
case TypeBounds(_, hi: CaptureRef) => this.subsumes(hi) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this case happen? I thought the upper bound has to be of the form There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The upper and lower bounds don't have to be in the form of |
||
case _ => y.captureSetOfInfo.elems.forall(this.subsumes) | ||
case CapturingType(parent, refs) if parent.derivesFrom(defn.Caps_CapSet) => | ||
refs.elems.forall(this.subsumes) | ||
case _ => false | ||
|| this.match | ||
case ReachCapability(x1) => x1.subsumes(y.stripReach) | ||
case x: TermRef => viaInfo(x.info)(subsumingRefs(_, y)) | ||
case x: TermParamRef => subsumesExistentially(x, y) | ||
case x: TypeRef if x.symbol.info.derivesFrom(defn.Caps_CapSet) => | ||
x.captureSetOfInfo.elems.exists(_.subsumes(y)) | ||
case x: TypeRef => assumedContainsOf(x).contains(y) | ||
case x: TypeRef if assumedContainsOf(x).contains(y) => true | ||
case x: TypeRef if x.derivesFrom(defn.Caps_CapSet) => | ||
x.info match | ||
case TypeBounds(lo: CaptureRef, _) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above; can this case happen? |
||
lo.subsumes(y) | ||
case _ => | ||
x.captureSetOfInfo.elems.exists(_.subsumes(y)) | ||
case CapturingType(parent, refs) if parent.derivesFrom(defn.Caps_CapSet) => | ||
refs.elems.exists(_.subsumes(y)) | ||
case _ => false | ||
end subsumes | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import caps.* | ||
|
||
class IO | ||
|
||
def f[C^](io: IO^{C^}) = ??? | ||
|
||
def test = | ||
f[CapSet](???) | ||
f[CapSet^{}](???) | ||
f[CapSet^](???) | ||
f[Nothing](???) // error | ||
f[String](???) // error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import caps.* | ||
|
||
trait Abstract[X^]: | ||
type C >: X <: CapSet^ | ||
// Don't test the return type using Unit, because it is a pure type. | ||
def boom(): AnyRef^{C^} | ||
|
||
class Concrete extends Abstract[CapSet^{}]: | ||
type C = CapSet^{} | ||
// TODO: Why do we get error without the return type here? | ||
def boom(): AnyRef = new Object | ||
|
||
class Concrete2 extends Abstract[CapSet^{}]: | ||
type C = CapSet^{} | ||
def boom(): AnyRef^ = new Object // error | ||
|
||
class Concrete3 extends Abstract[CapSet^{}]: | ||
def boom(): AnyRef = new Object | ||
|
||
class Concrete4(a: AnyRef^) extends Abstract[CapSet^{a}]: | ||
type C = CapSet // error | ||
def boom(): AnyRef^{a} = a // error | ||
|
||
class Concrete5(a: AnyRef^, b: AnyRef^) extends Abstract[CapSet^{a}]: | ||
type C = CapSet^{a} | ||
def boom(): AnyRef^{b} = b // error | ||
|
||
class Concrete6(a: AnyRef^, b: AnyRef^) extends Abstract[CapSet^{a}]: | ||
def boom(): AnyRef^{b} = b // error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import caps.* | ||
|
||
class C | ||
|
||
def test[X^, Y^, Z >: X <: Y](x: C^{X^}, y: C^{Y^}, z: C^{Z^}) = | ||
val x2z: C^{Z^} = x | ||
val z2y: C^{Y^} = z | ||
val x2y: C^{Y^} = x // error | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,13 @@ | ||
import caps.* | ||
|
||
trait AbstractWrong: | ||
type C <: CapSet | ||
def boom(): Unit^{C^} // error | ||
type C <: CapSet | ||
def f(): Unit^{C^} // error | ||
|
||
trait Abstract: | ||
type C <: CapSet^ | ||
def boom(): Unit^{C^} | ||
|
||
class Concrete extends Abstract: | ||
type C = Nothing | ||
def boom() = () // error | ||
trait Abstract1: | ||
type C >: CapSet <: CapSet^ | ||
def f(): Unit^{C^} | ||
|
||
// class Abstract2: | ||
// type C^ | ||
// def f(): Unit^{C^} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import language.experimental.modularity | ||
import caps.* | ||
|
||
class IO | ||
|
||
class File | ||
|
||
trait Abstract: | ||
type C >: CapSet <: CapSet^ | ||
def f(file: File^{C^}): Unit | ||
|
||
class Concrete1 extends Abstract: | ||
type C = CapSet | ||
def f(file: File) = () | ||
|
||
class Concrete2(io: IO^) extends Abstract: | ||
type C = CapSet^{io} | ||
def f(file: File^{io}) = () | ||
|
||
class Concrete3(io: IO^) extends Abstract: | ||
type C = CapSet^{io} | ||
def f(file: File) = () // error | ||
|
||
trait Abstract2(tracked val io: IO^): | ||
type C >: CapSet <: CapSet^{io} | ||
def f(file: File^{C^}): Unit | ||
|
||
class Concrete4(io: IO^) extends Abstract2(io): | ||
type C = CapSet | ||
def f(file: File) = () | ||
|
||
class Concrete5(io1: IO^, io2: IO^) extends Abstract2(io1): | ||
type C = CapSet^{io2} // error | ||
def f(file: File^{io2}) = () | ||
|
||
trait Abstract3[X^]: | ||
type C >: CapSet <: X | ||
def f(file: File^{C^}): Unit | ||
|
||
class Concrete6(io: IO^) extends Abstract3[CapSet^{io}]: | ||
type C = CapSet | ||
def f(file: File) = () | ||
|
||
class Concrete7(io1: IO^, io2: IO^) extends Abstract3[CapSet^{io1}]: | ||
type C = CapSet^{io2} // error | ||
def f(file: File^{io2}) = () | ||
|
||
class Concrete8(io1: IO^, io2: IO^) extends Abstract3[CapSet^{io1}]: | ||
def f(file: File^{io2}) = () // error |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import caps.* | ||
|
||
class IO | ||
class File(io: IO^) | ||
|
||
class Handler[C^]: | ||
def f(file: File^): File^{C^} = file // error | ||
def g(file: File^{C^}): File^ = file // ok |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
-- Error: tests/neg-custom-args/captures/use-capset.scala:7:50 --------------------------------------------------------- | ||
7 |private def g[C^] = (xs: List[Object^{C^}]) => xs.head // error | ||
-- Error: tests/neg-custom-args/captures/use-capset.scala:5:50 --------------------------------------------------------- | ||
5 |private def g[C^] = (xs: List[Object^{C^}]) => xs.head // error | ||
| ^^^^^^^ | ||
| Capture set parameter C leaks into capture scope of method g. | ||
| To allow this, the type C should be declared with a @use annotation | ||
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/use-capset.scala:13:22 ----------------------------------- | ||
13 | val _: () -> Unit = h // error: should be ->{io} | ||
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/use-capset.scala:11:22 ----------------------------------- | ||
11 | val _: () -> Unit = h // error: should be ->{io} | ||
| ^ | ||
| Found: (h : () ->{io} Unit) | ||
| Required: () -> Unit | ||
| | ||
| longer explanation available when compiling with `-explain` | ||
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/use-capset.scala:15:50 ----------------------------------- | ||
15 | val _: () -> List[Object^{io}] -> Object^{io} = h2 // error, should be ->{io} | ||
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/use-capset.scala:13:50 ----------------------------------- | ||
13 | val _: () -> List[Object^{io}] -> Object^{io} = h2 // error, should be ->{io} | ||
| ^^ | ||
| Found: (h2 : () ->? (x$0: List[box Object^]^{}) ->{io} Object^{io}) | ||
| Required: () -> List[box Object^{io}] -> Object^{io} | ||
| Found: (h2 : () ->? (x$0: List[box Object^{io}]^{}) ->{io} Object^{io}) | ||
| Required: () -> List[box Object^{io}] -> Object^{io} | ||
| | ||
| longer explanation available when compiling with `-explain` |
Uh oh!
There was an error while loading. Please reload this page.