Skip to content

Commit f0fc92a

Browse files
committed
Add capture checking attributes to TASTy
1 parent cb48537 commit f0fc92a

File tree

11 files changed

+48
-22
lines changed

11 files changed

+48
-22
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,22 @@ import dotty.tools.tasty.TastyVersion
1414
class CompilationUnitInfo(
1515
val associatedFile: AbstractFile,
1616
val tastyVersion: Option[TastyVersion],
17-
val explicitNulls: Boolean
17+
val explicitNulls: Boolean,
18+
val captureChecked: Boolean,
19+
val withPureFuns: Boolean,
1820
) {
1921

2022
override def toString(): String =
21-
s"CompilationUnitInfo($associatedFile, $tastyVersion)"
23+
s"CompilationUnitInfo($associatedFile, $tastyVersion, explicitNulls = $explicitNulls, captureChecked = $captureChecked, withPureFuns = $withPureFuns)"
2224
}
2325

2426
object CompilationUnitInfo:
25-
def apply(assocFile: AbstractFile | Null, explicitNulls: Boolean = false): CompilationUnitInfo | Null =
27+
def apply(assocFile: AbstractFile | Null, explicitNulls: Boolean = false, captureChecked: Boolean = false, withPureFuns: Boolean = false): CompilationUnitInfo | Null =
2628
if assocFile == null then null
2729
else new CompilationUnitInfo(
2830
assocFile,
2931
tastyVersion = None,
3032
explicitNulls = explicitNulls,
33+
captureChecked = captureChecked,
34+
withPureFuns = withPureFuns,
3135
)

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,6 @@ class Definitions {
10391039
@tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures")
10401040
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
10411041
@tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns")
1042-
@tu lazy val CaptureCheckedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.CaptureChecked")
10431042
@tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter")
10441043
@tu lazy val BeanSetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanSetter")
10451044
@tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field")

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ class TastyLoader(val tastyFile: AbstractFile) extends SymbolLoader {
434434
tastyFile,
435435
tastyVersion = Some(tastyVersion),
436436
explicitNulls = attributes.explicitNulls,
437+
captureChecked = attributes.captureChecked,
438+
withPureFuns = attributes.withPureFuns,
437439
)
438440

439441
def description(using Context): String = "TASTy file " + tastyFile.toString

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,16 @@ object Symbols {
293293
val compUnitInfo = compilationUnitInfo
294294
compUnitInfo != null && compUnitInfo.explicitNulls
295295

296+
/** If this class is capture checked */
297+
def captureChecked(using Context): Boolean =
298+
val compUnitInfo = compilationUnitInfo
299+
compUnitInfo != null && compUnitInfo.captureChecked
300+
301+
/** If this class is uses pure functions */
302+
def withPureFuns(using Context): Boolean =
303+
val compUnitInfo = compilationUnitInfo
304+
compUnitInfo != null && compUnitInfo.withPureFuns
305+
296306
/** The class file from which this class was generated, null if not applicable. */
297307
final def binaryFile(using Context): AbstractFile | Null = {
298308
val file = associatedFile

compiler/src/dotty/tools/dotc/core/tasty/AttributePickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object AttributePickler:
1212
pickler: TastyPickler,
1313
buf: TastyBuffer
1414
): Unit =
15-
if attributes.scala2StandardLibrary || attributes.explicitNulls then // or any other attribute is set
15+
if attributes.scala2StandardLibrary || attributes.explicitNulls || attributes.captureChecked || attributes.withPureFuns then // or any other attribute is set
1616
pickler.newSection(AttributesSection, buf)
1717

1818
for tag <- attributes.booleanTags do

compiler/src/dotty/tools/dotc/core/tasty/Attributes.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ class Attributes(
99
booleanTags.contains(TastyFormat.SCALA2STANDARDLIBRARYattr)
1010
def explicitNulls: Boolean =
1111
booleanTags.contains(TastyFormat.EXPLICITNULLSattr)
12+
def captureChecked: Boolean =
13+
booleanTags.contains(TastyFormat.CAPTURECHECKEDattr)
14+
def withPureFuns: Boolean =
15+
booleanTags.contains(TastyFormat.WITHPUREFUNSattr)
1216
}
1317

1418
object Attributes:
1519
def apply(
1620
scala2StandardLibrary: Boolean,
1721
explicitNulls: Boolean,
22+
captureChecked: Boolean,
23+
withPureFuns: Boolean,
1824
): Attributes =
1925
val booleanTags = List.newBuilder[Int]
2026
if scala2StandardLibrary then booleanTags += TastyFormat.SCALA2STANDARDLIBRARYattr
2127
if explicitNulls then booleanTags += TastyFormat.EXPLICITNULLSattr
28+
if captureChecked then booleanTags += TastyFormat.CAPTURECHECKEDattr
29+
if withPureFuns then booleanTags += TastyFormat.WITHPUREFUNSattr
2230
new Attributes(booleanTags.result())
2331
end apply

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,9 @@ class TreeUnpickler(reader: TastyReader,
9393
/** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
9494
private var ownerTree: OwnerTree = uninitialized
9595

96-
/** Was unpickled class compiled with pureFunctions? */
97-
private var withPureFuns: Boolean = false
98-
9996
/** Was unpickled class compiled with capture checks? */
100-
private var withCaptureChecks: Boolean = false
97+
private val withCaptureChecks: Boolean =
98+
attributeUnpicklerOpt.exists(_.attributes.captureChecked)
10199

102100
private val unpicklingScala2Library =
103101
attributeUnpicklerOpt.exists(_.attributes.scala2StandardLibrary)
@@ -656,13 +654,8 @@ class TreeUnpickler(reader: TastyReader,
656654
}
657655
registerSym(start, sym)
658656
if (isClass) {
659-
if sym.owner.is(Package) then
660-
if annots.exists(_.hasSymbol(defn.CaptureCheckedAnnot)) then
661-
sym.setFlag(CaptureChecked)
662-
withCaptureChecks = true
663-
withPureFuns = true
664-
else if annots.exists(_.hasSymbol(defn.WithPureFunsAnnot)) then
665-
withPureFuns = true
657+
if sym.owner.is(Package) && withCaptureChecks then
658+
sym.setFlag(CaptureChecked)
666659
sym.completer.withDecls(newScope)
667660
forkAt(templateStart).indexTemplateParams()(using localContext(sym))
668661
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Contexts.*
77
import Decorators.*
88
import tasty.*
99
import config.Printers.{noPrinter, pickling}
10+
import config.Feature
1011
import java.io.PrintStream
1112
import Periods.*
1213
import Phases.*
@@ -111,6 +112,8 @@ class Pickler extends Phase {
111112
val attributes = Attributes(
112113
scala2StandardLibrary = ctx.settings.YcompileScala2Library.value,
113114
explicitNulls = ctx.settings.YexplicitNulls.value,
115+
captureChecked = Feature.ccEnabled,
116+
withPureFuns = Feature.pureFunsEnabled,
114117
)
115118
AttributePickler.pickleAttributes(attributes, pickler, scratch.attributeBuffer)
116119

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
423423
val reference = ctx.settings.sourceroot.value
424424
val relativePath = util.SourceFile.relativePath(ctx.compilationUnit.source, reference)
425425
sym.addAnnotation(Annotation.makeSourceFile(relativePath, tree.span))
426-
if sym != defn.WithPureFunsAnnot && sym != defn.CaptureCheckedAnnot then
427-
if Feature.ccEnabled then
428-
sym.addAnnotation(Annotation(defn.CaptureCheckedAnnot, tree.span))
429-
else if Feature.pureFunsEnabled then
430-
sym.addAnnotation(Annotation(defn.WithPureFunsAnnot, tree.span))
431426
else
432427
if !sym.is(Param) && !sym.owner.isOneOf(AbstractOrTrait) then
433428
Checking.checkGoodBounds(tree.symbol)

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,16 @@ class Namer { typer: Typer =>
247247
case tree: TypeDef if tree.isClassDef =>
248248
val flags = checkFlags(tree.mods.flags)
249249
val name = checkNoConflict(tree.name, flags.is(Private), tree.span).asTypeName
250+
val compilationUnitInfo = CompilationUnitInfo(
251+
ctx.source.file,
252+
explicitNulls = ctx.explicitNulls,
253+
captureChecked = Feature.ccEnabled,
254+
withPureFuns = Feature.pureFunsEnabled,
255+
)
250256
val cls =
251257
createOrRefine[ClassSymbol](tree, name, flags, ctx.owner,
252258
cls => adjustIfModule(new ClassCompleter(cls, tree)(ctx), tree),
253-
newClassSymbol(ctx.owner, name, _, _, _, tree.nameSpan, CompilationUnitInfo(ctx.source.file, explicitNulls = ctx.explicitNulls)))
259+
newClassSymbol(ctx.owner, name, _, _, _, tree.nameSpan, compilationUnitInfo))
254260
cls.completer.asInstanceOf[ClassCompleter].init()
255261
cls
256262
case tree: MemberDef =>

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ Standard Section: "Attributes" Attribute*
272272
```none
273273
Attribute = SCALA2STANDARDLIBRARYattr
274274
EXPLICITNULLSattr
275+
CAPTURECHECKEDattr
276+
WITHPUREFUNSattr
275277
```
276278
277279
**************************************************************************************/
@@ -610,6 +612,8 @@ object TastyFormat {
610612

611613
final val SCALA2STANDARDLIBRARYattr = 1
612614
final val EXPLICITNULLSattr = 2
615+
final val CAPTURECHECKEDattr = 3
616+
final val WITHPUREFUNSattr = 4
613617

614618
/** Useful for debugging */
615619
def isLegalTag(tag: Int): Boolean =
@@ -829,6 +833,8 @@ object TastyFormat {
829833
def attributeTagToString(tag: Int): String = tag match {
830834
case SCALA2STANDARDLIBRARYattr => "SCALA2STANDARDLIBRARYattr"
831835
case EXPLICITNULLSattr => "EXPLICITNULLSattr"
836+
case CAPTURECHECKEDattr => "CAPTURECHECKEDattr"
837+
case WITHPUREFUNSattr => "WITHPUREFUNSattr"
832838
}
833839

834840
/** @return If non-negative, the number of leading references (represented as nats) of a length/trees entry.

0 commit comments

Comments
 (0)