Skip to content

Commit a7e2fbd

Browse files
committed
More fix
1 parent 995a2dc commit a7e2fbd

File tree

12 files changed

+93
-84
lines changed

12 files changed

+93
-84
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,9 +2261,9 @@ object desugar {
22612261
AppliedTypeTree(ref(defn.SeqType), t),
22622262
New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil))
22632263
else if op.name == nme.CC_REACH then
2264-
Apply(ref(defn.Caps_reachCapability), t :: Nil)
2264+
Annotated(t, New(ref(defn.ReachCapabilityAnnot.typeRef), Nil :: Nil))
22652265
else if op.name == nme.CC_READONLY then
2266-
Apply(ref(defn.Caps_readOnlyCapability), t :: Nil)
2266+
Annotated(t, New(ref(defn.ReadOnlyCapabilityAnnot.typeRef), Nil :: Nil))
22672267
else
22682268
assert(ctx.mode.isExpr || ctx.reporter.errorsReported || ctx.mode.is(Mode.Interactive), ctx.mode)
22692269
Select(t, op.name)

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,14 @@ case class CaptureAnnotation(refs: CaptureSet, boxed: Boolean)(cls: Symbol) exte
3838

3939
/** Reconstitute annotation tree from capture set */
4040
override def tree(using Context) =
41-
val elems = refs.elems.toList.map {
42-
case cr: TermRef => ref(cr)
43-
case cr: TermParamRef => untpd.Ident(cr.paramName).withType(cr)
44-
case cr: ThisType => This(cr.cls)
45-
case root(_) => ref(root.cap)
46-
// TODO: Will crash if the type is an annotated type, for example `cap.rd`
47-
}
48-
val arg = repeated(elems, TypeTree(defn.AnyType))
49-
New(symbol.typeRef, arg :: Nil)
41+
if symbol == defn.RetainsCapAnnot then
42+
New(symbol.typeRef, Nil)
43+
else
44+
val elems = refs.elems.toList
45+
val trefs =
46+
if elems.isEmpty then defn.NothingType
47+
else elems.reduce[Type]((a, b) => OrType(a, b, soft = false))
48+
New(AppliedType(symbol.typeRef, trefs :: Nil), Nil)
5049

5150
override def symbol(using Context) = cls
5251

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

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ extension (tree: Tree)
5353
* throw IllegalCaptureRef otherwise
5454
*/
5555
def toCaptureRefs(using Context): List[CaptureRef] = tree match
56-
case ReachCapabilityApply(arg) =>
57-
arg.toCaptureRefs.map(_.reach)
58-
case ReadOnlyCapabilityApply(arg) =>
59-
arg.toCaptureRefs.map(_.readOnly)
60-
case CapsOfApply(arg) =>
61-
arg.toCaptureRefs
56+
// case ReachCapabilityApply(arg) =>
57+
// arg.toCaptureRefs.map(_.reach)
58+
// case ReadOnlyCapabilityApply(arg) =>
59+
// arg.toCaptureRefs.map(_.readOnly)
60+
// case CapsOfApply(arg) =>
61+
// arg.toCaptureRefs
6262
case _ => tree.tpe.dealiasKeepAnnots match
6363
case ref: CaptureRef if ref.isTrackableRef =>
6464
ref :: Nil
@@ -78,28 +78,20 @@ extension (tree: Tree)
7878
val refs =
7979
tree match
8080
case Apply(_: TypeApply, _) =>
81-
CaptureSet(tree.retainedElemsFromType*)
81+
CaptureSet(tree.retainedSet.retainedElements*)
8282
case _ =>
8383
CaptureSet(tree.retainedElems.flatMap(_.toCaptureRefs)*)
8484
// println(s"toCaptureSet: $tree -> $refs")
8585
tree.putAttachment(Captures, refs)
8686
refs
8787

88-
def retainedElemsFromType(using Context): List[CaptureRef] =
89-
def collectRefs(tp: Type): List[CaptureRef] = tp match
90-
case tp: CaptureRef if tp.isTrackableRef =>
91-
tp :: Nil
92-
case tp: TypeRef if tp.symbol.isType && tp.derivesFrom(defn.Caps_CapSet) =>
93-
tp :: Nil
94-
case OrType(tp1, tp2) =>
95-
collectRefs(tp1) ++ collectRefs(tp2)
96-
case _ =>
97-
Nil
88+
def retainedSet(using Context): Type =
9889
tree match
99-
case Apply(TypeApply(_, refs :: Nil), _) =>
100-
collectRefs(refs.tpe)
90+
case Apply(TypeApply(_, refs :: Nil), _) => refs.tpe
10191
case _ =>
102-
Nil
92+
if tree.symbol.maybeOwner == defn.RetainsCapAnnot
93+
then root.cap
94+
else NoType
10395

