Skip to content

Commit 6009cce

Browse files
committed
Update reference and member searching and tests
1 parent d81ec1f commit 6009cce

37 files changed

+99
-121
lines changed

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

-3
Original file line numberDiff line numberDiff line change
@@ -542,9 +542,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
542542
annot.putAttachment(RetainsAnnot, ())
543543
Annotated(parent, annot)
544544

545-
def makeCapsOf(tp: RefTree)(using Context): Tree =
546-
TypeApply(capsInternalDot(nme.capsOf), tp :: Nil)
547-
548545
// Capture set variable `[C^]` becomes: `[C >: CapSet <: CapSet^{cap}]`
549546
def makeCapsBound()(using Context): TypeBoundsTree =
550547
TypeBoundsTree(

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

-8
Original file line numberDiff line numberDiff line change
@@ -807,14 +807,6 @@ trait FollowAliasesMap(using Context) extends TypeMap:
807807
// case Apply(ro, arg :: Nil) if ro.symbol == defn.Caps_readOnlyCapability => Some(arg)
808808
// case _ => None
809809

810-
/** An extractor for `caps.capsOf[X]`, which is used to express a generic capture set
811-
* as a tree in a @retains annotation.
812-
*/
813-
object CapsOfApply:
814-
def unapply(tree: TypeApply)(using Context): Option[Tree] = tree match
815-
case TypeApply(capsOf, arg :: Nil) if capsOf.symbol == defn.Caps_capsOf => Some(arg)
816-
case _ => None
817-
818810
abstract class AnnotatedCapability(annotCls: Context ?=> ClassSymbol):
819811
def apply(tp: Type)(using Context): AnnotatedType =
820812
assert(tp.isTrackableRef, i"not a trackable ref: $tp")

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

-3
Original file line numberDiff line numberDiff line change
@@ -998,9 +998,6 @@ class Definitions {
998998
@tu lazy val Caps_Capability: ClassSymbol = requiredClass("scala.caps.Capability")
999999
@tu lazy val Caps_CapSet: ClassSymbol = requiredClass("scala.caps.CapSet")
10001000
@tu lazy val CapsInternalModule: Symbol = requiredModule("scala.caps.internal")
1001-
@tu lazy val Caps_reachCapability: TermSymbol = CapsInternalModule.requiredMethod("reachCapability")
1002-
@tu lazy val Caps_readOnlyCapability: TermSymbol = CapsInternalModule.requiredMethod("readOnlyCapability")
1003-
@tu lazy val Caps_capsOf: TermSymbol = CapsInternalModule.requiredMethod("capsOf")
10041001
@tu lazy val CapsUnsafeModule: Symbol = requiredModule("scala.caps.unsafe")
10051002
@tu lazy val Caps_unsafeAssumePure: Symbol = CapsUnsafeModule.requiredMethod("unsafeAssumePure")
10061003
@tu lazy val Caps_unsafeAssumeSeparate: Symbol = CapsUnsafeModule.requiredMethod("unsafeAssumeSeparate")

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ object Flags {
380380
/** Tracked modifier for class parameter / a class with some tracked parameters */
381381
val (Tracked @ _, _, Dependent @ _) = newFlags(46, "tracked")
382382

383+
val (CaptureParam @ _, _, _) = newFlags(47, "capture-param")
384+
383385
// ------------ Flags following this one are not pickled ----------------------------------
384386

385387
/** Symbol is not a member of its owner */
@@ -449,7 +451,7 @@ object Flags {
449451

450452
/** Flags representing source modifiers */
451453
private val CommonSourceModifierFlags: FlagSet =
452-
commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent, Erased)
454+
commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent, Erased, CaptureParam)
453455

454456
val TypeSourceModifierFlags: FlagSet =
455457
CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque | Open
@@ -469,7 +471,7 @@ object Flags {
469471
val FromStartFlags: FlagSet = commonFlags(
470472
Module, Package, Deferred, Method, Case, Enum, Param, ParamAccessor,
471473
Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic,
472-
OuterOrCovariant, LabelOrContravariant, CaseAccessor, Tracked,
474+
OuterOrCovariant, LabelOrContravariant, CaseAccessor, Tracked, CaptureParam,
473475
Extension, NonMember, Implicit, Given, Permanent, Synthetic, Exported,
474476
SuperParamAliasOrScala2x, Inline, Macro, ConstructorProxy, Invisible)
475477

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

+13
Original file line numberDiff line numberDiff line change
@@ -317,4 +317,17 @@ object NamerOps:
317317
ann.tree match
318318
case ast.tpd.WitnessNamesAnnot(witnessNames) =>
319319
addContextBoundCompanionFor(sym, witnessNames, Nil)
320+
321+
/** Add a dummy term symbol for a type def that has capture parameter flag.
322+
* The dummy symbol has the same name as the original type symbol and is stable.
323+
*
324+
* @param param the original type symbol of the capture parameter
325+
*/
326+
def addDummyTermCaptureParam(param: Symbol)(using Context): Unit =
327+
val name = param.name.toTermName
328+
val flags = (param.flagsUNSAFE & AccessFlags).toTermFlags | CaptureParam | StableRealizable | Synthetic
329+
val dummy = newSymbol(param.owner, name, flags, param.typeRef)
330+
typr.println(i"Adding dummy term symbol $dummy for $param, flags = $flags")
331+
ctx.enter(dummy)
332+
320333
end NamerOps

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

-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,6 @@ object StdNames {
445445
val canEqual_ : N = "canEqual"
446446
val canEqualAny : N = "canEqualAny"
447447
val caps: N = "caps"
448-
val capsOf: N = "capsOf"
449448
val captureChecking: N = "captureChecking"
450449
val checkInitialized: N = "checkInitialized"
451450
val classOf: N = "classOf"

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

+3
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ class SymUtils:
9090
def isContextBoundCompanion(using Context): Boolean =
9191
self.is(Synthetic) && self.infoOrCompleter.typeSymbol == defn.CBCompanion
9292

93+
def isDummyCaptureParam(using Context): Boolean =
94+
self.is(Synthetic) && self.is(CaptureParam)
95+
9396
/** Is this a case class for which a product mirror is generated?
9497
* Excluded are value classes, abstract classes and case classes with more than one
9598
* parameter section.

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,8 @@ object Types extends TypeUtils {
748748
case tp: ClassInfo => tp.appliedRef
749749
case _ => widenIfUnstable
750750
}
751-
findMember(name, pre, required, excluded)
751+
val excluded1 = if ctx.mode.is(Mode.InCaptureSet) then excluded else excluded | CaptureParam
752+
findMember(name, pre, required, excluded1)
752753
}
753754

754755
/** The implicit members with given name. If there are none and the denotation

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

-4
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,6 @@ class PlainPrinter(_ctx: Context) extends Printer {
173173
private def toTextRetainedElem[T <: Untyped](ref: Tree[T]): Text = ref match
174174
case ref: RefTree[?] if ref.typeOpt.exists =>
175175
toTextCaptureRef(ref.typeOpt)
176-
case TypeApply(fn, arg :: Nil) if fn.symbol == defn.Caps_capsOf =>
177-
toTextRetainedElem(arg)
178-
// case ReachCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ "*"
179-
// case ReadOnlyCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ ".rd"
180176
case _ => toText(ref)
181177

182178
private def toTextRetainedElems[T <: Untyped](refs: List[Tree[T]]): Text =

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

+2
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,8 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
348348
unusable(ConstructorProxyNotValue(_))
349349
else if tree.symbol.isContextBoundCompanion then
350350
unusable(ContextBoundCompanionNotValue(_))
351+
else if tree.symbol.isDummyCaptureParam then
352+
throw new Exception(s"Dummy capture param ${tree.symbol} should not be used as a value")
351353
else
352354
tree
353355

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,9 @@ object TreeChecker {
387387
}
388388

389389
def isSymWithoutDef(sym: Symbol)(using Context): Boolean =
390-
sym.is(ConstructorProxy) || sym.isContextBoundCompanion
390+
sym.is(ConstructorProxy)
391+
|| sym.isContextBoundCompanion
392+
|| sym.isDummyCaptureParam
391393

392394
/** Exclude from double definition checks any erased symbols that were
393395
* made `private` in phase `UnlinkErasedDecls`. These symbols will be removed

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

+3
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,9 @@ class Namer { typer: Typer =>
11321132
ensureUpToDate(sym.typeRef, dummyInfo1)
11331133
if (dummyInfo2 `ne` dummyInfo1) ensureUpToDate(sym.typeRef, dummyInfo2)
11341134

1135+
if sym.info.derivesFrom(defn.Caps_CapSet) then
1136+
addDummyTermCaptureParam(sym)(using ictx)
1137+
11351138
sym.info
11361139
end typeSig
11371140
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,8 @@ object RefChecks {
473473
}
474474

475475
def emitOverrideError(fullmsg: Message) =
476-
if (!(hasErrors && member.is(Synthetic) && member.is(Module))) {
477-
// suppress errors relating toi synthetic companion objects if other override
476+
if (!(hasErrors && member.is(Synthetic) && member.is(Module) || member.isDummyCaptureParam)) {
477+
// suppress errors relating to synthetic companion objects if other override
478478
// errors (e.g. relating to the companion class) have already been reported.
479479
if (member.owner == clazz) report.error(fullmsg, member.srcPos)
480480
else mixinOverrideErrors += new MixinOverrideError(member, fullmsg)

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ trait TypeAssigner {
162162
// if this fails.
163163
ctx.javaFindMember(name, pre, lookInCompanion = false)
164164
else
165-
qualType.findMember(name, pre)
165+
val excluded = if ctx.mode.is(Mode.InCaptureSet) then EmptyFlags else CaptureParam
166+
qualType.findMember(name, pre, excluded = excluded)
166167

167168
if reallyExists(mbr) && NamedType.validPrefix(qualType) then qualType.select(name, mbr)
168169
else if qualType.isErroneous || name.toTermName == nme.ERROR then UnspecifiedErrorType

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

+5-18
Original file line numberDiff line numberDiff line change
@@ -626,8 +626,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
626626
val saved2 = foundUnderScala2
627627
unimported = Set.empty
628628
foundUnderScala2 = NoType
629+
val excluded = if ctx.mode.is(Mode.InCaptureSet) then EmptyFlags else CaptureParam
629630
try
630-
val found = findRef(name, pt, EmptyFlags, EmptyFlags, tree.srcPos)
631+
val found = findRef(name, pt, EmptyFlags, excluded, tree.srcPos)
631632
if foundUnderScala2.exists && !(foundUnderScala2 =:= found) then
632633
report.migrationWarning(
633634
em"""Name resolution will change.
@@ -715,11 +716,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
715716
&& ctx.owner.owner.unforcedDecls.lookup(tree.name).exists
716717
then // we are in the arguments of a this(...) constructor call
717718
errorTree(tree, em"$tree is not accessible from constructor arguments")
718-
else if name.isTermName && 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)
722-
typed(untpd.cpy.Ident(tree)(name.toTypeName), pt)
723719
else
724720
errorTree(tree, MissingIdent(tree, kind, name, pt))
725721
end typedIdent
@@ -925,13 +921,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
925921
typedCBSelect(tree0, pt, qual)
926922
else EmptyTree
927923

928-
// Otherwise, if we are in a capture set, try to type it as a capture variable
929-
// reference (as selecting a type name).
930-
def trySelectTypeInCaptureSet() =
931-
if tree0.name.isTermName && ctx.mode.is(Mode.InCaptureSet) then
932-
typedSelectWithAdapt(untpd.cpy.Select(tree0)(qual, tree0.name.toTypeName), pt, qual)
933-
else EmptyTree
934-
935924
// Otherwise, report an error
936925
def reportAnError() =
937926
assignType(tree,
@@ -953,7 +942,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
953942
.orElse(tryDynamic())
954943
.orElse(trySelectable())
955944
.orElse(tryCBCompanion())
956-
.orElse(trySelectTypeInCaptureSet())
957945
.orElse(reportAnError())
958946
end typedSelectWithAdapt
959947

@@ -2541,10 +2529,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25412529

25422530
def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(using Context): Tree = {
25432531
val ref1 = typedExpr(tree.ref, SingletonTypeProto)
2544-
// println(i"typed singleton type $ref1 : ${ref1.tpe}, ${ctx.mode.is(Mode.InCaptureSet)}")
2545-
ref1.tpe match
2546-
case _: TypeRef if ctx.mode.is(Mode.InCaptureSet) => return ref1
2547-
case _ =>
2532+
if ctx.mode.is(Mode.InCaptureSet) && ref1.symbol.is(Flags.CaptureParam) then
2533+
// println(s"typedSingletonTypeTree: $ref1 -> ${ref1.tpe.widen}")
2534+
return Ident(ref1.tpe.widen.asInstanceOf[TypeRef]).withSpan(tree.span)
25482535
checkStable(ref1.tpe, tree.srcPos, "singleton type")
25492536
assignType(cpy.SingletonTypeTree(tree)(ref1), ref1)
25502537
}

library/src/scala/annotation/retains.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package scala.annotation
22

33
/** An annotation that indicates capture of a set of references under -Ycc.
44
*
5-
* T @retains(x, y, z)
5+
* T @retains[x.type | y.type | z.type]
66
*
77
* is the internal representation used for the capturing type
88
*
@@ -14,7 +14,7 @@ package scala.annotation
1414
@experimental
1515
class retains[Elems] extends annotation.StaticAnnotation
1616

17-
/** Equivalent in meaning to `@retains(cap)`, but consumes less bytecode.
17+
/** Equivalent in meaning to `@retains[cap.type]`, but consumes less bytecode.
1818
*/
1919
@experimental
2020
class retainsCap extends annotation.StaticAnnotation

library/src/scala/caps/package.scala

-18
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,6 @@ sealed trait Exists extends Capability
8888
@experimental
8989
object internal:
9090

91-
/** A wrapper indicating a type variable in a capture argument list of a
92-
* @retains annotation. E.g. `^{x, Y^}` is represented as `@retains(x, capsOf[Y])`.
93-
*/
94-
@compileTimeOnly("Should be be used only internally by the Scala compiler")
95-
def capsOf[CS >: CapSet <: CapSet @retainsCap]: Any = ???
96-
97-
/** Reach capabilities x* which appear as terms in @retains annotations are encoded
98-
* as `caps.reachCapability(x)`. When converted to CaptureRef types in capture sets
99-
* they are represented as `x.type @annotation.internal.reachCapability`.
100-
*/
101-
extension (x: Any) def reachCapability: Any = x
102-
103-
/** Read-only capabilities x.rd which appear as terms in @retains annotations are encoded
104-
* as `caps.readOnlyCapability(x)`. When converted to CaptureRef types in capture sets
105-
* they are represented as `x.type @annotation.internal.readOnlyCapability`.
106-
*/
107-
extension (x: Any) def readOnlyCapability: Any = x
108-
10991
/** An internal annotation placed on a refinement created by capture checking.
11092
* Refinements with this annotation unconditionally override any
11193
* info from the parent type, so no intersection needs to be formed.

tests/disabled/neg-custom-args/captures/capt-wf.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
// No longer valid
22
class C
3-
type Cap = C @retains(caps.cap)
4-
type Top = Any @retains(caps.cap)
3+
type Cap = C @retains[caps.cap.type]
4+
type Top = Any @retains[caps.cap.type]
55

6-
type T = (x: Cap) => List[String @retains(x)] => Unit // error
7-
val x: (x: Cap) => Array[String @retains(x)] = ??? // error
6+
type T = (x: Cap) => List[String @retains[x.type]] => Unit // error
7+
val x: (x: Cap) => Array[String @retains[x.type]] = ??? // error
88
val y = x
99

1010
def test: Unit =
1111
def f(x: Cap) = // ok
12-
val g = (xs: List[String @retains(x)]) => ()
12+
val g = (xs: List[String @retains[x.type]]) => ()
1313
g
14-
def f2(x: Cap)(xs: List[String @retains(x)]) = ()
14+
def f2(x: Cap)(xs: List[String @retains[x.type]]) = ()
1515
val x = f // error
1616
val x2 = f2 // error
1717
val y = f(C()) // ok

tests/disabled/neg-custom-args/captures/try2.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import annotation.ability
55
@ability erased val canThrow: * = ???
66

77
class CanThrow[E <: Exception] extends Retains[canThrow.type]
8-
type Top = Any @retains(caps.cap)
8+
type Top = Any @retains[caps.cap.type]
99

1010
infix type throws[R, E <: Exception] = (erased CanThrow[E]) ?=> R
1111

tests/neg-custom-args/boxmap.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import annotation.retains
2-
type Top = Any @retains(caps.cap)
2+
type Top = Any @retains[caps.cap.type]
33

44
type Box[+T <: Top] = ([K <: Top] -> (T => K) -> K)
55

tests/neg-custom-args/captures/capt-depfun.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import annotation.retains
22

33

44
class C
5-
type Cap = C @retains(caps.cap)
5+
type Cap = C @retains[caps.cap.type]
66
class Str
77

88
def f(y: Cap, z: Cap) =
9-
def g(): C @retains(y, z) = ???
10-
val ac: ((x: Cap) => Str @retains(x) => Str @retains(x)) = ???
9+
def g(): C @retains[y.type | z.type] = ???
10+
val ac: ((x: Cap) => Str @retains[x.type] => Str @retains[x.type]) = ???
1111
val dc: ((Str^{y, z}) => Str^{y, z}) = ac(g()) // error // error: separatioon

tests/neg-custom-args/captures/capt-depfun2.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import annotation.retains
22
class C
3-
type Cap = C @retains(caps.cap)
3+
type Cap = C @retains[caps.cap.type]
44
class Str
55

66
def f(y: Cap, z: Cap) =
7-
def g(): C @retains(y, z) = ???
8-
val ac: ((x: Cap) => Array[Str @retains(x)]) = ???
7+
def g(): C @retains[y.type | z.type] = ???
8+
val ac: ((x: Cap) => Array[Str @retains[x.type]]) = ???
99
val dc = ac(g()) // error: Needs explicit type Array[? >: Str <: {y, z} Str]
1010
// This is a shortcoming of rechecking since the originally inferred
1111
// type is `Array[Str]` and the actual type after rechecking

tests/neg-custom-args/captures/capt-test.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import annotation.retains
22
import language.experimental.erasedDefinitions
33

44
class CT[E <: Exception]
5-
type CanThrow[E <: Exception] = CT[E] @retains(caps.cap)
6-
type Top = Any @retains(caps.cap)
5+
type CanThrow[E <: Exception] = CT[E] @retains[caps.cap.type]
6+
type Top = Any @retains[caps.cap.type]
77

88
infix type throws[R, E <: Exception] = (erased CanThrow[E]) ?=> R
99

@@ -14,7 +14,7 @@ def raise[E <: Exception](e: E): Nothing throws E = throw e
1414
def foo(x: Boolean): Int throws Fail =
1515
if x then 1 else raise(Fail())
1616

17-
def handle[E <: Exception, R <: Top](op: (CT[E] @retains(caps.cap)) => R)(handler: E => R): R =
17+
def handle[E <: Exception, R <: Top](op: (CT[E] @retains[caps.cap.type]) => R)(handler: E => R): R =
1818
val x: CT[E] = ???
1919
try op(x)
2020
catch case ex: E => handler(ex)

tests/neg-custom-args/captures/capt-wf-typer.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ object foo
66

77
def test(c: Cap, other: String): Unit =
88
val x7: String^{c} = ??? // OK
9-
val x8: String @retains(x7 + x7) = ??? // error
10-
val x9: String @retains(foo) = ??? // error
9+
val x8: String @retains[x7 + x7] = ??? // error
10+
val x9: String @retains[foo] = ??? // error
1111
()

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
| reference (x : C^) is not included in the allowed capture set {}
4545
| of an enclosing function literal with expected type () -> box C^
4646
-- Error: tests/neg-custom-args/captures/capt1.scala:38:13 -------------------------------------------------------------
47-
38 | val z3 = h[(() -> Cap) @retains(x)](() => x)(() => C()) // error
47+
38 | val z3 = h[(() -> Cap) @retains[x.type]](() => x)(() => C()) // error
4848
| ^^^^^^^^^^^^^^^^^^^^^^^
4949
| Type variable X of method h cannot be instantiated to box () ->{x} C^ since
5050
| the part C^ of that type captures the root capability `cap`.

0 commit comments

Comments
 (0)