Skip to content

Commit dee72c8

Browse files
committed
Document toResultInResults and add test cases
1 parent b964d44 commit dee72c8

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,8 @@ object Capabilities:
851851
end toResult
852852

853853
/** Map global roots in function results to result roots. Also,
854-
* map roots in the types of parameterless def methods.
854+
* map roots in the types of def methods that are parameterless
855+
* or have only type parameters.
855856
*/
856857
def toResultInResults(sym: Symbol, fail: Message => Unit, keepAliases: Boolean = false)(tp: Type)(using Context): Type =
857858
val m = new TypeMap with FollowAliasesMap:
@@ -880,8 +881,17 @@ object Capabilities:
880881
throw ex
881882
m(tp) match
882883
case tp1: ExprType if sym.is(Method, butNot = Accessor) =>
884+
// Map the result of parameterless `def` methods.
883885
tp1.derivedExprType(toResult(tp1.resType, tp1, fail))
884886
case tp1: PolyType if !tp1.resType.isInstanceOf[MethodicType] =>
887+
// Map also the result type of method with only type parameters.
888+
// This way, the `^` in the following method will be mapped to a `ResultCap`:
889+
// ```
890+
// object Buffer:
891+
// def empty[T]: Buffer[T]^
892+
// ```
893+
// This is more desirable than interpreting `^` as a `Fresh` at the level of `Buffer.empty`
894+
// in most cases.
885895
tp1.derivedLambdaType(resType = toResult(tp1.resType, tp1, fail))
886896
case tp1 => tp1
887897
end toResultInResults
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Flag -source set repeatedly
2+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-fresh-levels.scala:14:10 ------------------------------
3+
14 | r.put(x) // error
4+
| ^
5+
| Found: IO^{x}
6+
| Required: IO^
7+
|
8+
| where: ^ refers to a fresh root capability in the type of value r
9+
|
10+
| longer explanation available when compiling with `-explain`
11+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-fresh-levels.scala:17:10 ------------------------------
12+
17 | r.put(innerIO) // error
13+
| ^^^^^^^
14+
| Found: IO^{innerIO}
15+
| Required: IO^
16+
|
17+
| where: ^ refers to a fresh root capability in the type of value r
18+
|
19+
| longer explanation available when compiling with `-explain`
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//> using options -source 3.7
2+
import language.experimental.captureChecking
3+
import caps.*
4+
class IO
5+
class Ref[X](init: X):
6+
private var _data = init
7+
def get: X = _data
8+
def put(y: X): Unit = _data = y
9+
def runIO(op: IO^ => Unit): Unit = ()
10+
def test1(a: IO^, b: IO^, c: IO^): Unit =
11+
val r: Ref[IO^] = Ref(a)
12+
r.put(b) // ok
13+
def outer(x: IO^): Unit =
14+
r.put(x) // error
15+
r.put(c) // ok
16+
runIO: (innerIO: IO^) =>
17+
r.put(innerIO) // error
18+
runIO: innerIO =>
19+
r.put(innerIO) // should be error, but ok // unsound
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import language.experimental.captureChecking
2+
trait Collection[T]
3+
trait IO
4+
def empty[T]: Collection[T]^ = ???
5+
def emptyAlt[T](): Collection[T]^ = ???
6+
def newIO: IO^ = ???
7+
def test1(): Unit =
8+
val t1: Collection[Int]^ = empty[Int] // ok
9+
val t2: IO^ = newIO // ok
10+
val t3: Collection[Int]^ = emptyAlt[Int]() // ok
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
4+
trait Collection[T] extends Mutable:
5+
update def add(elem: T): Unit
6+
update def remove(elem: T): Unit
7+
def get(index: Int): Option[T]
8+
9+
object Collection:
10+
def empty[T]: Collection[T] = ???
11+
12+
trait Foo:
13+
val thunks: Collection[() => Unit] // that's fine
14+
15+
object FooImpl1 extends Foo:
16+
val thunks: Collection[() => Unit] = Collection.empty // was error, now ok

0 commit comments

Comments
 (0)