Skip to content

Commit 060676e

Browse files
authored
Special handling of experimental.captureChecking import (#17427)
The question is, how do we introduce capture checking safely. There are two conflicting requirements: - Capture checking should not leak into standard Scala. It should be meaningful only in code that has capture checking explicitly enabled. - We need to be able to build up libraries that express capture information and that can be consumed from other code. This needs to start with the standard library itself. So far, everything related to capture checking was marked experimental. This means all code that refers to a capture checking abstraction in any way whatsoever needs to be declared experimental. That clearly does not work for the new use cases. But fortunately, capture checking has some properties that enable a different scheme. Specifically, a file compiled under capture checking looks like a completely normal component (both Tasty and binary) to any other file that uses it and that is not compiled with captureChecking. Only when the consumer is also compiled with capture checking, the capturing types of the original file will be revealed. The same holds for binaries. Capture checking has no effect at all on the binaries that get generated and all types and annotations needed for capture checking are erased. This allows the following more flexible scheme: - We can turn capture checking on with a setting or language import in any source file. The sources do not have to be @experimental. - If capture checking is turned on, a number of annotations and other symbols that are needed for capture checking and are normally experimental are also made available. The important property is that capture checking in one component cannot poison other normal components. Like @experimental itself, the whole scheme is transitive. With the new scheme we do not need a special exemption for the dotty package anymore, so the code implementing the exception is dropped.
2 parents 4e4552e + e6d1242 commit 060676e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+117
-85
lines changed

compiler/src/dotty/tools/dotc/config/Feature.scala

+13-8
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,21 @@ object Feature:
136136
if !isExperimentalEnabled then
137137
report.error(em"Experimental $which may only be used with a nightly or snapshot version of the compiler$note", srcPos)
138138

139+
private def ccException(sym: Symbol)(using Context): Boolean =
140+
ccEnabled && defn.ccExperimental.contains(sym)
141+
139142
def checkExperimentalDef(sym: Symbol, srcPos: SrcPos)(using Context) =
140143
if !isExperimentalEnabled then
141-
val symMsg =
142-
if sym.hasAnnotation(defn.ExperimentalAnnot) then
143-
i"$sym is marked @experimental"
144-
else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then
145-
i"${sym.owner} is marked @experimental"
146-
else
147-
i"$sym inherits @experimental"
148-
report.error(em"$symMsg and therefore may only be used in an experimental scope.", srcPos)
144+
val experimentalSym =
145+
if sym.hasAnnotation(defn.ExperimentalAnnot) then sym
146+
else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then sym.owner
147+
else NoSymbol
148+
if !ccException(experimentalSym) then
149+
val symMsg =
150+
if experimentalSym.exists
151+
then i"$experimentalSym is marked @experimental"
152+
else i"$sym inherits @experimental"
153+
report.error(em"$symMsg and therefore may only be used in an experimental scope.", srcPos)
149154

150155
/** Check that experimental compiler options are only set for snapshot or nightly compiler versions. */
151156
def checkExperimentalSettings(using Context): Unit =

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

+21-9
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,8 @@ class Definitions {
976976
@tu lazy val Caps_unsafeBoxFunArg: Symbol = CapsUnsafeModule.requiredMethod("unsafeBoxFunArg")
977977
@tu lazy val Caps_SealedAnnot: ClassSymbol = requiredClass("scala.caps.Sealed")
978978

979+
@tu lazy val PureClass: Symbol = requiredClass("scala.Pure")
980+
979981
// Annotation base classes
980982
@tu lazy val AnnotationClass: ClassSymbol = requiredClass("scala.annotation.Annotation")
981983
@tu lazy val StaticAnnotationClass: ClassSymbol = requiredClass("scala.annotation.StaticAnnotation")
@@ -1944,6 +1946,14 @@ class Definitions {
19441946
case Some(pkgs) => pkgs.contains(sym.owner)
19451947
case none => false
19461948

1949+
/** Experimental definitions that can nevertheless be accessed from a stable
1950+
* compiler if capture checking is enabled.
1951+
*/
1952+
@tu lazy val ccExperimental: Set[Symbol] = Set(
1953+
CapsModule, CapsModule.moduleClass, PureClass,
1954+
CapabilityAnnot, RequiresCapabilityAnnot,
1955+
RetainsAnnot, RetainsByNameAnnot, WithPureFunsAnnot)
1956+
19471957
// ----- primitive value class machinery ------------------------------------------
19481958

19491959
class PerRun[T](generate: Context ?=> T) {
@@ -2041,15 +2051,17 @@ class Definitions {
20412051
def isValueSubClass(sym1: Symbol, sym2: Symbol): Boolean =
20422052
valueTypeEnc(sym2.asClass.name) % valueTypeEnc(sym1.asClass.name) == 0
20432053

2044-
@tu lazy val specialErasure: SimpleIdentityMap[Symbol, ClassSymbol] =
2045-
SimpleIdentityMap.empty[Symbol]
2046-
.updated(AnyClass, ObjectClass)
2047-
.updated(MatchableClass, ObjectClass)
2048-
.updated(AnyValClass, ObjectClass)
2049-
.updated(SingletonClass, ObjectClass)
2050-
.updated(TupleClass, ProductClass)
2051-
.updated(NonEmptyTupleClass, ProductClass)
2052-
.updated(PairClass, ObjectClass)
2054+
@tu lazy val specialErasure: collection.Map[Symbol, ClassSymbol] =
2055+
val m = mutable.Map[Symbol, ClassSymbol]()
2056+
m(AnyClass) = ObjectClass
2057+
m(MatchableClass) = ObjectClass
2058+
m(PureClass) = ObjectClass
2059+
m(AnyValClass) = ObjectClass
2060+
m(SingletonClass) = ObjectClass
2061+
m(TupleClass) = ProductClass
2062+
m(NonEmptyTupleClass) = ProductClass
2063+
m(PairClass) = ObjectClass
2064+
m
20532065

20542066
// ----- Initialization ---------------------------------------------------
20552067

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ object TypeErasure {
410410
val candidates = takeUntil(tp2superclasses)(!_.is(Trait))
411411

412412
// Candidates st "no other common superclass or trait derives from S"
413-
// Also, drop `PairClass` since it is not valid after erasue
413+
// Also, drop `PairClass` since it is not valid after erasure
414414
val minimums = candidates.filter { cand =>
415415
cand != defn.PairClass
416416
&& candidates.forall(x => !x.derivesFrom(cand) || x.eq(cand))

compiler/src/dotty/tools/dotc/transform/Erasure.scala

+8-6
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,14 @@ class Erasure extends Phase with DenotTransformer {
190190
def assertErased(tp: Type, tree: tpd.Tree = tpd.EmptyTree)(using Context): Unit = {
191191
def isAllowed(cls: Symbol, sourceName: String) =
192192
tp.typeSymbol == cls && ctx.compilationUnit.source.file.name == sourceName
193-
assert(isErasedType(tp) ||
194-
isAllowed(defn.ArrayClass, "Array.scala") ||
195-
isAllowed(defn.TupleClass, "Tuple.scala") ||
196-
isAllowed(defn.NonEmptyTupleClass, "Tuple.scala") ||
197-
isAllowed(defn.PairClass, "Tuple.scala"),
198-
i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree : ${tree.tpe} / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase.prev}")
193+
assert(
194+
isErasedType(tp)
195+
|| isAllowed(defn.ArrayClass, "Array.scala")
196+
|| isAllowed(defn.TupleClass, "Tuple.scala")
197+
|| isAllowed(defn.NonEmptyTupleClass, "Tuple.scala")
198+
|| isAllowed(defn.PairClass, "Tuple.scala")
199+
|| isAllowed(defn.PureClass, "Pure.scala"),
200+
i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree : ${tree.tpe} / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase.prev}")
199201
}
200202
}
201203

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

-2
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,6 @@ object SymUtils:
370370
self.hasAnnotation(defn.ExperimentalAnnot)
371371
|| isDefaultArgumentOfExperimentalMethod
372372
|| (!self.is(Package) && self.owner.isInExperimentalScope)
373-
|| self.topLevelClass.ownersIterator.exists(p =>
374-
p.is(Package) && p.owner.isRoot && p.name == tpnme.dotty)
375373

376374
/** The declared self type of this class, as seen from `site`, stripping
377375
* all refinements for opaque types.

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,9 @@ object Checking {
784784
for case imp @ Import(qual, selectors) <- trees do
785785
def isAllowedImport(sel: untpd.ImportSelector) =
786786
val name = Feature.experimental(sel.name)
787-
name == Feature.scala2macros || name == Feature.erasedDefinitions
787+
name == Feature.scala2macros
788+
|| name == Feature.erasedDefinitions
789+
|| name == Feature.captureChecking
788790

789791
languageImport(qual) match
790792
case Some(nme.experimental)

library/src/scala/Pure.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package scala
2+
import annotation.experimental
3+
4+
/** A marker trait that declares that all inheriting classes are "pure" in the
5+
* sense that their values retain no capabilities including capabilities needed
6+
* to perform effects. This has formal meaning only under capture checking.
7+
*/
8+
@experimental trait Pure:
9+
this: Pure =>

library/src/scala/caps.scala

-6
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,3 @@ import annotation.experimental
4040
*/
4141
@deprecated("The Sealed annotation should not be directly used in source code.\nUse the `sealed` modifier on type parameters instead.")
4242
class Sealed extends annotation.Annotation
43-
44-
/** Mixing in this trait forces a trait or class to be pure, i.e.
45-
* have no capabilities retained in its self type.
46-
*/
47-
trait Pure:
48-
this: Pure =>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@annotation.experimental class C(x: () => Unit) extends caps.Pure // error
1+
@annotation.experimental class C(x: () => Unit) extends Pure // error
22

3-
@annotation.experimental class D(@annotation.constructorOnly x: () => Unit) extends caps.Pure // ok
3+
@annotation.experimental class D(@annotation.constructorOnly x: () => Unit) extends Pure // ok
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package scala.runtime
2+
3+
import language.experimental.captureChecking
4+
5+
object test:
6+
type T = Pure
7+
8+
class Foo extends Object, Pure:
9+
val x: Pure = ???
10+
def foo() = ()
11+

tests/pos-custom-args/no-experimental/dotty-experimental.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package dotty.tools
1+
import language.experimental.captureChecking
22
object test {
33

44
val x = caps.cap

tests/pos-with-compiler-cc/backend/jvm/BCodeHelpers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
209209
}
210210
} // end of trait BCPickles
211211

212-
trait BCInnerClassGen extends caps.Pure {
212+
trait BCInnerClassGen extends Pure {
213213

214214
def debugLevel = 3 // 0 -> no debug info; 1-> filename; 2-> lines; 3-> varnames
215215

tests/pos-with-compiler-cc/backend/jvm/BCodeIdiomatic.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import dotty.tools.dotc.report
1717
* @version 1.0
1818
*
1919
*/
20-
trait BCodeIdiomatic extends caps.Pure {
20+
trait BCodeIdiomatic extends Pure {
2121
val int: DottyBackendInterface
2222
final lazy val bTypes = new BTypesFromSymbols[int.type](int)
2323

tests/pos-with-compiler-cc/backend/jvm/BTypes.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import scala.tools.asm
1414
* This representation is immutable and independent of the compiler data structures, hence it can
1515
* be queried by concurrent threads.
1616
*/
17-
abstract class BTypes extends caps.Pure {
17+
abstract class BTypes extends Pure {
1818

1919
val int: DottyBackendInterface
2020
import int.given
@@ -47,7 +47,7 @@ abstract class BTypes extends caps.Pure {
4747
* A BType is either a primitve type, a ClassBType, an ArrayBType of one of these, or a MethodType
4848
* referring to BTypes.
4949
*/
50-
/*sealed*/ trait BType extends caps.Pure { // Not sealed for now due to SI-8546
50+
/*sealed*/ trait BType extends Pure { // Not sealed for now due to SI-8546
5151
final override def toString: String = this match {
5252
case UNIT => "V"
5353
case BOOL => "Z"

tests/pos-with-compiler-cc/backend/sjs/ScopedVar.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dotty.tools.backend.sjs
22

3-
class ScopedVar[A](init: A) extends caps.Pure {
3+
class ScopedVar[A](init: A) extends Pure {
44
import ScopedVar.Assignment
55

66
private[ScopedVar] var value = init

tests/pos-with-compiler-cc/dotc/ast/Positioned.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import annotation.internal.sharable
1515

1616
/** A base class for things that have positions (currently: modifiers and trees)
1717
*/
18-
abstract class Positioned(implicit @constructorOnly src: SourceFile) extends SrcPos, Product, Cloneable, caps.Pure {
18+
abstract class Positioned(implicit @constructorOnly src: SourceFile) extends SrcPos, Product, Cloneable, Pure {
1919
import Positioned.{ids, nextId, debugId}
2020

2121
private var mySpan: Span = _

tests/pos-with-compiler-cc/dotc/cc/CaptureSet.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import annotation.retains
3939
* if the mapped function is either a bijection or if it is idempotent
4040
* on capture references (c.f. doc comment on `map` below).
4141
*/
42-
sealed abstract class CaptureSet extends Showable, caps.Pure:
42+
sealed abstract class CaptureSet extends Showable, Pure:
4343
import CaptureSet.*
4444

4545
/** The elements of this capture set. For capture variables,

tests/pos-with-compiler-cc/dotc/core/Annotations.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Annotations {
1717
if (tree.symbol.isConstructor) tree.symbol.owner
1818
else tree.tpe.typeSymbol
1919

20-
abstract class Annotation extends Showable, caps.Pure {
20+
abstract class Annotation extends Showable, Pure {
2121

2222
def tree(using Context): Tree
2323

tests/pos-with-compiler-cc/dotc/core/CheckRealizable.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import annotation.constructorOnly
1313
/** Realizability status */
1414
object CheckRealizable {
1515

16-
sealed abstract class Realizability(val msg: String) extends caps.Pure {
16+
sealed abstract class Realizability(val msg: String) extends Pure {
1717
def andAlso(other: => Realizability): Realizability =
1818
if (this == Realizable) other else this
1919
def mapError(f: Realizability -> Context ?-> Realizability)(using Context): Realizability =

tests/pos-with-compiler-cc/dotc/core/Denotations.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ object Denotations {
7676
/** A PreDenotation represents a group of single denotations or a single multi-denotation
7777
* It is used as an optimization to avoid forming MultiDenotations too eagerly.
7878
*/
79-
abstract class PreDenotation extends caps.Pure {
79+
abstract class PreDenotation extends Pure {
8080

8181
/** A denotation in the group exists */
8282
def exists: Boolean

tests/pos-with-compiler-cc/dotc/core/NameKinds.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ object NameKinds {
2323
@sharable private val uniqueNameKinds = util.HashMap[String, UniqueNameKind]()
2424

2525
/** A class for the info stored in a derived name */
26-
abstract class NameInfo extends caps.Pure {
26+
abstract class NameInfo extends Pure {
2727
def kind: NameKind
2828
def mkString(underlying: TermName): String
2929
def map(f: SimpleName => SimpleName): NameInfo = this
3030
}
3131

3232
/** An abstract base class of classes that define the kind of a derived name info */
33-
abstract class NameKind(val tag: Int) extends caps.Pure { self =>
33+
abstract class NameKind(val tag: Int) extends Pure { self =>
3434

3535
/** The info class defined by this kind */
3636
type ThisInfo <: Info

tests/pos-with-compiler-cc/dotc/core/Names.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ object Names {
3232
* in a name table. A derived term name adds a tag, and possibly a number
3333
* or a further simple name to some other name.
3434
*/
35-
abstract class Name extends Designator, Showable, caps.Pure derives CanEqual {
35+
abstract class Name extends Designator, Showable, Pure derives CanEqual {
3636

3737
/** A type for names of the same kind as this name */
3838
type ThisName <: Name

tests/pos-with-compiler-cc/dotc/core/Phases.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ object Phases {
285285
final def isTyper(phase: Phase): Boolean = phase.id == typerPhase.id
286286
}
287287

288-
abstract class Phase extends caps.Pure {
288+
abstract class Phase extends Pure {
289289

290290
/** A name given to the `Phase` that can be used to debug the compiler. For
291291
* instance, it is possible to print trees after a given phase using:

tests/pos-with-compiler-cc/dotc/core/Scopes.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ object Scopes {
6060
* or to delete them. These methods are provided by subclass
6161
* MutableScope.
6262
*/
63-
abstract class Scope extends printing.Showable, caps.Pure {
63+
abstract class Scope extends printing.Showable, Pure {
6464

6565
/** The last scope-entry from which all others are reachable via `prev` */
6666
private[dotc] def lastEntry: ScopeEntry | Null

tests/pos-with-compiler-cc/dotc/core/TypeErrors.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import ast.untpd
1515
import config.Printers.cyclicErrors
1616
import language.experimental.pureFunctions
1717

18-
abstract class TypeError(using creationContext: DetachedContext) extends Exception(""), caps.Pure:
18+
abstract class TypeError(using creationContext: DetachedContext) extends Exception(""), Pure:
1919

2020
/** Convert to message. This takes an additional Context, so that we
2121
* use the context when the message is first produced, i.e. when the TypeError

tests/pos-with-compiler-cc/dotc/core/Types.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ object Types {
9191
*
9292
* Note: please keep in sync with copy in `docs/docs/internals/type-system.md`.
9393
*/
94-
abstract class Type extends Hashable, printing.Showable, caps.Pure {
94+
abstract class Type extends Hashable, printing.Showable, Pure {
9595

9696
// ----- Tests -----------------------------------------------------
9797

tests/pos-with-compiler-cc/dotc/core/classfile/ClassfileParser.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import annotation.retains
2828

2929
object ClassfileParser {
3030
/** Marker trait for unpicklers that can be embedded in classfiles. */
31-
trait Embedded extends caps.Pure
31+
trait Embedded extends Pure
3232

3333
/** Indicate that there is nothing to unpickle and the corresponding symbols can
3434
* be invalidated. */

tests/pos-with-compiler-cc/dotc/interactive/Completion.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ object Completion {
538538
/** Temporary data structure representing denotations with the same name introduced in a given scope
539539
* as a member of a type, by a local definition or by an import clause
540540
*/
541-
private case class ScopedDenotations(denots: Seq[SingleDenotation], ctx: DetachedContext) extends caps.Pure
541+
private case class ScopedDenotations(denots: Seq[SingleDenotation], ctx: DetachedContext) extends Pure
542542

543543
/**
544544
* The completion mode: defines what kinds of symbols should be included in the completion

tests/pos-with-compiler-cc/dotc/parsing/Scanners.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1554,7 +1554,7 @@ object Scanners {
15541554
* InBraces a pair of braces { ... }
15551555
* Indented a pair of <indent> ... <outdent> tokens
15561556
*/
1557-
abstract class Region(val closedBy: Token) extends caps.Pure:
1557+
abstract class Region(val closedBy: Token) extends Pure:
15581558

15591559
/** The region enclosing this one, or `null` for the outermost region */
15601560
def outer: Region | Null

tests/pos-with-compiler-cc/dotc/printing/Highlighting.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ object Highlighting {
2828
else mod + super.show
2929
}
3030

31-
case class HighlightBuffer(hl: Highlight)(using DetachedContext) extends caps.Pure {
31+
case class HighlightBuffer(hl: Highlight)(using DetachedContext) extends Pure {
3232
private val buffer = new mutable.ListBuffer[String]
3333

3434
buffer += hl.show

tests/pos-with-compiler-cc/dotc/printing/Printer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import scala.annotation.internal.sharable
1515

1616
/** The base class of all printers
1717
*/
18-
abstract class Printer extends caps.Pure {
18+
abstract class Printer extends Pure {
1919

2020
private var prec: Precedence = GlobalPrec
2121

tests/pos-with-compiler-cc/dotc/profile/AsyncHelper.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicInteger
99
import dotty.tools.dotc.core.Phases.Phase
1010
import dotty.tools.dotc.core.Contexts._
1111

12-
sealed trait AsyncHelper extends caps.Pure {
12+
sealed trait AsyncHelper extends Pure {
1313

1414
def newUnboundedQueueFixedThreadPool
1515
(nThreads: Int,

tests/pos-with-compiler-cc/dotc/profile/Profiler.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ case class ProfileRange(start: ProfileSnap, end:ProfileSnap, phase:Phase, purpos
6565
def retainedHeapMB: Double = toMegaBytes(end.heapBytes - start.heapBytes)
6666
}
6767

68-
sealed trait Profiler extends caps.Pure {
68+
sealed trait Profiler extends Pure {
6969

7070
def finished(): Unit
7171

tests/pos-with-compiler-cc/dotc/transform/CapturedVars.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer:
3434
override def initContext(ctx: FreshContext): Unit =
3535
Captured = ctx.addLocation(util.ReadOnlySet.empty)
3636

37-
private class RefInfo(using DetachedContext) extends caps.Pure {
37+
private class RefInfo(using DetachedContext) extends Pure {
3838
/** The classes for which a Ref type exists. */
3939
val refClassKeys: collection.Set[Symbol] =
4040
defn.ScalaNumericValueClasses() `union` Set(defn.BooleanClass, defn.ObjectClass)

0 commit comments

Comments
 (0)