10496
/** The arguments of a @retains, @retainsCap or @retainsByName annotation */
10597
def retainedElems(using Context): List[Tree] = tree match
@@ -112,6 +104,21 @@ extension (tree: Tree)
112104

113105
extension (tp: Type)
114106

107+
def retainedElements(using Context): List[CaptureRef] = tp match
108+
case ReachCapability(tp1) =>
109+
tp1.reach :: Nil
110+
case ReadOnlyCapability(tp1) =>
111+
tp1.readOnly :: Nil
112+
case tp: CaptureRef if tp.isTrackableRef =>
113+
tp :: Nil
114+
case tp: TypeRef if tp.symbol.isType && tp.derivesFrom(defn.Caps_CapSet) =>
115+
tp :: Nil
116+
case OrType(tp1, tp2) =>
117+
tp1.retainedElements ++ tp2.retainedElements
118+
case _ =>
119+
if tp.isNothingType then Nil
120+
else throw IllegalCaptureRef(tp)
121+
115122
/** Is this type a CaptureRef that can be tracked?
116123
* This is true for
117124
* - all ThisTypes and all TermParamRef,
@@ -543,7 +550,7 @@ extension (cls: ClassSymbol)
543550
|| bc.is(CaptureChecked)
544551
&& bc.givenSelfType.dealiasKeepAnnots.match
545552
case CapturingType(_, refs) => refs.isAlwaysEmpty
546-
case RetainingType(_, refs) => refs.isEmpty
553+
case RetainingType(_, refs) => refs.retainedElements.isEmpty
547554
case selfType =>
548555
isCaptureChecking // At Setup we have not processed self types yet, so
549556
// unless a self type is explicitly given, we can't tell
@@ -661,7 +668,7 @@ class CleanupRetains(using Context) extends TypeMap:
661668
def apply(tp: Type): Type =
662669
tp match
663670
case AnnotatedType(tp, annot) if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot =>
664-
RetainingType(tp, Nil, byName = annot.symbol == defn.RetainsByNameAnnot)
671+
RetainingType(tp, defn.NothingType, byName = annot.symbol == defn.RetainsByNameAnnot)
665672
case _ => mapOver(tp)
666673

667674
/** A typemap that follows aliases and keeps their transformed results if
@@ -680,18 +687,18 @@ trait FollowAliasesMap(using Context) extends TypeMap:
680687
/** An extractor for `caps.reachCapability(ref)`, which is used to express a reach
681688
* capability as a tree in a @retains annotation.
682689
*/
683-
object ReachCapabilityApply:
684-
def unapply(tree: Apply)(using Context): Option[Tree] = tree match
685-
case Apply(reach, arg :: Nil) if reach.symbol == defn.Caps_reachCapability => Some(arg)
686-
case _ => None
690+
// object ReachCapabilityApply:
691+
// def unapply(tree: Apply)(using Context): Option[Tree] = tree match
692+
// case Apply(reach, arg :: Nil) if reach.symbol == defn.Caps_reachCapability => Some(arg)
693+
// case _ => None
687694

688695
/** An extractor for `caps.readOnlyCapability(ref)`, which is used to express a read-only
689696
* capability as a tree in a @retains annotation.
690697
*/
691-
object ReadOnlyCapabilityApply:
692-
def unapply(tree: Apply)(using Context): Option[Tree] = tree match
693-
case Apply(ro, arg :: Nil) if ro.symbol == defn.Caps_readOnlyCapability => Some(arg)
694-
case _ => None
698+
// object ReadOnlyCapabilityApply:
699+
// def unapply(tree: Apply)(using Context): Option[Tree] = tree match
700+
// case Apply(ro, arg :: Nil) if ro.symbol == defn.Caps_readOnlyCapability => Some(arg)
701+
// case _ => None
695702

696703
/** An extractor for `caps.capsOf[X]`, which is used to express a generic capture set
697704
* as a tree in a @retains annotation.

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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,24 @@ object CheckCaptures:
9999
* This check is performed at Typer.
100100
*/
101101
def checkWellformed(parent: Tree, ann: Tree)(using Context): Unit =
102-
def check(elem: Tree, pos: SrcPos): Unit = elem.tpe match
102+
def check(elem: Type, pos: SrcPos): Unit = elem match
103103
case ref: CaptureRef =>
104104
if !ref.isTrackableRef then
105105
report.error(em"$elem cannot be tracked since it is not a parameter or local value", pos)
106106
case tpe =>
107107
report.error(em"$elem: $tpe is not a legal element of a capture set", pos)
108-
for elem <- ann.retainedElems do
108+
for elem <- ann.retainedSet.retainedElements do
109109
elem match
110-
case CapsOfApply(arg) =>
111-
def isLegalCapsOfArg =
112-
arg.symbol.isType && arg.symbol.info.derivesFrom(defn.Caps_CapSet)
113-
if !isLegalCapsOfArg then
114-
report.error(
115-
em"""$arg is not a legal prefix for `^` here,
116-
|is must be a type parameter or abstract type with a caps.CapSet upper bound.""",
117-
elem.srcPos)
118-
case ReachCapabilityApply(arg) => check(arg, elem.srcPos)
119-
case ReadOnlyCapabilityApply(arg) => check(arg, elem.srcPos)
120-
case _ => check(elem, elem.srcPos)
110+
case ref: TypeRef =>
111+
val refSym = ref.symbol
112+
if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then
113+
report.error(em"$elem is not a legal element of a capture set", ann.srcPos)
114+
case ReachCapability(ref) =>
115+
check(ref, ann.srcPos)
116+
case ReadOnlyCapability(ref) =>
117+
check(ref, ann.srcPos)
118+
case _ =>
119+
check(elem, ann.srcPos)
121120

