Skip to content

Commit a2dd16f

Browse files
committed
Convert -Ycc to language import
Two new experimental language imports: - captureChecking: replaces -Ycc - pureFunctions: Enables pure function syntax A -> B
1 parent 62d3875 commit a2dd16f

File tree

26 files changed

+128
-73
lines changed

26 files changed

+128
-73
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ class Compiler {
8181
new PatternMatcher) :: // Compile pattern matches
8282
List(new TestRecheck.Pre) :: // Test only: run rechecker, enabled under -Yrecheck-test
8383
List(new TestRecheck) :: // Test only: run rechecker, enabled under -Yrecheck-test
84-
List(new CheckCaptures.Pre) :: // Preparations for check captures phase, enabled under -Ycc
85-
List(new CheckCaptures) :: // Check captures, enabled under -Ycc
84+
List(new CheckCaptures.Pre) :: // Preparations for check captures phase, enabled under captureChecking
85+
List(new CheckCaptures) :: // Check captures, enabled under captureChecking
8686
List(new ElimOpaque, // Turn opaque into normal aliases
8787
new sjs.ExplicitJSClasses, // Make all JS classes explicit (Scala.js only)
8888
new ExplicitOuter, // Add accessors to outer classes from nested ones.

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
195195
case arg => arg.typeOpt.widen.isRepeatedParam
196196
}
197197

198-
/** Is tree a type tree of the form `=> T` or (under -Ycc) `{refs}-> T`? */
198+
/** Is tree a type tree of the form `=> T` or (under pureFunctions) `{refs}-> T`? */
199199
def isByNameType(tree: Tree)(using Context): Boolean =
200200
stripByNameType(tree) ne tree
201201

202-
/** Strip `=> T` to `T` and (under -Ycc) `{refs}-> T` to `T` */
202+
/** Strip `=> T` to `T` and (under pureFunctions) `{refs}-> T` to `T` */
203203
def stripByNameType(tree: Tree)(using Context): Tree = unsplice(tree) match
204204
case ByNameTypeTree(t1) => t1
205205
case untpd.CapturingTypeTree(_, parent) =>
@@ -400,12 +400,12 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
400400
}
401401
}
402402

403-
/** Under -Ycc: A builder and extractor for `=> T`, which is an alias for `{*}-> T`.
403+
/** Under pureFunctions: A builder and extractor for `=> T`, which is an alias for `{*}-> T`.
404404
* Only trees of the form `=> T` are matched; trees written directly as `{*}-> T`
405405
* are ignored by the extractor.
406406
*/
407407
object ImpureByNameTypeTree:
408-
408+
409409
def apply(tp: ByNameTypeTree)(using Context): untpd.CapturingTypeTree =
410410
untpd.CapturingTypeTree(
411411
Ident(nme.CAPTURE_ROOT).withSpan(tp.span.startPos) :: Nil, tp)

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
217217

218218
case class Infix()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Infix)
219219

220-
/** Used under -Ycc to mark impure function types `A => B` in `FunctionWithMods` */
220+
/** Used under pureFunctions to mark impure function types `A => B` in `FunctionWithMods` */
221221
case class Impure()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Impure)
222222
}
223223

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Decorators.*, NameOps.*
99
import config.Printers.capt
1010
import util.Property.Key
1111
import tpd.*
12+
import config.Feature
1213

1314
private val Captures: Key[CaptureSet] = Key()
1415
private val BoxedType: Key[BoxedTypeCache] = Key()
@@ -120,11 +121,11 @@ extension (tp: Type)
120121
case _ =>
121122
tp
122123

