Skip to content

Commit

Permalink
Follow span of function types when computing captureSetOfInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
odersky committed Jul 4, 2023
1 parent d07282d commit 9c96538
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 28 deletions.
63 changes: 37 additions & 26 deletions compiler/src/dotty/tools/dotc/cc/CaptureSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -846,34 +846,45 @@ object CaptureSet:
/** The capture set of the type underlying a CaptureRef */
def ofInfo(ref: CaptureRef)(using Context): CaptureSet = ref match
case ref: TermRef if ref.isRootCapability => ref.singletonCaptureSet
case _ => ofType(ref.underlying)
case _ => ofType(ref.underlying, followResult = true)

/** Capture set of a type */
def ofType(tp: Type)(using Context): CaptureSet =
def recur(tp: Type): CaptureSet = tp.dealias match
case tp: TermRef =>
tp.captureSet
case tp: TermParamRef =>
tp.captureSet
case _: TypeRef =>
if tp.classSymbol.hasAnnotation(defn.CapabilityAnnot) then universal else empty
case _: TypeParamRef =>
empty
case CapturingType(parent, refs) =>
recur(parent) ++ refs
case AppliedType(tycon, args) =>
val cs = recur(tycon)
tycon.typeParams match
case tparams @ (LambdaParam(tl, _) :: _) => cs.substParams(tl, args)
case _ => cs
case tp: TypeProxy =>
recur(tp.underlying)
case AndType(tp1, tp2) =>
recur(tp1) ** recur(tp2)
case OrType(tp1, tp2) =>
recur(tp1) ++ recur(tp2)
case _ =>
empty
def ofType(tp: Type, followResult: Boolean)(using Context): CaptureSet =
def recur(tp: Type): CaptureSet = trace(i"ofType $tp, ${tp.getClass} $followResult", show = true):
tp.dealias match
case tp: TermRef =>
tp.captureSet
case tp: TermParamRef =>
tp.captureSet
case _: TypeRef =>
if tp.classSymbol.hasAnnotation(defn.CapabilityAnnot) then universal else empty
case _: TypeParamRef =>
empty
case CapturingType(parent, refs) =>
recur(parent) ++ refs
case tpd @ RefinedType(parent, _, rinfo: MethodType)
if followResult && defn.isFunctionType(tpd) =>
ofType(parent, followResult = false) // pick up capture set from parent type
++ (recur(rinfo.resType) // add capture set of result
-- CaptureSet(rinfo.paramRefs.filter(_.isTracked)*)) // but disregard bound parameters
case tpd @ AppliedType(tycon, args) =>
if followResult && defn.isNonRefinedFunction(tpd) then
recur(args.last)
// must be (pure) FunctionN type since ImpureFunctions have already
// been eliminated in selector's dealias. Use capture set of result.
else
val cs = recur(tycon)
tycon.typeParams match
case tparams @ (LambdaParam(tl, _) :: _) => cs.substParams(tl, args)
case _ => cs
case tp: TypeProxy =>
recur(tp.underlying)
case AndType(tp1, tp2) =>
recur(tp1) ** recur(tp2)
case OrType(tp1, tp2) =>
recur(tp1) ++ recur(tp2)
case _ =>
empty
recur(tp)
.showing(i"capture set of $tp = $result", capt)

Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -854,8 +854,9 @@ class CheckCaptures extends Recheck, SymTransformer:
actual match
case ref: CaptureRef if ref.isTracked =>
actualw match
case CapturingType(p, refs) =>
case CapturingType(p, refs) if ref.singletonCaptureSet.mightSubcapture(refs) =>
actualw = actualw.derivedCapturingType(p, ref.singletonCaptureSet)
.showing(i"improve $actualw to $result", capt)
// given `a: C T`, improve `C T` to `{a} T`
case _ =>
case _ =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1561,7 +1561,7 @@ object Types {
}

/** The capture set of this type. Overridden and cached in CaptureRef */
def captureSet(using Context): CaptureSet = CaptureSet.ofType(this)
def captureSet(using Context): CaptureSet = CaptureSet.ofType(this, followResult = false)

// ----- Normalizing typerefs over refined types ----------------------------

Expand Down
5 changes: 5 additions & 0 deletions tests/pos-custom-args/captures/dependent-pure.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import language.experimental.captureChecking
class ContextCls
type Context = ContextCls^

class Filtered(p: (c: Context) ?-> () ->{c} Boolean) extends Pure

0 comments on commit 9c96538

Please sign in to comment.