File tree Expand file tree Collapse file tree 6 files changed +24
-10
lines changed
compiler/src/dotty/tools/dotc Expand file tree Collapse file tree 6 files changed +24
-10
lines changed Original file line number Diff line number Diff line change @@ -495,15 +495,13 @@ extension (sym: Symbol)
495
495
496
496
/** Does this symbol allow results carrying the universal capability?
497
497
* 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.
501
500
* But it could be generalized to other functions that so that they can take capability
502
501
* classes as arguments.
503
502
*/
504
503
def allowsRootCapture (using Context ): Boolean =
505
- sym == defn.Compiletime_erasedValue
506
- || defn.isFunctionClass(sym.maybeOwner)
504
+ defn.capsErasedValueMethods.contains(sym) || defn.isFunctionClass(sym.maybeOwner)
507
505
508
506
/** When applying `sym`, would the result type be unboxed?
509
507
* This is the case if the result type contains a top-level reference to an enclosing
Original file line number Diff line number Diff line change @@ -576,7 +576,7 @@ class CheckCaptures extends Recheck, SymTransformer:
576
576
* @param args the type arguments
577
577
*/
578
578
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)
580
580
if ! isExempt then
581
581
val paramNames = atPhase(thisPhase.prev):
582
582
fn.tpe.widenDealias match
Original file line number Diff line number Diff line change @@ -1004,9 +1004,11 @@ class Definitions {
1004
1004
@ tu lazy val Caps_Capability : ClassSymbol = requiredClass(" scala.caps.Capability" )
1005
1005
@ tu lazy val Caps_CapSet : ClassSymbol = requiredClass(" scala.caps.CapSet" )
1006
1006
@ tu lazy val CapsInternalModule : Symbol = requiredModule(" scala.caps.internal" )
1007
+ @ tu lazy val Caps_erasedValue : Symbol = CapsInternalModule .requiredMethod(" erasedValue" )
1007
1008
@ tu lazy val CapsUnsafeModule : Symbol = requiredModule(" scala.caps.unsafe" )
1008
1009
@ tu lazy val Caps_unsafeAssumePure : Symbol = CapsUnsafeModule .requiredMethod(" unsafeAssumePure" )
1009
1010
@ tu lazy val Caps_unsafeAssumeSeparate : Symbol = CapsUnsafeModule .requiredMethod(" unsafeAssumeSeparate" )
1011
+ @ tu lazy val Caps_unsafeErasedValue : Symbol = CapsUnsafeModule .requiredMethod(" unsafeErasedValue" )
1010
1012
@ tu lazy val Caps_ContainsTrait : TypeSymbol = CapsModule .requiredType(" Contains" )
1011
1013
@ tu lazy val Caps_ContainsModule : Symbol = requiredModule(" scala.caps.Contains" )
1012
1014
@ tu lazy val Caps_containsImpl : TermSymbol = Caps_ContainsModule .requiredMethod(" containsImpl" )
@@ -1559,7 +1561,7 @@ class Definitions {
1559
1561
Set (StringClass , NothingClass , NullClass ) ++ ScalaValueClasses ()
1560
1562
1561
1563
@ tu lazy val capsErasedValueMethods =
1562
- Set [ Symbol ]( )
1564
+ Set ( Caps_erasedValue , Caps_unsafeErasedValue )
1563
1565
@ tu lazy val erasedValueMethods =
1564
1566
capsErasedValueMethods + Compiletime_erasedValue
1565
1567
Original file line number Diff line number Diff line change @@ -231,7 +231,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
231
231
case PreciseConstrained (tp, true ) =>
232
232
if tp.isSingletonBounded(frozen = false ) then
233
233
withNoErrors :
234
- ref(defn.Compiletime_erasedValue ).appliedToType(formal).withSpan(span)
234
+ ref(defn.Caps_erasedValue ).appliedToType(formal).withSpan(span)
235
235
else
236
236
withErrors(i " $tp is not a singleton " )
237
237
case _ =>
@@ -240,7 +240,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
240
240
val synthesizedPrecise : SpecialHandler = (formal, span) => formal match
241
241
case PreciseConstrained (tp, false ) =>
242
242
withNoErrors :
243
- ref(defn.Compiletime_erasedValue ).appliedToType(formal).withSpan(span)
243
+ ref(defn.Caps_erasedValue ).appliedToType(formal).withSpan(span)
244
244
case _ =>
245
245
EmptyTreeNoError
246
246
Original file line number Diff line number Diff line change @@ -2392,7 +2392,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
2392
2392
untpd.ValDef (
2393
2393
CanThrowEvidenceName .fresh(),
2394
2394
untpd.TypeTree (defn.CanThrowClass .typeRef.appliedTo(tp)),
2395
- untpd.ref(defn.Compiletime_erasedValue ))
2395
+ untpd.ref(defn.Caps_erasedValue ))
2396
2396
.withFlags(Given | Final | Erased )
2397
2397
.withSpan(expr.span)
2398
2398
val caughtExceptions =
Original file line number Diff line number Diff line change @@ -110,6 +110,13 @@ object internal:
110
110
*/
111
111
final class inferredDepFun extends annotation.StaticAnnotation
112
112
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
+
113
120
end internal
114
121
115
122
@ experimental
@@ -135,4 +142,11 @@ object unsafe:
135
142
*/
136
143
def unsafeAssumeSeparate (op : Any ): op.type = op
137
144
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
+
138
152
end unsafe
You can’t perform that action at this time.
0 commit comments