Skip to content

Commit 1d453d6

Browse files
committed
Add variants of compiletime.erasedValue
1 parent 478b527 commit 1d453d6

File tree

6 files changed

+24
-10
lines changed

6 files changed

+24
-10
lines changed

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -495,15 +495,13 @@ extension (sym: Symbol)
495495

496496
/** Does this symbol allow results carrying the universal capability?
497497
* Currently this is true only for function type applies (since their
498-
* results are unboxed) and `erasedValue` since this function is magic in
499-
* that is allows to conjure global capabilies from nothing (aside: can we find a
500-
* more controlled way to achieve this?).
498+
* results are unboxed) and `caps.{$internal,unsafe}.erasedValue` since
499+
* these function are magic in that they allow to conjure global capabilies from nothing.
501500
* But it could be generalized to other functions that so that they can take capability
502501
* classes as arguments.
503502
*/
504503
def allowsRootCapture(using Context): Boolean =
505-
sym == defn.Compiletime_erasedValue
506-
|| defn.isFunctionClass(sym.maybeOwner)
504+
defn.capsErasedValueMethods.contains(sym) || defn.isFunctionClass(sym.maybeOwner)
507505

508506
/** When applying `sym`, would the result type be unboxed?
509507
* This is the case if the result type contains a top-level reference to an enclosing

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ class CheckCaptures extends Recheck, SymTransformer:
576576
* @param args the type arguments
577577
*/
578578
def disallowCapInTypeArgs(fn: Tree, sym: Symbol, args: List[Tree])(using Context): Unit =
579-
def isExempt = sym.isTypeTestOrCast || sym == defn.Compiletime_erasedValue
579+
def isExempt = sym.isTypeTestOrCast || defn.capsErasedValueMethods.contains(sym)
580580
if !isExempt then
581581
val paramNames = atPhase(thisPhase.prev):
582582
fn.tpe.widenDealias match

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,9 +1004,11 @@ class Definitions {
10041004
@tu lazy val Caps_Capability: ClassSymbol = requiredClass("scala.caps.Capability")
10051005
@tu lazy val Caps_CapSet: ClassSymbol = requiredClass("scala.caps.CapSet")
10061006
@tu lazy val CapsInternalModule: Symbol = requiredModule("scala.caps.internal")
1007+
@tu lazy val Caps_erasedValue: Symbol = CapsInternalModule.requiredMethod("erasedValue")
10071008
@tu lazy val CapsUnsafeModule: Symbol = requiredModule("scala.caps.unsafe")
10081009
@tu lazy val Caps_unsafeAssumePure: Symbol = CapsUnsafeModule.requiredMethod("unsafeAssumePure")
10091010
@tu lazy val Caps_unsafeAssumeSeparate: Symbol = CapsUnsafeModule.requiredMethod("unsafeAssumeSeparate")
1011+
@tu lazy val Caps_unsafeErasedValue: Symbol = CapsUnsafeModule.requiredMethod("unsafeErasedValue")
10101012
@tu lazy val Caps_ContainsTrait: TypeSymbol = CapsModule.requiredType("Contains")
10111013
@tu lazy val Caps_ContainsModule: Symbol = requiredModule("scala.caps.Contains")
10121014
@tu lazy val Caps_containsImpl: TermSymbol = Caps_ContainsModule.requiredMethod("containsImpl")
@@ -1559,7 +1561,7 @@ class Definitions {
15591561
Set(StringClass, NothingClass, NullClass) ++ ScalaValueClasses()
15601562

15611563
@tu lazy val capsErasedValueMethods =
1562-
Set[Symbol]()
1564+
Set(Caps_erasedValue, Caps_unsafeErasedValue)
15631565
@tu lazy val erasedValueMethods =
15641566
capsErasedValueMethods + Compiletime_erasedValue
15651567

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
231231
case PreciseConstrained(tp, true) =>
232232
if tp.isSingletonBounded(frozen = false) then
233233
withNoErrors:
234-
ref(defn.Compiletime_erasedValue).appliedToType(formal).withSpan(span)
234+
ref(defn.Caps_erasedValue).appliedToType(formal).withSpan(span)
235235
else
236236
withErrors(i"$tp is not a singleton")
237237
case _ =>
@@ -240,7 +240,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
240240
val synthesizedPrecise: SpecialHandler = (formal, span) => formal match
241241
case PreciseConstrained(tp, false) =>
242242
withNoErrors:
243-
ref(defn.Compiletime_erasedValue).appliedToType(formal).withSpan(span)
243+
ref(defn.Caps_erasedValue).appliedToType(formal).withSpan(span)
244244
case _ =>
245245
EmptyTreeNoError
246246

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2392,7 +2392,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
23922392
untpd.ValDef(
23932393
CanThrowEvidenceName.fresh(),
23942394
untpd.TypeTree(defn.CanThrowClass.typeRef.appliedTo(tp)),
2395-
untpd.ref(defn.Compiletime_erasedValue))
2395+
untpd.ref(defn.Caps_erasedValue))
23962396
.withFlags(Given | Final | Erased)
23972397
.withSpan(expr.span)
23982398
val caughtExceptions =

library/src/scala/caps/package.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ object internal:
110110
*/
111111
final class inferredDepFun extends annotation.StaticAnnotation
112112

113+
/** An erasedValue issued internally by the compiler. Unlike the
114+
* user-accessible compiletime.erasedValue, this version is assumed
115+
* to be a pure expression, hence capability safe. The compiler generates this
116+
* version only where it is known that a value can be generated.
117+
*/
118+
def erasedValue[T]: T = ???
119+
113120
end internal
114121

115122
@experimental
@@ -135,4 +142,11 @@ object unsafe:
135142
*/
136143
def unsafeAssumeSeparate(op: Any): op.type = op
137144

145+
/** An unsafe variant of erasedValue that can be used as an escape hatch. Unlike the
146+
* user-accessible compiletime.erasedValue, this version is assumed
147+
* to be a pure expression, hence capability safe. But there is no proof
148+
* of realizability, hence it is unsafe.
149+
*/
150+
def unsafeErasedValue[T]: T = ???
151+
138152
end unsafe

0 commit comments

Comments
 (0)