Skip to content

Commit

Permalink
Add capture checking attributes to TASTy
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Nov 27, 2023
1 parent e8428e1 commit f71121b
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 20 deletions.
4 changes: 1 addition & 3 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1038,8 +1038,6 @@ class Definitions {
@tu lazy val UncheckedVarianceAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedVariance")
@tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures")
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
@tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns")
@tu lazy val CaptureCheckedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.CaptureChecked")
@tu lazy val BeanGetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanGetter")
@tu lazy val BeanSetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.beanSetter")
@tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field")
Expand Down Expand Up @@ -2004,7 +2002,7 @@ class Definitions {
@tu lazy val ccExperimental: Set[Symbol] = Set(
CapsModule, CapsModule.moduleClass, PureClass,
CapabilityAnnot, RequiresCapabilityAnnot,
RetainsAnnot, RetainsByNameAnnot, WithPureFunsAnnot)
RetainsAnnot, RetainsByNameAnnot)

// ----- primitive value class machinery ------------------------------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object AttributePickler:
pickler: TastyPickler,
buf: TastyBuffer
): Unit =
if attributes.scala2StandardLibrary || attributes.explicitNulls then // or any other attribute is set
if attributes.scala2StandardLibrary || attributes.explicitNulls || attributes.captureChecked || attributes.withPureFuns then // or any other attribute is set
pickler.newSection(AttributesSection, buf)

for tag <- attributes.booleanTags do
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/core/tasty/Attributes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,23 @@ class Attributes(
booleanTags.contains(TastyFormat.SCALA2STANDARDLIBRARYattr)
def explicitNulls: Boolean =
booleanTags.contains(TastyFormat.EXPLICITNULLSattr)
def captureChecked: Boolean =
booleanTags.contains(TastyFormat.CAPTURECHECKEDattr)
def withPureFuns: Boolean =
booleanTags.contains(TastyFormat.WITHPUREFUNSattr)
}

object Attributes:
def apply(
scala2StandardLibrary: Boolean,
explicitNulls: Boolean,
captureChecked: Boolean,
withPureFuns: Boolean,
): Attributes =
val booleanTags = List.newBuilder[Int]
if scala2StandardLibrary then booleanTags += TastyFormat.SCALA2STANDARDLIBRARYattr
if explicitNulls then booleanTags += TastyFormat.EXPLICITNULLSattr
if captureChecked then booleanTags += TastyFormat.CAPTURECHECKEDattr
if withPureFuns then booleanTags += TastyFormat.WITHPUREFUNSattr
new Attributes(booleanTags.result())
end apply
15 changes: 4 additions & 11 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,9 @@ class TreeUnpickler(reader: TastyReader,
/** The root owner tree. See `OwnerTree` class definition. Set by `enterTopLevel`. */
private var ownerTree: OwnerTree = uninitialized

/** Was unpickled class compiled with pureFunctions? */
private var withPureFuns: Boolean = false

/** Was unpickled class compiled with capture checks? */
private var withCaptureChecks: Boolean = false
private val withCaptureChecks: Boolean =
attributeUnpicklerOpt.exists(_.attributes.captureChecked)

private val unpicklingScala2Library =
attributeUnpicklerOpt.exists(_.attributes.scala2StandardLibrary)
Expand Down Expand Up @@ -655,13 +653,8 @@ class TreeUnpickler(reader: TastyReader,
}
registerSym(start, sym)
if (isClass) {
if sym.owner.is(Package) then
if annots.exists(_.hasSymbol(defn.CaptureCheckedAnnot)) then
sym.setFlag(CaptureChecked)
withCaptureChecks = true
withPureFuns = true
else if annots.exists(_.hasSymbol(defn.WithPureFunsAnnot)) then
withPureFuns = true
if sym.owner.is(Package) && withCaptureChecks then
sym.setFlag(CaptureChecked)
sym.completer.withDecls(newScope)
forkAt(templateStart).indexTemplateParams()(using localContext(sym))
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Contexts.*
import Decorators.*
import tasty.*
import config.Printers.{noPrinter, pickling}
import config.Feature
import java.io.PrintStream
import Periods.*
import Phases.*
Expand Down Expand Up @@ -111,6 +112,8 @@ class Pickler extends Phase {
val attributes = Attributes(
scala2StandardLibrary = ctx.settings.YcompileScala2Library.value,
explicitNulls = ctx.settings.YexplicitNulls.value,
captureChecked = Feature.ccEnabled,
withPureFuns = Feature.pureFunsEnabled,
)
AttributePickler.pickleAttributes(attributes, pickler, scratch.attributeBuffer)

Expand Down
5 changes: 0 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
val reference = ctx.settings.sourceroot.value
val relativePath = util.SourceFile.relativePath(ctx.compilationUnit.source, reference)
sym.addAnnotation(Annotation.makeSourceFile(relativePath, tree.span))
if sym != defn.WithPureFunsAnnot && sym != defn.CaptureCheckedAnnot then
if Feature.ccEnabled then
sym.addAnnotation(Annotation(defn.CaptureCheckedAnnot, tree.span))
else if Feature.pureFunsEnabled then
sym.addAnnotation(Annotation(defn.WithPureFunsAnnot, tree.span))
else
if !sym.is(Param) && !sym.owner.isOneOf(AbstractOrTrait) then
Checking.checkGoodBounds(tree.symbol)
Expand Down
6 changes: 6 additions & 0 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ Standard Section: "Attributes" Attribute*
```none
Attribute = SCALA2STANDARDLIBRARYattr
EXPLICITNULLSattr
CAPTURECHECKEDattr
WITHPUREFUNSattr
```
**************************************************************************************/
Expand Down Expand Up @@ -610,6 +612,8 @@ object TastyFormat {

final val SCALA2STANDARDLIBRARYattr = 1
final val EXPLICITNULLSattr = 2
final val CAPTURECHECKEDattr = 3
final val WITHPUREFUNSattr = 4

/** Useful for debugging */
def isLegalTag(tag: Int): Boolean =
Expand Down Expand Up @@ -829,6 +833,8 @@ object TastyFormat {
def attributeTagToString(tag: Int): String = tag match {
case SCALA2STANDARDLIBRARYattr => "SCALA2STANDARDLIBRARYattr"
case EXPLICITNULLSattr => "EXPLICITNULLSattr"
case CAPTURECHECKEDattr => "CAPTURECHECKEDattr"
case WITHPUREFUNSattr => "WITHPUREFUNSattr"
}

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

0 comments on commit f71121b

Please sign in to comment.