Skip to content

Commit 99f431e

Browse files
authored
Expand Capability types T to T^ only if no explicit capture set is given (#21375)
If C is a class extending caps.Capability we used to always expand C to C^, even if there was an explicitly given capture set. For instance `C^{x}` got expanded to `C^{cap}^{x}` which caused a redundant capture x warning. We now do this expansion only if there is no explicitly given capture set. @natsukagami I hope this helps the Async use case.
2 parents bcf5d6a + 5dd0bf7 commit 99f431e

File tree

4 files changed

+30
-7
lines changed

4 files changed

+30
-7
lines changed

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ class CheckCaptures extends Recheck, SymTransformer:
632632
def addParamArgRefinements(core: Type, initCs: CaptureSet): (Type, CaptureSet) =
633633
var refined: Type = core
634634
var allCaptures: CaptureSet =
635-
if core.derivesFromCapability then CaptureSet.universal else initCs
635+
if core.derivesFromCapability then defn.universalCSImpliedByCapability else initCs
636636
for (getterName, argType) <- mt.paramNames.lazyZip(argTypes) do
637637
val getter = cls.info.member(getterName).suchThat(_.isRefiningParamAccessor).symbol
638638
if !getter.is(Private) && getter.hasTrackedParts then
@@ -809,7 +809,7 @@ class CheckCaptures extends Recheck, SymTransformer:
809809
val localSet = capturedVars(sym)
810810
if !localSet.isAlwaysEmpty then
811811
curEnv = Env(sym, EnvKind.Regular, localSet, curEnv)
812-
812+
813813
// ctx with AssumedContains entries for each Contains parameter
814814
val bodyCtx =
815815
var ac = CaptureSet.assumedContains
@@ -828,7 +828,7 @@ class CheckCaptures extends Recheck, SymTransformer:
828828
interpolateVarsIn(tree.tpt)
829829
curEnv = saved
830830
end recheckDefDef
831-
831+
832832
/** If val or def definition with inferred (result) type is visible
833833
* in other compilation units, check that the actual inferred type
834834
* conforms to the expected type where all inferred capture sets are dropped.

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

+12-4
Original file line numberDiff line numberDiff line change
@@ -299,24 +299,32 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
299299
CapturingType(fntpe, cs, boxed = false)
300300
else fntpe
301301

302+
def stripImpliedCaptureSet(tp: Type): Type = tp match
303+
case tp @ CapturingType(parent, refs)
304+
if (refs eq defn.universalCSImpliedByCapability) && !tp.isBoxedCapturing =>
305+
parent
306+
case tp @ CapturingType(parent, refs) => tp
307+
case _ => tp
308+
302309
def apply(t: Type) =
303310
t match
304311
case t @ CapturingType(parent, refs) =>
305-
t.derivedCapturingType(this(parent), refs)
312+
t.derivedCapturingType(stripImpliedCaptureSet(this(parent)), refs)
306313
case t @ AnnotatedType(parent, ann) =>
307314
val parent1 = this(parent)
308315
if ann.symbol.isRetains then
316+
val parent2 = stripImpliedCaptureSet(parent1)
309317
for tpt <- tptToCheck do
310-
checkWellformedLater(parent1, ann.tree, tpt)
311-
CapturingType(parent1, ann.tree.toCaptureSet)
318+
checkWellformedLater(parent2, ann.tree, tpt)
319+
CapturingType(parent2, ann.tree.toCaptureSet)
312320
else
313321
t.derivedAnnotatedType(parent1, ann)
314322
case throwsAlias(res, exc) =>
315323
this(expandThrowsAlias(res, exc, Nil))
316324
case t =>
317325
// Map references to capability classes C to C^
318326
if t.derivesFromCapability && !t.isSingleton && t.typeSymbol != defn.Caps_Exists
319-
then CapturingType(t, CaptureSet.universal, boxed = false)
327+
then CapturingType(t, defn.universalCSImpliedByCapability, boxed = false)
320328
else normalizeCaptures(mapOver(t))
321329
end toCapturing
322330

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

+3
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,9 @@ class Definitions {
10051005
@tu lazy val Caps_ContainsTrait: TypeSymbol = CapsModule.requiredType("Contains")
10061006
@tu lazy val Caps_containsImpl: TermSymbol = CapsModule.requiredMethod("containsImpl")
10071007

1008+
/** The same as CaptureSet.universal but generated implicitly for references of Capability subtypes */
1009+
@tu lazy val universalCSImpliedByCapability = CaptureSet(captureRoot.termRef)
1010+
10081011
@tu lazy val PureClass: Symbol = requiredClass("scala.Pure")
10091012

10101013
// Annotation base classes
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//> using options -Werror
2+
import caps.Capability
3+
4+
trait Buffer[T] extends Capability:
5+
def append(x: T): this.type
6+
7+
def f(buf: Buffer[Int]) =
8+
val buf1 = buf.append(1).append(2)
9+
val buf2: Buffer[Int]^{buf1} = buf1
10+
11+
12+

0 commit comments

Comments
 (0)