123-
/** Under -Ycc, map regular function type to impure function type
124+
/** Under pureFunctions, map regular function type to impure function type
124125
*/
125-
def adaptFunctionTypeUnderCC(using Context): Type = tp match
126+
def adaptFunctionTypeUnderPureFuns(using Context): Type = tp match
126127
case AppliedType(fn, args)
127-
if ctx.settings.Ycc.value && defn.isFunctionClass(fn.typeSymbol) =>
128+
if Feature.pureFunsEnabled && defn.isFunctionClass(fn.typeSymbol) =>
128129
val fname = fn.typeSymbol.name
129130
defn.FunctionType(
130131
fname.functionArity,

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Phases.*, DenotTransformers.*, SymDenotations.*
77
import Contexts.*, Names.*, Flags.*, Symbols.*, Decorators.*
88
import Types.*, StdNames.*, Denotations.*
99
import config.Printers.{capt, recheckr}
10-
import config.Config
10+
import config.{Config, Feature}
1111
import ast.{tpd, untpd, Trees}
1212
import Trees.*
1313
import typer.RefChecks.{checkAllOverrides, checkParents}
@@ -26,7 +26,7 @@ object CheckCaptures:
2626

2727
class Pre extends PreRecheck, SymTransformer:
2828

29-
override def isEnabled(using Context) = ctx.settings.Ycc.value
29+
override def isEnabled(using Context) = Feature.ccEnabled
3030

3131
/** Reset `private` flags of parameter accessors so that we can refine them
3232
* in Setup if they have non-empty capture sets. Special handling of some
@@ -133,7 +133,7 @@ class CheckCaptures extends Recheck, SymTransformer:
133133
import CheckCaptures.*
134134

135135
def phaseName: String = "cc"
136-
override def isEnabled(using Context) = ctx.settings.Ycc.value
136+
override def isEnabled(using Context) = Feature.ccEnabled
137137

138138
def newRechecker()(using Context) = CaptureChecker(ctx)
139139

@@ -148,7 +148,7 @@ class CheckCaptures extends Recheck, SymTransformer:
148148
/** Check overrides again, taking capture sets into account.
149149
* TODO: Can we avoid doing overrides checks twice?
150150
* We need to do them here since only at this phase CaptureTypes are relevant
151-
* But maybe we can then elide the check during the RefChecks phase if -Ycc is set?
151+
* But maybe we can then elide the check during the RefChecks phase under captureChecking?
152152
*/
153153
def checkOverrides = new TreeTraverser:
154154
def traverse(t: Tree)(using Context) =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ object Config {
240240
*/
241241
inline val printCaptureSetsAsPrefix = true
242242

243-
/** If true, allow mappping capture set variables under -Ycc with maps that are neither
243+
/** If true, allow mappping capture set variables under captureChecking with maps that are neither
244244
* bijective nor idempotent. We currently do now know how to do this correctly in all
245245
* cases, though.
246246
*/

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ object Feature:
2828
val symbolLiterals = deprecated("symbolLiterals")
2929
val fewerBraces = experimental("fewerBraces")
3030
val saferExceptions = experimental("saferExceptions")
31+
val pureFunctions = experimental("pureFunctions")
32+
val captureChecking = experimental("captureChecking")
3133

3234
/** Is `feature` enabled by by a command-line setting? The enabling setting is
3335
*
@@ -75,6 +77,11 @@ object Feature:
7577

7678
def scala2ExperimentalMacroEnabled(using Context) = enabled(scala2macros)
7779

80+
def pureFunsEnabled(using Context) =
81+
enabled(pureFunctions) || ccEnabled
82+
83+
def ccEnabled(using Context) = enabled(captureChecking)
84+
7885
def sourceVersionSetting(using Context): SourceVersion =
7986
SourceVersion.valueOf(ctx.settings.source.value)
8087

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,8 @@ private sealed trait YSettings:
328328
val YcheckInit: Setting[Boolean] = BooleanSetting("-Ysafe-init", "Ensure safe initialization of objects")
329329
val YrequireTargetName: Setting[Boolean] = BooleanSetting("-Yrequire-targetName", "Warn if an operator is defined without a @targetName annotation")
330330
val YrecheckTest: Setting[Boolean] = BooleanSetting("-Yrecheck-test", "Run basic rechecking (internal test only)")
331-
val Ycc: Setting[Boolean] = BooleanSetting("-Ycc", "Check captured references (warning: extremely experimental and unstable)")
332-
val YccDebug: Setting[Boolean] = BooleanSetting("-Ycc-debug", "Used in conjunction with -Ycc, debug info for captured references")
333-
val YccNoAbbrev: Setting[Boolean] = BooleanSetting("-Ycc-no-abbrev", "Used in conjunction with -Ycc, suppress type abbreviations")
331+
val YccDebug: Setting[Boolean] = BooleanSetting("-Ycc-debug", "Used in conjunction with captureChecking language import, debug info for captured references")
332+
val YccNoAbbrev: Setting[Boolean] = BooleanSetting("-Ycc-no-abbrev", "Used in conjunction with captureChecking language import, suppress type abbreviations")
334333

335334
/** Area-specific debug output */
336335
val YexplainLowlevel: Setting[Boolean] = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import typer.ImportInfo.RootRef
1414
import Comments.CommentsContext
1515
import Comments.Comment
1616
import util.Spans.NoSpan
17+
import config.Feature
1718
import Symbols.requiredModuleRef
1819
import cc.{CapturingType, CaptureSet, EventuallyCapturingType}
1920

@@ -976,7 +977,6 @@ class Definitions {
976977
@tu lazy val BooleanBeanPropertyAnnot: ClassSymbol = requiredClass("scala.beans.BooleanBeanProperty")
977978
@tu lazy val BodyAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Body")
978979
@tu lazy val CapabilityAnnot: ClassSymbol = requiredClass("scala.annotation.capability")
979-
@tu lazy val CaptureCheckedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.CaptureChecked")
980980
@tu lazy val ChildAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Child")
981981
@tu lazy val ContextResultCountAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ContextResultCount")
982982
@tu lazy val ProvisionalSuperClassAnnot: ClassSymbol = requiredClass("scala.annotation.internal.ProvisionalSuperClass")
@@ -1012,6 +1012,7 @@ class Definitions {
10121012
@tu lazy val UncheckedStableAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedStable")
10131013
@tu lazy val UncheckedVarianceAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedVariance")
10141014
@tu lazy val VolatileAnnot: ClassSymbol = requiredClass("scala.volatile")
1015+
@tu lazy val WithPureFunsAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WithPureFuns")
10151016
@tu lazy val FieldMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.field")
10161017
@tu lazy val GetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.getter")
10171018
@tu lazy val ParamMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.param")
@@ -1160,7 +1161,7 @@ class Definitions {
11601161

11611162
/** Extractor for context function types representing by-name parameters, of the form
11621163
* `() ?=> T`.
1163-
* Under -Ycc, this becomes `() ?-> T` or `{r1, ..., rN} () ?-> T`.
1164+
* Under purefunctions, this becomes `() ?-> T` or `{r1, ..., rN} () ?-> T`.
11641165
*/
11651166
object ByNameFunction:
11661167
def apply(tp: Type)(using Context): Type = tp match
@@ -1984,7 +1985,7 @@ class Definitions {
19841985
if (!isInitialized) {
19851986
// force initialization of every symbol that is synthesized or hijacked by the compiler
19861987
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
1987-
++ (JavaEnumClass :: (if ctx.settings.Ycc.value then captureRoot :: Nil else Nil))
1988+
++ (JavaEnumClass :: (if Feature.ccEnabled then captureRoot :: Nil else Nil))
19881989

19891990
isInitialized = true
19901991
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import scala.io.Codec
88
import Int.MaxValue
99
import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._, Types._
1010
import util.Chars.{isOperatorPart, digit2int}
11+
import config.Feature
1112
import Decorators.*
1213
import Definitions._
1314
import nme._
@@ -208,14 +209,14 @@ object NameOps {
208209
if str == mustHave then found = true
209210
idx + str.length
210211
else idx
211-
val start = if ctx.settings.Ycc.value then skip(0, "Impure") else 0
212+
val start = if Feature.pureFunsEnabled then skip(0, "Impure") else 0
212213
skip(skip(start, "Erased"), "Context") == suffixStart
213214
&& found
214215
}
215216

216217
/** Same as `funArity`, except that it returns -1 if the prefix
217218
* is not one of a (possibly empty) concatenation of a subset of
218-
* "Impure" (only under -Ycc), "Erased" and "Context" (in that order).
219+
* "Impure" (only under pureFunctions), "Erased" and "Context" (in that order).
219220
*/
220221
private def checkedFunArity(suffixStart: Int)(using Context): Int =
221222
if isFunctionPrefix(suffixStart) then funArity(suffixStart) else -1

0 commit comments

Comments
 (0)