Skip to content

Miscellaneous CC fixes and tweaks #20564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ object ccConfig:
*/
inline val allowUnsoundMaps = false

/** If true, expand capability classes in Setup instead of treating them
* in adapt.
*/
val expandCapabilityInSetup = true

/** If true, use `sealed` as encapsulation mechanism instead of the
* previous global retriction that `cap` can't be boxed or unboxed.
*/
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/cc/CaptureSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,15 @@ sealed abstract class CaptureSet extends Showable:
case y: TermRef =>
(y.prefix eq x)
|| y.info.match
case y1: CaptureRef => x.subsumes(y1)
case y1: SingletonCaptureRef => x.subsumes(y1)
case _ => false
case MaybeCapability(y1) => x.stripMaybe.subsumes(y1)
case _ => false
|| x.match
case ReachCapability(x1) => x1.subsumes(y.stripReach)
case x: TermRef =>
x.info match
case x1: CaptureRef => x1.subsumes(y)
case x1: SingletonCaptureRef => x1.subsumes(y)
case _ => false
case _ => false

Expand Down Expand Up @@ -1058,7 +1058,7 @@ object CaptureSet:
case tp: TermParamRef =>
tp.captureSet
case tp: TypeRef =>
if tp.derivesFromCapability then universal // TODO: maybe return another value that indicates that the underltinf ref is maximal?
if !ccConfig.expandCapabilityInSetup && tp.derivesFromCapability then universal
else empty
case _: TypeParamRef =>
empty
Expand Down
3 changes: 0 additions & 3 deletions compiler/src/dotty/tools/dotc/cc/CapturingType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,13 @@ object CapturingType:

/** Smart constructor that
* - drops empty capture sets
* - drops a capability class expansion if it is further refined with another capturing type
* - fuses compatible capturing types.
* An outer type capturing type A can be fused with an inner capturing type B if their
* boxing status is the same or if A is boxed.
*/
def apply(parent: Type, refs: CaptureSet, boxed: Boolean = false)(using Context): Type =
if refs.isAlwaysEmpty then parent
else parent match
case parent @ CapturingType(parent1, refs1) if refs1 eq defn.expandedUniversalSet =>
apply(parent1, refs, boxed)
case parent @ CapturingType(parent1, refs1) if boxed || !parent.isBoxed =>
apply(parent1, refs ++ refs1, boxed)
case _ =>
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,9 @@ class CheckCaptures extends Recheck, SymTransformer:
/** If actual derives from caps.Capability, yet is not a capturing type itself,
* make its capture set explicit.
*/
private def makeCaptureSetExplicit(actual: Type)(using Context): Type = actual match
private def makeCaptureSetExplicit(actual: Type)(using Context): Type =
if ccConfig.expandCapabilityInSetup then actual
else actual match
case CapturingType(_, _) => actual
case _ if actual.derivesFromCapability =>
val cap: CaptureRef = actual match
Expand Down Expand Up @@ -1284,7 +1286,7 @@ class CheckCaptures extends Recheck, SymTransformer:
case ref: TermParamRef
if !allowed.contains(ref) && !seen.contains(ref) =>
seen += ref
if ref.underlying.isRef(defn.Caps_Capability) then
if ref.isMaxCapability then
report.error(i"escaping local reference $ref", tree.srcPos)
else
val widened = ref.captureSetOfInfo
Expand Down
14 changes: 7 additions & 7 deletions compiler/src/dotty/tools/dotc/cc/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,10 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
case t: TypeVar =>
this(t.underlying)
case t =>
recur(t)
// Map references to capability classes C to C^
if ccConfig.expandCapabilityInSetup && t.derivesFromCapability
then CapturingType(t, CaptureSet.universal, boxed = false)
else recur(t)
end expandAliases

val tp1 = expandAliases(tp) // TODO: Do we still need to follow aliases?
Expand Down Expand Up @@ -575,10 +578,8 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
!refs.isEmpty
case tp: (TypeRef | AppliedType) =>
val sym = tp.typeSymbol
if sym.isClass then
!sym.isPureClass
else
sym != defn.Caps_Capability && instanceCanBeImpure(tp.superType)
if sym.isClass then !sym.isPureClass
else instanceCanBeImpure(tp.superType)
case tp: (RefinedOrRecType | MatchType) =>
instanceCanBeImpure(tp.underlying)
case tp: AndType =>
Expand Down Expand Up @@ -711,8 +712,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:

if ref.captureSetOfInfo.elems.isEmpty then
report.error(em"$ref cannot be tracked since its capture set is empty", pos)
if parent.captureSet ne defn.expandedUniversalSet then
check(parent.captureSet, parent)
check(parent.captureSet, parent)