122121
/** Under the sealed policy, report an error if some part of `tp` contains the
123122
* root capability in its capture set or if it refers to a type parameter that

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,22 @@ import Decorators.i
1212
*/
1313
object RetainingType:
1414

15-
def apply(tp: Type, refs: List[Tree], byName: Boolean = false)(using Context): Type =
15+
// def apply(tp: Type, refs: List[CaptureRef], byName: Boolean = false)(using Context): Type = ???
16+
17+
def apply(tp: Type, typeRefs: Type, byName: Boolean = false)(using Context): Type =
1618
val annotCls = if byName then defn.RetainsByNameAnnot else defn.RetainsAnnot
17-
val annotTree =
18-
New(annotCls.typeRef,
19-
Typed(
20-
SeqLiteral(refs, TypeTree(defn.AnyType)),
21-
TypeTree(defn.RepeatedParamClass.typeRef.appliedTo(defn.AnyType))) :: Nil)
19+
val annotTree = New(AppliedType(annotCls.typeRef, defn.NothingType :: Nil), Nil)
2220
AnnotatedType(tp, Annotation(annotTree))
2321

24-
def unapply(tp: AnnotatedType)(using Context): Option[(Type, List[Tree])] =
22+
def unapply(tp: AnnotatedType)(using Context): Option[(Type, Type)] =
2523
val sym = tp.annot.symbol
2624
if sym.isRetainsLike then
2725
tp.annot match
2826
case _: CaptureAnnotation =>
2927
assert(ctx.mode.is(Mode.IgnoreCaptures), s"bad retains $tp at ${ctx.phase}")
3028
None
3129
case ann =>
32-
Some((tp.parent, ann.tree.retainedElems))
30+
Some((tp.parent, ann.tree.retainedSet))
3331
else
3432
None
3533
end RetainingType

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
790790
case CapturingType(_, refs) =>
791791
!refs.isAlwaysEmpty
792792
case RetainingType(parent, refs) =>
793-
!refs.isEmpty
793+
!refs.retainedElements.isEmpty
794794
case tp: (TypeRef | AppliedType) =>
795795
val sym = tp.typeSymbol
796796
if sym.isClass
@@ -836,7 +836,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
836836
&& !refs.isUniversal // if refs is {cap}, an added variable would not change anything
837837
case RetainingType(parent, refs) =>
838838
needsVariable(parent)
839-
&& !refs.tpes.exists:
839+
&& !refs.retainedElements.exists:
840840
case ref: TermRef => ref.isCap
841841
case _ => false
842842
case AnnotatedType(parent, _) =>
@@ -931,8 +931,8 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
931931
* @param tpt the tree for which an error or warning should be reported
932932
*/
933933
private def checkWellformed(parent: Type, ann: Tree, tpt: Tree)(using Context): Unit =
934-
capt.println(i"checkWF post $parent ${ann.retainedElems} in $tpt")
935-
var retained = ann.retainedElems.toArray
934+
capt.println(i"checkWF post $parent ${ann.retainedSet} in $tpt")
935+
var retained = ann.retainedSet.retainedElems.toArray
936936
for i <- 0 until retained.length do
937937
val refTree = retained(i)
938938
val refs =
@@ -942,8 +942,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
942942
Nil
943943
for ref <- refs do
944944
def pos =
945-
if refTree.span.exists then refTree.srcPos
946-
else if ann.span.exists then ann.srcPos
945+
if ann.span.exists then ann.srcPos
947946
else tpt.srcPos
948947

949948
def check(others: CaptureSet, dom: Type | CaptureSet): Unit =
@@ -959,14 +958,15 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
959958

