diff --git a/compiler/src/dotty/tools/dotc/config/Feature.scala b/compiler/src/dotty/tools/dotc/config/Feature.scala index 23305a6b0333..961b112693c8 100644 --- a/compiler/src/dotty/tools/dotc/config/Feature.scala +++ b/compiler/src/dotty/tools/dotc/config/Feature.scala @@ -137,6 +137,10 @@ object Feature: enabledBySetting(captureChecking) || ctx.originalCompilationUnit.needsCaptureChecking + /** Are capture-checking annotations emitted in the resulting TASTy tree? */ + def ccAnnotationsEnabled(using Context) = + ccEnabled && !ctx.settings.YccNoTasty.value + /** Is pureFunctions enabled for any of the currently compiled compilation units? */ def pureFunsEnabledSomewhere(using Context) = enabledBySetting(pureFunctions) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index a3fa5fd9bb06..606a2d4da2e1 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -459,6 +459,7 @@ private sealed trait YSettings: val YccLog: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycc-log", "Used in conjunction with captureChecking language import, print tracing and debug info") val YccVerbose: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycc-verbose", "Print root capabilities with more details") val YccPrintSetup: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycc-print-setup", "Used in conjunction with captureChecking language import, print trees after cc.Setup phase") + val YccNoTasty: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycc-no-tasty", "Used in conjunction with captureChecking language import, do not emit captureChecking-related TASTy annotations") /** Area-specific debug output */ val YexplainLowlevel: Setting[Boolean] = BooleanSetting(ForkSetting, "Yexplain-lowlevel", "When explaining type errors, show types at a lower level.") diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 8cc5aac942a6..739132c5b14f 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1146,6 +1146,20 @@ class Definitions { "reactor.util.annotation.NonNullApi" :: "io.reactivex.annotations.NonNull" :: Nil) + // Capture checking annotations + @tu lazy val CCAnnots: Set[ClassSymbol] = Set( + ReachCapabilityAnnot, + RootCapabilityAnnot, + ReadOnlyCapabilityAnnot, + OnlyCapabilityAnnot, + RequiresCapabilityAnnot, + RetainsAnnot, + RetainsCapAnnot, + RetainsByNameAnnot, + UseAnnot, + ) + + // convenient one-parameter method types def methOfAny(tp: Type): MethodType = MethodType(List(AnyType), tp) def methOfAnyVal(tp: Type): MethodType = MethodType(List(AnyValType), tp) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 4e63c7e973fe..9bd6a0bfb40c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -20,6 +20,7 @@ import collection.mutable import reporting.{Profile, NoProfile} import dotty.tools.tasty.TastyFormat.ASTsSection import quoted.QuotePatterns +import dotty.tools.dotc.config.Feature object TreePickler: class StackSizeExceeded(val mdef: tpd.MemberDef) extends Exception @@ -282,9 +283,11 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { pickleVariances(tpe.hi) } case tpe: AnnotatedType => - writeByte(ANNOTATEDtype) - withLength { pickleType(tpe.parent, richTypes); pickleTree(tpe.annot.tree) } - annotatedTypeTrees += tpe.annot.tree + if !isSkippedCCAnnot(tpe.annot) then + writeByte(ANNOTATEDtype) + withLength { pickleType(tpe.parent, richTypes); pickleTree(tpe.annot.tree) } + annotatedTypeTrees += tpe.annot.tree + else pickleType(tpe.parent, richTypes) case tpe: AndType => writeByte(ANDtype) withLength { pickleType(tpe.tp1, richTypes); pickleType(tpe.tp2, richTypes) } @@ -749,8 +752,10 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { writeByte(BYNAMEtpt) pickleTree(tp) case Annotated(tree, annot) => - writeByte(ANNOTATEDtpt) - withLength { pickleTree(tree); pickleTree(annot) } + if !isSkippedCCAnnot(annot.symbol) then + writeByte(ANNOTATEDtpt) + withLength { pickleTree(tree); pickleTree(annot) } + else pickleTree(tree) case LambdaTypeTree(tparams, body) => writeByte(LAMBDAtpt) withLength { pickleParams(tparams); pickleTree(body) } @@ -927,8 +932,16 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { ann.symbol == defn.BodyAnnot // inline bodies are reconstituted automatically when unpickling } + private def isSkippedCCAnnot(ann: Annotation)(using Context): Boolean = isSkippedCCAnnot(ann.symbol) + private def isSkippedCCAnnot(ann: Symbol)(using Context): Boolean = + if Feature.ccEnabled && !Feature.ccAnnotationsEnabled then + // an annotation symbol can be either a class symbol or a constructor symbol + val ccAnnot = defn.CCAnnots.find(annot => annot == ann || annot.primaryConstructor == ann) + ccAnnot.isDefined + else false + def pickleAnnotation(owner: Symbol, mdef: MemberDef, ann: Annotation)(using Context): Unit = - if !isUnpicklable(owner, ann) then + if !isUnpicklable(owner, ann) && !isSkippedCCAnnot(ann) then writeByte(ANNOTATION) withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) } var treeBuf = annotTrees.lookup(mdef) diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 7aeaeb4e319d..9c3fb8a53e40 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -293,7 +293,7 @@ class Pickler extends Phase { sourceFile = sourceRelativePath, scala2StandardLibrary = Feature.shouldBehaveAsScala2, explicitNulls = ctx.settings.YexplicitNulls.value, - captureChecked = Feature.ccEnabled, + captureChecked = Feature.ccEnabled && Feature.ccAnnotationsEnabled, withPureFuns = Feature.pureFunsEnabled, isJava = isJavaAttr, isOutline = isOutline