val others =
for j <- 0 until retained.length if j != i yield retained(j).toCaptureRef
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -998,7 +998,6 @@ class Definitions {
@tu lazy val Caps_unsafeBox: Symbol = CapsUnsafeModule.requiredMethod("unsafeBox")
@tu lazy val Caps_unsafeUnbox: Symbol = CapsUnsafeModule.requiredMethod("unsafeUnbox")
@tu lazy val Caps_unsafeBoxFunArg: Symbol = CapsUnsafeModule.requiredMethod("unsafeBoxFunArg")
@tu lazy val expandedUniversalSet: CaptureSet = CaptureSet(captureRoot.termRef)

@tu lazy val PureClass: Symbol = requiredClass("scala.Pure")

Expand Down
8 changes: 6 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1646,10 +1646,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
else
val resTpt = TypeTree(mt.nonDependentResultApprox).withSpan(body.span)
val paramTpts = appDef.termParamss.head.map(p => TypeTree(p.tpt.tpe).withSpan(p.tpt.span))
val funSym = defn.FunctionSymbol(numArgs, isContextual, isImpure)
val funSym = defn.FunctionSymbol(numArgs, isContextual)
val tycon = TypeTree(funSym.typeRef)
AppliedTypeTree(tycon, paramTpts :+ resTpt)
RefinedTypeTree(core, List(appDef), ctx.owner.asClass)
val res = RefinedTypeTree(core, List(appDef), ctx.owner.asClass)
if isImpure then
typed(untpd.makeRetaining(untpd.TypedSplice(res), Nil, tpnme.retainsCap), pt)
else
res
end typedDependent

args match {
Expand Down
7 changes: 6 additions & 1 deletion tests/neg-custom-args/captures/byname.check
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
-- Error: tests/neg-custom-args/captures/byname.scala:19:5 -------------------------------------------------------------
19 | h(g()) // error
| ^^^
| reference (cap2 : Cap) is not included in the allowed capture set {cap1}
| reference (cap2 : Cap^) is not included in the allowed capture set {cap1}
| of an enclosing function literal with expected type () ?->{cap1} I
-- Error: tests/neg-custom-args/captures/byname.scala:22:12 ------------------------------------------------------------
22 | h2(() => g())() // error
| ^^^
| reference (cap2 : Cap^) is not included in the allowed capture set {cap1}
| of an enclosing function literal with expected type () ->{cap1} I
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:4:2 -----------------------------------------
4 | def f() = if cap1 == cap1 then g else g // error
| ^
Expand Down
3 changes: 3 additions & 0 deletions tests/neg-custom-args/captures/byname.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ def test2(cap1: Cap, cap2: Cap): I^{cap1} =
def h(x: ->{cap1} I) = x // ok
h(f()) // OK
h(g()) // error
def h2(x: () ->{cap1} I) = x // ok
h2(() => f()) // OK
h2(() => g())() // error



2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/cc-this5.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Error: tests/neg-custom-args/captures/cc-this5.scala:16:20 ----------------------------------------------------------
16 | def f = println(c) // error
| ^
| (c : Cap) cannot be referenced here; it is not included in the allowed capture set {}
| (c : Cap^) cannot be referenced here; it is not included in the allowed capture set {}
| of the enclosing class A
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-this5.scala:21:15 -------------------------------------
21 | val x: A = this // error
Expand Down
4 changes: 4 additions & 0 deletions tests/neg-custom-args/captures/effect-swaps.check
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@
73 | fr.await.ok
|
| longer explanation available when compiling with `-explain`
-- Error: tests/neg-custom-args/captures/effect-swaps.scala:66:15 ------------------------------------------------------
66 | Result.make: // error
| ^^^^^^^^^^^
| escaping local reference contextual$9.type
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/effect-swaps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test[T, E](using Async) =
fr.await.ok

def fail4[T, E](fr: Future[Result[T, E]]^) =
Result.make: //lbl ?=> // should be error, escaping label from Result but infers Result[Any, Any]
Result.make: // error
Future: fut ?=>
fr.await.ok

Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/extending-cap-classes.check
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/extending-cap-classes.scala:13:15 ------------------------
13 | val z2: C1 = y2 // error
| ^^
| Found: (y2 : C2)^{y2}
| Found: (y2 : C2^)
| Required: C1
|
| longer explanation available when compiling with `-explain`
4 changes: 2 additions & 2 deletions tests/neg-custom-args/captures/i16725.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ type Wrapper[T] = [R] -> (f: T => R) -> R
def mk[T](x: T): Wrapper[T] = [R] => f => f(x)
def useWrappedIO(wrapper: Wrapper[IO]): () -> Unit =
() =>
wrapper: io =>
wrapper: io => // error
io.brewCoffee()
def main(): Unit =
val escaped = usingIO(io => useWrappedIO(mk(io))) // error
val escaped = usingIO(io => useWrappedIO(mk(io)))
escaped() // boom
Loading