Skip to content

Commit edd7d13

Browse files
noti0na1bracevac
authored andcommitted
Remove unnecessary ^ in capture set syntax.
1 parent 3fe9304 commit edd7d13

33 files changed

+118
-104
lines changed

compiler/src/dotty/tools/dotc/core/Mode.scala

+9-1
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,16 @@ object Mode {
9191
*/
9292
val ImplicitExploration: Mode = newMode(12, "ImplicitExploration")
9393

94+
/** We are currently inside a capture set.
95+
* A term name could be a capture variable, so we need to
96+
* check that it is valid to use as type name.
97+
* Since this mode is only used during annotation typing,
98+
* we can reuse the value of `ImplicitExploration` to save bits.
99+
*/
100+
val InCaptureSet: Mode = newMode(13, "InCaptureSet")
101+
94102
/** We are currently unpickling Scala2 info */
95-
val Scala2Unpickling: Mode = newMode(13, "Scala2Unpickling")
103+
val Scala2Unpickling: Mode = newMode(14, "Scala2Unpickling")
96104

97105
/** Signifies one of two possible situations:
98106
* 1. We are currently checking bounds to be non-empty, so we should not

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+1-7
Original file line numberDiff line numberDiff line change
@@ -1601,20 +1601,14 @@ object Parsers {
16011601
}
16021602

16031603
/** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`]
1604-
* | [ { SimpleRef `.` } SimpleRef `.` ] id `^`
1604+
* | [ { SimpleRef `.` } SimpleRef `.` ] id
16051605
*/
16061606
def captureRef(): Tree =
16071607
val ref = dotSelectors(simpleRef())
16081608
if isIdent(nme.raw.STAR) then
16091609
in.nextToken()
16101610
atSpan(startOffset(ref)):
16111611
PostfixOp(ref, Ident(nme.CC_REACH))
1612-
else if isIdent(nme.UPARROW) then
1613-
in.nextToken()
1614-
atSpan(startOffset(ref)):
1615-
convertToTypeId(ref) match
1616-
case ref: RefTree => makeCapsOf(ref)
1617-
case ref => ref
16181612
else ref
16191613

16201614
/** CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}` -- under captureChecking

compiler/src/dotty/tools/dotc/typer/Applications.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import annotation.threadUnsafe
3636

3737
import scala.util.control.NonFatal
3838
import dotty.tools.dotc.inlines.Inlines
39+
import dotty.tools.dotc.cc.isRetains
3940

4041
object Applications {
4142
import tpd.*
@@ -1115,7 +1116,9 @@ trait Applications extends Compatibility {
11151116
val fun2 = Applications.retypeSignaturePolymorphicFn(fun1, methType)
11161117
simpleApply(fun2, proto)
11171118
case funRef: TermRef =>
1118-
val app = ApplyTo(tree, fun1, funRef, proto, pt)
1119+
// println(i"typedApply: $funRef, ${tree.args}, ${funRef.symbol.maybeOwner.isRetains}")
1120+
val applyCtx = if funRef.symbol.maybeOwner.isRetains then ctx.addMode(Mode.InCaptureSet) else ctx
1121+
val app = ApplyTo(tree, fun1, funRef, proto, pt)(using applyCtx)
11191122
convertNewGenericArray(
11201123
widenEnumCase(
11211124
postProcessByNameArgs(funRef, app).computeNullable(),

compiler/src/dotty/tools/dotc/typer/Typer.scala

+12
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
715715
&& ctx.owner.owner.unforcedDecls.lookup(tree.name).exists
716716
then // we are in the arguments of a this(...) constructor call
717717
errorTree(tree, em"$tree is not accessible from constructor arguments")
718+
else if ctx.mode.is(Mode.InCaptureSet) then
719+
// If we are in a capture set and the identifier is not a term name,
720+
// try to type it with the same name but as a type
721+
typed(untpd.makeCapsOf(untpd.cpy.Ident(tree)(name.toTypeName)), pt)
718722
else
719723
errorTree(tree, MissingIdent(tree, kind, name, pt))
720724
end typedIdent
@@ -920,6 +924,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
920924
typedCBSelect(tree0, pt, qual)
921925
else EmptyTree
922926

927+
// Otherwise, if we are in a capture set, try to type it as a capture variable
928+
// reference (as selecting a type name).
929+
def trySelectTypeInCaptureSet() =
930+
if ctx.mode.is(Mode.InCaptureSet) && tree0.name.isTypeName then
931+
typedSelectWithAdapt(untpd.cpy.Select(tree0)(qual, tree0.name.toTypeName), pt, qual)
932+
else EmptyTree
933+
923934
// Otherwise, report an error
924935
def reportAnError() =
925936
assignType(tree,
@@ -941,6 +952,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
941952
.orElse(tryDynamic())
942953
.orElse(trySelectable())
943954
.orElse(tryCBCompanion())
955+
.orElse(trySelectTypeInCaptureSet())
944956
.orElse(reportAnError())
945957
end typedSelectWithAdapt
946958

tests/neg-custom-args/captures/capset-bound.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class IO
55
case class File(io: IO^)
66

77
def test(io1: IO^, io2: IO^) =
8-
def f[C >: CapSet^{io1} <: CapSet^](file: File^{C^}) = ???
8+
def f[C >: CapSet^{io1} <: CapSet^](file: File^{C}) = ???
99
val f1: File^{io1} = ???
1010
val f2: File^{io2} = ???
1111
val f3: File^{io1, io2} = ???

tests/neg-custom-args/captures/capset-bound2.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import caps.*
22

33
class IO
44

5-
def f[C^](io: IO^{C^}) = ???
5+
def f[C^](io: IO^{C}) = ???
66

77
def test =
88
f[CapSet](???)
99
f[CapSet^{}](???)
1010
f[CapSet^](???)
1111
f[Nothing](???) // error
1212
f[String](???) // error
13-

tests/neg-custom-args/captures/capset-members.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import caps.*
33
trait Abstract[X^]:
44
type C >: X <: CapSet^
55
// Don't test the return type using Unit, because it is a pure type.
6-
def boom(): AnyRef^{C^}
6+
def boom(): AnyRef^{C}
77

88
class Concrete extends Abstract[CapSet^{}]:
99
type C = CapSet^{}
@@ -27,4 +27,3 @@ class Concrete5(a: AnyRef^, b: AnyRef^) extends Abstract[CapSet^{a}]:
2727

2828
class Concrete6(a: AnyRef^, b: AnyRef^) extends Abstract[CapSet^{a}]:
2929
def boom(): AnyRef^{b} = b // error
30-

tests/neg-custom-args/captures/capture-parameters.scala

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import caps.*
22

33
class C
44

5-
def test[X^, Y^, Z >: X <: Y](x: C^{X^}, y: C^{Y^}, z: C^{Z^}) =
6-
val x2z: C^{Z^} = x
7-
val z2y: C^{Y^} = z
8-
val x2y: C^{Y^} = x // error
9-
5+
def test[X^, Y^, Z >: X <: Y](x: C^{X}, y: C^{Y}, z: C^{Z}) =
6+
val x2z: C^{Z} = x
7+
val z2y: C^{Y} = z
8+
val x2y: C^{Y} = x // error

tests/neg-custom-args/captures/capture-poly.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ trait Foo extends Capability
55
trait CaptureSet:
66
type C >: CapSet <: CapSet^
77

8-
def capturePoly[C^](a: Foo^{C^}): Foo^{C^} = a
9-
def capturePoly2(c: CaptureSet)(a: Foo^{c.C^}): Foo^{c.C^} = a
8+
def capturePoly[C^](a: Foo^{C}): Foo^{C} = a
9+
def capturePoly2(c: CaptureSet)(a: Foo^{c.C}): Foo^{c.C} = a
1010

1111
def test =
1212
val x: Foo^ = ???
@@ -15,8 +15,8 @@ def test =
1515
object X extends CaptureSet:
1616
type C = CapSet^{x}
1717

18-
val z1: Foo^{X.C^} = x
19-
val z2: Foo^{X.C^} = y // error
18+
val z1: Foo^{X.C} = x
19+
val z2: Foo^{X.C} = y // error
2020

2121
val z3: Foo^{x} = capturePoly(x)
2222
val z4: Foo^{x} = capturePoly(y) // error

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

+13-13
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,32 @@ import caps.*
33

44
def test[C^] =
55
val a: C = ???
6-
val b: CapSet^{C^} = a
6+
val b: CapSet^{C} = a
77
val c: C = b
8-
val d: CapSet^{C^, c} = a
8+
val d: CapSet^{C, c} = a
99

1010
// TODO: make "CapSet-ness" of type variables somehow contagious?
1111
// Then we don't have to spell out the bounds explicitly...
1212
def testTrans[C^, D >: CapSet <: C, E >: CapSet <: D, F >: C <: CapSet^] =
1313
val d1: D = ???
14-
val d2: CapSet^{D^} = d1
14+
val d2: CapSet^{D} = d1
1515
val d3: D = d2
1616
val e1: E = ???
17-
val e2: CapSet^{E^} = e1
17+
val e2: CapSet^{E} = e1
1818
val e3: E = e2
1919
val d4: D = e1
2020
val c1: C = d1
2121
val c2: C = e1
2222
val f1: F = c1
23-
val d_e_f1: CapSet^{D^,E^,F^} = d1
24-
val d_e_f2: CapSet^{D^,E^,F^} = e1
25-
val d_e_f3: CapSet^{D^,E^,F^} = f1
23+
val d_e_f1: CapSet^{D,E,F} = d1
24+
val d_e_f2: CapSet^{D,E,F} = e1
25+
val d_e_f3: CapSet^{D,E,F} = f1
2626
val f2: F = d_e_f1
2727
val c3: C = d_e_f1 // error
2828
val c4: C = f1 // error
2929
val e4: E = f1 // error
3030
val e5: E = d1 // error
31-
val c5: CapSet^{C^} = e1
31+
val c5: CapSet^{C} = e1
3232

3333

3434
trait A[+T]
@@ -37,12 +37,12 @@ trait B[-C]
3737

3838
def testCong[C^, D^] =
3939
val a: A[C] = ???
40-
val b: A[CapSet^{C^}] = a
41-
val c: A[CapSet^{D^}] = a // error
42-
val d: A[CapSet^{C^,D^}] = a
40+
val b: A[CapSet^{C}] = a
41+
val c: A[CapSet^{D}] = a // error
42+
val d: A[CapSet^{C,D}] = a
4343
val e: A[C] = d // error
4444
val f: B[C] = ???
45-
val g: B[CapSet^{C^}] = f
45+
val g: B[CapSet^{C}] = f
4646
val h: B[C] = g
47-
val i: B[CapSet^{C^,D^}] = h // error
47+
val i: B[CapSet^{C,D}] = h // error
4848
val j: B[C] = i

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

+15-15
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,32 @@ trait BoundsTest:
1010

1111
def testTransMixed[A^,
1212
B >: CapSet <: A,
13-
C >: CapSet <: CapSet^{B^},
13+
C >: CapSet <: CapSet^{B},
1414
D >: CapSet <: C,
15-
E >: CapSet <: CapSet^{D^},
16-
F >: CapSet <: CapSet^{A^,b},
17-
X >: CapSet <: CapSet^{F^,D^},
18-
Y >: CapSet^{F^} <: CapSet^{F^,A^,b},
19-
Z >: CapSet^{b} <: CapSet^{b,Y^}] =
15+
E >: CapSet <: CapSet^{D},
16+
F >: CapSet <: CapSet^{A,b},
17+
X >: CapSet <: CapSet^{F,D},
18+
Y >: CapSet^{F} <: CapSet^{F,A,b},
19+
Z >: CapSet^{b} <: CapSet^{b,Y}] =
2020
val e: E = ???
21-
val e2: CapSet^{E^} = e
21+
val e2: CapSet^{E} = e
2222
val ed: D = e
23-
val ed2: CapSet^{D^} = e
23+
val ed2: CapSet^{D} = e
2424
val ec: C = e
25-
val ec2: CapSet^{C^} = e
25+
val ec2: CapSet^{C} = e
2626
val eb: B = e
27-
val eb2: CapSet^{B^} = e
27+
val eb2: CapSet^{B} = e
2828
val ea: A = e
29-
val ea2: CapSet^{A^} = e
29+
val ea2: CapSet^{A} = e
3030
val ex: X = e // error
31-
val ex2: CapSet^{X^} = e // error
31+
val ex2: CapSet^{X} = e // error
3232
val f: F = ???
33-
val f2: CapSet^{F^} = f
33+
val f2: CapSet^{F} = f
3434
val y: Y = f
35-
val y2: CapSet^{Y^} = f
35+
val y2: CapSet^{Y} = f
3636
val cb: CapSet^{b} = ???
3737
val z: Z = cb
38-
val z2: CapSet^{Z^} = cb
38+
val z2: CapSet^{Z} = cb
3939

4040
def callTransMixed =
4141
val x, y, z: Bar^ = ???

tests/neg-custom-args/captures/cc-poly-1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Test:
66
class C extends Capability
77
class D
88

9-
def f[X^](x: D^{X^}): D^{X^} = x
9+
def f[X^](x: D^{X}): D^{X} = x
1010

1111
def test(c1: C, c2: C) =
1212
f[Any](D()) // error

tests/neg-custom-args/captures/cc-poly-2.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Test:
66
class C extends Capability
77
class D
88

9-
def f[X^](x: D^{X^}): D^{X^} = x
9+
def f[X^](x: D^{X}): D^{X} = x
1010

1111
def test(c1: C, c2: C) =
1212
val d: D^ = D()

tests/neg-custom-args/captures/i21313.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ trait Async:
66
def foo(x: Async) = x.await(???) // error
77

88
trait Source[+T, Cap^]:
9-
final def await(using ac: Async^{Cap^}) = ac.await[T, Cap](this) // Contains[Cap, ac] is assured because {ac} <: Cap.
9+
final def await(using ac: Async^{Cap}) = ac.await[T, Cap](this) // Contains[Cap, ac] is assured because {ac} <: Cap.
1010

1111
def test(using ac1: Async^, ac2: Async^, x: String) =
1212
val src1 = new Source[Int, CapSet^{ac1}] {}

tests/neg-custom-args/captures/i21347.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import language.experimental.captureChecking
22

3-
def runOps[C^](ops: List[() ->{C^} Unit]): Unit =
3+
def runOps[C^](ops: List[() ->{C} Unit]): Unit =
44
ops.foreach: op => // error
55
op()
66

tests/neg-custom-args/captures/i21868.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import caps.*
22

33
trait AbstractWrong:
44
type C <: CapSet
5-
def f(): Unit^{C^} // error
5+
def f(): Unit^{C} // error
66

77
trait Abstract1:
88
type C >: CapSet <: CapSet^
9-
def f(): Unit^{C^}
9+
def f(): Unit^{C}
1010

1111
// class Abstract2:
1212
// type C^

tests/neg-custom-args/captures/i21868b.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class File
77

88
trait Abstract:
99
type C >: CapSet <: CapSet^
10-
def f(file: File^{C^}): Unit
10+
def f(file: File^{C}): Unit
1111

1212
class Concrete1 extends Abstract:
1313
type C = CapSet
@@ -23,7 +23,7 @@ class Concrete3(io: IO^) extends Abstract:
2323

2424
trait Abstract2(tracked val io: IO^):
2525
type C >: CapSet <: CapSet^{io}
26-
def f(file: File^{C^}): Unit
26+
def f(file: File^{C}): Unit
2727

2828
class Concrete4(io: IO^) extends Abstract2(io):
2929
type C = CapSet
@@ -35,7 +35,7 @@ class Concrete5(io1: IO^, io2: IO^) extends Abstract2(io1):
3535

3636
trait Abstract3[X^]:
3737
type C >: CapSet <: X
38-
def f(file: File^{C^}): Unit
38+
def f(file: File^{C}): Unit
3939

4040
class Concrete6(io: IO^) extends Abstract3[CapSet^{io}]:
4141
type C = CapSet

tests/neg-custom-args/captures/i22005.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ class IO
44
class File(io: IO^)
55

66
class Handler[C^]:
7-
def f(file: File^): File^{C^} = file // error
8-
def g(file: File^{C^}): File^ = file // ok
7+
def f(file: File^): File^{C} = file // error
8+
def g(file: File^{C}): File^ = file // ok
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-- Error: tests/neg-custom-args/captures/polyCaptures.scala:4:22 -------------------------------------------------------
2-
4 |val runOpsCheck: [C^] -> (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error
2+
4 |val runOpsCheck: [C^] -> (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error
33
| ^
44
| Implementation restriction: polymorphic function types cannot wrap function types that have capture sets
55
-- Error: tests/neg-custom-args/captures/polyCaptures.scala:5:23 -------------------------------------------------------
6-
5 |val runOpsCheck2: [C^] => (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error
6+
5 |val runOpsCheck2: [C^] => (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error
77
| ^
88
| Implementation restriction: polymorphic function types cannot wrap function types that have capture sets
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Box[X](val elem: X)
22

3-
val runOps = [C^] => (b: Box[() ->{C^} Unit]) => b.elem()
4-
val runOpsCheck: [C^] -> (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error
5-
val runOpsCheck2: [C^] => (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error
3+
val runOps = [C^] => (b: Box[() ->{C} Unit]) => b.elem()
4+
val runOpsCheck: [C^] -> (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error
5+
val runOpsCheck2: [C^] => (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error
66

77

tests/neg-custom-args/captures/use-capset.check

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
-- Error: tests/neg-custom-args/captures/use-capset.scala:5:50 ---------------------------------------------------------
2-
5 |private def g[C^] = (xs: List[Object^{C^}]) => xs.head // error
3-
| ^^^^^^^
4-
| Capture set parameter C leaks into capture scope of method g.
5-
| To allow this, the type C should be declared with a @use annotation
1+
-- Error: tests/neg-custom-args/captures/use-capset.scala:5:49 ---------------------------------------------------------
2+
5 |private def g[C^] = (xs: List[Object^{C}]) => xs.head // error
3+
| ^^^^^^^
4+
| Capture set parameter C leaks into capture scope of method g.
5+
| To allow this, the type C should be declared with a @use annotation
66
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/use-capset.scala:11:22 -----------------------------------
77
11 | val _: () -> Unit = h // error: should be ->{io}
88
| ^

0 commit comments

Comments
 (0)