960959
val others =
961960
for
962-
j <- 0 until retained.length if j != i
963-
r <- retained(j).toCaptureRefs
961+
j <- 0 until retainedRefs.length if j != i
962+
r = retainedRefs(j)
964963
if !r.isRootCapability
965964
yield r
966965
val remaining = CaptureSet(others*)
967966
check(remaining, remaining)
968967
end for
969-
end for
968+
catch case ex: IllegalCaptureRef =>
969+
report.error(em"Illegal capture reference: ${ex.getMessage.nn}", tpt.srcPos)
970970
end checkWellformed
971971

972972
/** Check well formed at post check time. We need to wait until after

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ class Definitions {
123123
HKTypeLambda(argParamNames :+ "R".toTypeName, argVariances :+ Covariant)(
124124
tl => List.fill(arity + 1)(TypeBounds.empty),
125125
tl => RetainingType(underlyingClass.typeRef.appliedTo(tl.paramRefs),
126-
ref(captureRoot.termRef) :: Nil)
126+
captureRoot.termRef)
127127
))
128128
else
129129
val cls = denot.asClass.classSymbol

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
178178
toTextCaptureRef(ref.typeOpt)
179179
case TypeApply(fn, arg :: Nil) if fn.symbol == defn.Caps_capsOf =>
180180
toTextRetainedElem(arg)
181-
case ReachCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ "*"
182-
case ReadOnlyCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ ".rd"
181+
// case ReachCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ "*"
182+
// case ReadOnlyCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ ".rd"
183183
case _ => toText(ref)
184184

185185
private def toTextRetainedElems[T <: Untyped](refs: List[Tree[T]]): Text =
@@ -287,9 +287,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
287287
&& refs.isReadOnly
288288
then toText(parent)
289289
else toTextCapturing(parent, refs, boxText)
290-
case tp @ RetainingType(parent, refs) =>
290+
case tp @ RetainingType(parent, refsType) =>
291+
val refs = refsType.retainedElements
291292
if Feature.ccEnabledSomewhere then
292-
toTextCapturing(parent, refs, "") ~ Str("R").provided(printDebug)
293+
toTextCapturing(parent, refs.map(r => ast.tpd.TypeTree(r)), "") ~ Str("R").provided(printDebug)
293294
else toText(parent)
294295
case tp: PreviousErrorType if ctx.settings.XprintTypes.value =>
295296
"<error>" // do not print previously reported error message because they may try to print this error type again recursively

library/src/scala/annotation/retains.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ package scala.annotation
1212
* non-standard capturing type syntax.
1313
*/
1414
@experimental
15-
class retains[Args](xs: (Any @retainsArg)*) extends annotation.StaticAnnotation
15+
class retains[Elems] extends annotation.StaticAnnotation
1616

1717
/** Equivalent in meaning to `@retains(cap)`, but consumes less bytecode.
1818
*/
1919
@experimental
20-
class retainsCap() extends annotation.StaticAnnotation
20+
class retainsCap extends annotation.StaticAnnotation
2121
// This special case is needed to be able to load standard library modules without
2222
// cyclic reference errors. Specifically, load sequences involving IterableOnce.
2323

library/src/scala/annotation/retainsByName.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ package scala.annotation
22

33
/** An annotation that indicates capture of an enclosing by-name type
44
*/
5-
@experimental class retainsByName[Args](xs: (Any@retainsArg)*) extends annotation.StaticAnnotation
5+
@experimental class retainsByName[Elems] extends annotation.StaticAnnotation
66

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
import language.experimental.captureChecking
12
import annotation.retains
3+
import annotation.retainsCap
4+
25
object Test:
36

4-
def f[A <: Matchable @retains(caps.cap)](x: A): Matchable = x // error
7+
def f[A <: Matchable @retains[caps.cap.type]](x: A): Matchable = x // error
8+
9+
def g[A <: Matchable @retainsCap](x: A): Matchable = x // error
510

tests/pos-custom-args/captures/cc-expand.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ object Test:
55
class B
66
class C
77
class CTC
8-
type CT = CTC @retains(caps.cap)
8+
type CT = CTC @retains[caps.cap.type]
99

1010
def test(ct: CT, dt: CT) =
1111

@@ -17,6 +17,6 @@ object Test:
1717

1818
def x4: (x: A @retains(ct)) -> B -> C = ???
1919

20-
def x5: A -> (x: B @retains(ct)) -> () -> C @retains(dt) = ???
21-
def x6: A -> (x: B @retains(ct)) -> (() -> C @retains(dt)) @retains(x, dt) = ???
22-
def x7: A -> (x: B @retains(ct)) -> (() -> C @retains(dt)) @retains(x) = ???
20+
def x5: A -> (x: B @retains[ct.type]) -> () -> C @retains(dt) = ???
21+
def x6: A -> (x: B @retains[ct.type]) -> (() -> C @retains[dt.type]) @retains[x.type | dt.type] = ???
22+
def x7: A -> (x: B @retains[ct.type]) -> (() -> C @retains[dt.type]) @retains[x.type] = ???

0 commit comments

Comments
 (0)