Skip to content

Commit 992f46e

Browse files
authored
Merge branch 'main' into exclusive-capabilities-v3
2 parents 62b0125 + a25fe5e commit 992f46e

File tree

177 files changed

+3267
-476
lines changed

Some content is hidden

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

177 files changed

+3267
-476
lines changed

.github/workflows/ci.yaml

+7-3
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,10 @@ jobs:
630630
- ${{ github.workspace }}/../../cache/general:/root/.cache
631631
strategy:
632632
matrix:
633-
branch: [main, lts-3.3]
633+
series: [
634+
{repository: scala/scala3, branch: main}, # Scala Next nightly
635+
{repository: scala/scala3-lts, branch: lts-3.3} # Scala LTS nightly
636+
]
634637
needs: [test_non_bootstrapped, test, mima, community_build_a, community_build_b, community_build_c, test_sbt, test_java8]
635638
if: "(github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.repository == 'scala/scala3'"
636639
env:
@@ -660,7 +663,8 @@ jobs:
660663
- name: Git Checkout
661664
uses: actions/checkout@v4
662665
with:
663-
ref: ${{ matrix.branch }}
666+
repository: ${{ matrix.series.repository }}
667+
ref: ${{ matrix.series.branch }}
664668

665669
- name: Add SBT proxy repositories
666670
run: cp -vf .github/workflows/repositories /root/.sbt/ ; true
@@ -832,7 +836,7 @@ jobs:
832836
sha256sum "${msiInstaller}" > "${msiInstaller}.sha256"
833837
834838
- name: Install GH CLI
835-
uses: dev-hanz-ops/[email protected].0
839+
uses: dev-hanz-ops/[email protected].1
836840
with:
837841
gh-cli-version: 2.59.0
838842

.github/workflows/lts-backport.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
with:
1616
fetch-depth: 0
1717
- uses: coursier/cache-action@v6
18-
- uses: VirtusLab/[email protected].1
18+
- uses: VirtusLab/[email protected].2
1919
- run: scala-cli ./project/scripts/addToBackportingProject.scala -- ${{ github.sha }}
2020
env:
2121
GRAPHQL_API_TOKEN: ${{ secrets.GRAPHQL_API_TOKEN }}

.github/workflows/spec.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
env:
5050
USER_FOR_TEST: ${{ secrets.SPEC_DEPLOY_USER }}
5151
if: ${{ env.USER_FOR_TEST != '' }}
52-
uses: burnett01/[email protected].1
52+
uses: burnett01/[email protected].2
5353
with:
5454
switches: -rzv
5555
path: docs/_spec/_site/

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import parsing.Parser
88
import Phases.Phase
99
import transform.*
1010
import backend.jvm.{CollectSuperCalls, GenBCode}
11-
import localopt.StringInterpolatorOpt
11+
import localopt.{StringInterpolatorOpt, DropForMap}
1212

1313
/** The central class of the dotc compiler. The job of a compiler is to create
1414
* runs, which process given `phases` in a given `rootContext`.
@@ -68,7 +68,8 @@ class Compiler {
6868
new InlineVals, // Check right hand-sides of an `inline val`s
6969
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
7070
new ElimRepeated, // Rewrite vararg parameters and arguments
71-
new RefChecks) :: // Various checks mostly related to abstract members and overriding
71+
new RefChecks, // Various checks mostly related to abstract members and overriding
72+
new DropForMap) :: // Drop unused trailing map calls in for comprehensions
7273
List(new semanticdb.ExtractSemanticDB.AppendDiagnostics) :: // Attach warnings to extracted SemanticDB and write to .semanticdb file
7374
List(new init.Checker) :: // Check initialization of objects
7475
List(new ProtectedAccessors, // Add accessors for protected members

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import Run.Progress
3838
import scala.compiletime.uninitialized
3939
import dotty.tools.dotc.transform.MegaPhase
4040
import dotty.tools.dotc.transform.Pickler.AsyncTastyHolder
41+
import java.util.{Timer, TimerTask}
4142

4243
/** A compiler run. Exports various methods to compile source files */
4344
class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with ConstraintRunInfo {
@@ -382,7 +383,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
382383
initializeAsyncTasty()
383384
else () => {}
384385

385-
runPhases(allPhases = fusedPhases)(using runCtx)
386+
showProgress(runPhases(allPhases = fusedPhases)(using runCtx))
386387
cancelAsyncTasty()
387388

388389
ctx.reporter.finalizeReporting()
@@ -433,6 +434,26 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
433434
process()(using unitCtx)
434435
}
435436

437+
/** If set to true, prints every 10 seconds the files currently being compiled.
438+
* Turn this flag on if you want to find out which test among many takes more time
439+
* to compile than the others or causes an infinite loop in the compiler.
440+
*/
441+
private inline val debugPrintProgress = false
442+
443+
/** Period between progress reports, in ms */
444+
private inline val printProgressPeriod = 10000
445+
446+
/** Shows progress if debugPrintProgress is true */
447+
private def showProgress(proc: => Unit)(using Context): Unit =
448+
if !debugPrintProgress then proc
449+
else
450+
val watchdog = new TimerTask:
451+
def run() = println(i"[compiling $units]")
452+
try
453+
new Timer().schedule(watchdog, printProgressPeriod, printProgressPeriod)
454+
proc
455+
finally watchdog.cancel()
456+
436457
private sealed trait PrintedTree
437458
private /*final*/ case class SomePrintedTree(phase: String, tree: String) extends PrintedTree
438459
private object NoPrintedTree extends PrintedTree

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

+20-12
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ object desugar {
6464
*/
6565
val PolyFunctionApply: Property.Key[Unit] = Property.StickyKey()
6666

67+
/** An attachment key to indicate that an Apply is created as a last `map`
68+
* scall in a for-comprehension.
69+
*/
70+
val TrailingForMap: Property.Key[Unit] = Property.StickyKey()
71+
6772
/** What static check should be applied to a Match? */
6873
enum MatchCheck {
6974
case None, Exhaustive, IrrefutablePatDef, IrrefutableGenFrom
@@ -418,6 +423,7 @@ object desugar {
418423
.withMods(Modifiers(
419424
meth.mods.flags & (AccessFlags | Synthetic) | (vparam.mods.flags & Inline),
420425
meth.mods.privateWithin))
426+
.withSpan(vparam.rhs.span)
421427
val rest = defaultGetters(vparams :: paramss1, n + 1)
422428
if vparam.rhs.isEmpty then rest else defaultGetter :: rest
423429
case _ :: paramss1 => // skip empty parameter lists and type parameters
@@ -1966,14 +1972,8 @@ object desugar {
19661972
*
19671973
* 3.
19681974
*
1969-
* for (P <- G) yield P ==> G
1970-
*
1971-
* If betterFors is enabled, P is a variable or a tuple of variables and G is not a withFilter.
1972-
*
19731975
* for (P <- G) yield E ==> G.map (P => E)
19741976
*
1975-
* Otherwise
1976-
*
19771977
* 4.
19781978
*
19791979
* for (P_1 <- G_1; P_2 <- G_2; ...) ...
@@ -2146,14 +2146,20 @@ object desugar {
21462146
case (Tuple(ts1), Tuple(ts2)) => ts1.corresponds(ts2)(deepEquals)
21472147
case _ => false
21482148

2149+
def markTrailingMap(aply: Apply, gen: GenFrom, selectName: TermName): Unit =
2150+
if betterForsEnabled
2151+
&& selectName == mapName
2152+
&& gen.checkMode != GenCheckMode.Filtered // results of withFilter have the wrong type
2153+
&& (deepEquals(gen.pat, body) || deepEquals(body, Tuple(Nil)))
2154+
then
2155+
aply.putAttachment(TrailingForMap, ())
2156+
21492157
enums match {
21502158
case Nil if betterForsEnabled => body
21512159
case (gen: GenFrom) :: Nil =>
2152-
if betterForsEnabled
2153-
&& gen.checkMode != GenCheckMode.Filtered // results of withFilter have the wrong type
2154-
&& deepEquals(gen.pat, body)
2155-
then gen.expr // avoid a redundant map with identity
2156-
else Apply(rhsSelect(gen, mapName), makeLambda(gen, body))
2160+
val aply = Apply(rhsSelect(gen, mapName), makeLambda(gen, body))
2161+
markTrailingMap(aply, gen, mapName)
2162+
aply
21572163
case (gen: GenFrom) :: (rest @ (GenFrom(_, _, _) :: _)) =>
21582164
val cont = makeFor(mapName, flatMapName, rest, body)
21592165
Apply(rhsSelect(gen, flatMapName), makeLambda(gen, cont))
@@ -2164,7 +2170,9 @@ object desugar {
21642170
val selectName =
21652171
if rest.exists(_.isInstanceOf[GenFrom]) then flatMapName
21662172
else mapName
2167-
Apply(rhsSelect(gen, selectName), makeLambda(gen, cont))
2173+
val aply = Apply(rhsSelect(gen, selectName), makeLambda(gen, cont))
2174+
markTrailingMap(aply, gen, selectName)
2175+
aply
21682176
case (gen: GenFrom) :: (rest @ GenAlias(_, _) :: _) =>
21692177
val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
21702178
val pats = valeqs map { case GenAlias(pat, _) => pat }

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
606606
// For example, `(x: T, y: x.f.type) => Unit`. In this case, when we
607607
// substitute `x.f.type`, `x` becomes a `TermParamRef`. But the new method
608608
// type is still under initialization and `paramInfos` is still `null`,
609-
// so the new `NamedType` will not have a denoation.
609+
// so the new `NamedType` will not have a denotation.
610610
def adaptedInfo(psym: Symbol, info: mt.PInfo): mt.PInfo = mt.companion match
611611
case mtc: MethodTypeCompanion => mtc.adaptParamInfo(psym, info).asInstanceOf[mt.PInfo]
612612
case _ => info

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

+27-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import SourceVersion.*
1111
import reporting.Message
1212
import NameKinds.QualifiedName
1313
import Annotations.ExperimentalAnnotation
14+
import Annotations.PreviewAnnotation
1415
import Settings.Setting.ChoiceWithHelp
1516

1617
object Feature:
@@ -28,9 +29,7 @@ object Feature:
2829
val dependent = experimental("dependent")
2930
val erasedDefinitions = experimental("erasedDefinitions")
3031
val symbolLiterals = deprecated("symbolLiterals")
31-
val fewerBraces = experimental("fewerBraces")
3232
val saferExceptions = experimental("saferExceptions")
33-
val clauseInterleaving = experimental("clauseInterleaving")
3433
val pureFunctions = experimental("pureFunctions")
3534
val captureChecking = experimental("captureChecking")
3635
val into = experimental("into")
@@ -39,6 +38,7 @@ object Feature:
3938
val betterMatchTypeExtractors = experimental("betterMatchTypeExtractors")
4039
val quotedPatternsWithPolymorphicFunctions = experimental("quotedPatternsWithPolymorphicFunctions")
4140
val betterFors = experimental("betterFors")
41+
val packageObjectValues = experimental("packageObjectValues")
4242

4343
def experimentalAutoEnableFeatures(using Context): List[TermName] =
4444
defn.languageExperimentalFeatures
@@ -60,9 +60,7 @@ object Feature:
6060
(dependent, "Allow dependent method types"),
6161
(erasedDefinitions, "Allow erased definitions"),
6262
(symbolLiterals, "Allow symbol literals"),
63-
(fewerBraces, "Enable support for using indentation for arguments"),
6463
(saferExceptions, "Enable safer exceptions"),
65-
(clauseInterleaving, "Enable clause interleaving"),
6664
(pureFunctions, "Enable pure functions for capture checking"),
6765
(captureChecking, "Enable experimental capture checking"),
6866
(into, "Allow into modifier on parameter types"),
@@ -124,9 +122,6 @@ object Feature:
124122

125123
def namedTypeArgsEnabled(using Context) = enabled(namedTypeArguments)
126124

127-
def clauseInterleavingEnabled(using Context) =
128-
sourceVersion.isAtLeast(`3.6`) || enabled(clauseInterleaving)
129-
130125
def betterForsEnabled(using Context) = enabled(betterFors)
131126

132127
def genericNumberLiteralsEnabled(using Context) = enabled(genericNumberLiterals)
@@ -169,9 +164,6 @@ object Feature:
169164
def migrateTo3(using Context): Boolean =
170165
sourceVersion == `3.0-migration`
171166

172-
def fewerBracesEnabled(using Context) =
173-
sourceVersion.isAtLeast(`3.3`) || enabled(fewerBraces)
174-
175167
/** If current source migrates to `version`, issue given warning message
176168
* and return `true`, otherwise return `false`.
177169
*/
@@ -242,4 +234,29 @@ object Feature:
242234
true
243235
else
244236
false
237+
238+
def isPreviewEnabled(using Context): Boolean =
239+
ctx.settings.preview.value
240+
241+
def checkPreviewFeature(which: String, srcPos: SrcPos, note: => String = "")(using Context) =
242+
if !isPreviewEnabled then
243+
report.error(previewUseSite(which) + note, srcPos)
244+
245+
def checkPreviewDef(sym: Symbol, srcPos: SrcPos)(using Context) = if !isPreviewEnabled then
246+
val previewSym =
247+
if sym.hasAnnotation(defn.PreviewAnnot) then sym
248+
else if sym.owner.hasAnnotation(defn.PreviewAnnot) then sym.owner
249+
else NoSymbol
250+
val msg =
251+
previewSym.getAnnotation(defn.PreviewAnnot).collectFirst {
252+
case PreviewAnnotation(msg) if msg.nonEmpty => s": $msg"
253+
}.getOrElse("")
254+
val markedPreview =
255+
if previewSym.exists
256+
then i"$previewSym is marked @preview$msg"
257+
else i"$sym inherits @preview$msg"
258+
report.error(i"${markedPreview}\n\n${previewUseSite("definition")}", srcPos)
259+
260+
private def previewUseSite(which: String): String =
261+
s"Preview $which may only be used when compiling with the `-preview` compiler flag"
245262
end Feature

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ object PathResolver {
5353
def classPathEnv: String = envOrElse("CLASSPATH", "")
5454
def sourcePathEnv: String = envOrElse("SOURCEPATH", "")
5555

56-
//using propOrNone/getOrElse instead of propOrElse so that searchForBootClasspath is lazy evaluated
57-
def javaBootClassPath: String = propOrNone("sun.boot.class.path") getOrElse searchForBootClasspath
56+
def javaBootClassPath: String = propOrElse("sun.boot.class.path", searchForBootClasspath)
5857

5958
def javaExtDirs: String = propOrEmpty("java.ext.dirs")
6059
def scalaHome: String = propOrEmpty("scala.home")

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ trait PropertiesTrait {
4545

4646
def propIsSet(name: String): Boolean = System.getProperty(name) != null
4747
def propIsSetTo(name: String, value: String): Boolean = propOrNull(name) == value
48-
def propOrElse(name: String, alt: String): String = System.getProperty(name, alt)
48+
def propOrElse(name: String, alt: => String): String = Option(System.getProperty(name)).getOrElse(alt)
4949
def propOrEmpty(name: String): String = propOrElse(name, "")
5050
def propOrNull(name: String): String = propOrElse(name, null)
5151
def propOrNone(name: String): Option[String] = Option(propOrNull(name))
5252
def propOrFalse(name: String): Boolean = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
5353
def setProp(name: String, value: String): String = System.setProperty(name, value)
5454
def clearProp(name: String): String = System.clearProperty(name)
5555

56-
def envOrElse(name: String, alt: String): String = Option(System getenv name) getOrElse alt
56+
def envOrElse(name: String, alt: => String): String = Option(System getenv name) getOrElse alt
5757
def envOrNone(name: String): Option[String] = Option(System getenv name)
5858

5959
// for values based on propFilename
60-
def scalaPropOrElse(name: String, alt: String): String = scalaProps.getProperty(name, alt)
60+
def scalaPropOrElse(name: String, alt: => String): String = scalaProps.getProperty(name, alt)
6161
def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
6262
def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name))
6363

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ trait CommonScalaSettings:
116116
val unchecked: Setting[Boolean] = BooleanSetting(RootSetting, "unchecked", "Enable additional warnings where generated code depends on assumptions.", initialValue = true, aliases = List("--unchecked"))
117117
val language: Setting[List[ChoiceWithHelp[String]]] = MultiChoiceHelpSetting(RootSetting, "language", "feature", "Enable one or more language features.", choices = ScalaSettingsProperties.supportedLanguageFeatures, legacyChoices = ScalaSettingsProperties.legacyLanguageFeatures, default = Nil, aliases = List("--language"))
118118
val experimental: Setting[Boolean] = BooleanSetting(RootSetting, "experimental", "Annotate all top-level definitions with @experimental. This enables the use of experimental features anywhere in the project.")
119+
val preview: Setting[Boolean] = BooleanSetting(RootSetting, "preview", "Enable the use of preview features anywhere in the project.")
119120

120121
/* Coverage settings */
121122
val coverageOutputDir = PathSetting(RootSetting, "coverage-out", "Destination for coverage classfiles and instrumentation data.", "", aliases = List("--coverage-out"))
@@ -184,9 +185,10 @@ private sealed trait WarningSettings:
184185
ChoiceWithHelp("linted", "Enable -Wunused:imports,privates,locals,implicits"),
185186
ChoiceWithHelp(
186187
name = "strict-no-implicit-warn",
187-
description = "Same as -Wunused:import, only for imports of explicit named members.\n" +
188-
"NOTE : This overrides -Wunused:imports and NOT set by -Wunused:all"
188+
description = """Same as -Wunused:imports, only for imports of explicit named members.
189+
|NOTE : This overrides -Wunused:imports and NOT set by -Wunused:all""".stripMargin
189190
),
191+
ChoiceWithHelp("unsafe-warn-patvars", "Deprecated alias for `patvars`"),
190192
),
191193
default = Nil
192194
)
@@ -211,7 +213,7 @@ private sealed trait WarningSettings:
211213
def params(using Context) = allOr("params")
212214
def privates(using Context) =
213215
allOr("privates") || allOr("linted")
214-
def patvars(using Context) = allOr("patvars")
216+
def patvars(using Context) = allOr("patvars") || isChoiceSet("unsafe-warn-patvars")
215217
def inlined(using Context) = isChoiceSet("inlined")
216218
def linted(using Context) =
217219
allOr("linted")

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

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ enum SourceVersion:
3131

3232
def isAtMost(v: SourceVersion) = stable.ordinal <= v.ordinal
3333

34+
def enablesFewerBraces = isAtLeast(`3.3`)
35+
def enablesClauseInterleaving = isAtLeast(`3.6`)
36+
def enablesNewGivens = isAtLeast(`3.6`)
37+
def enablesNamedTuples = isAtLeast(`3.7`)
38+
3439
object SourceVersion extends Property.Key[SourceVersion]:
3540
def defaultSourceVersion = `3.7`
3641

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

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ trait WrappedProperties extends PropertiesTrait {
1414
protected def propCategory: String = "wrapped"
1515
protected def pickJarBasedOn: Class[?] = this.getClass
1616

17-
override def propIsSet(name: String): Boolean = wrap(super.propIsSet(name)) exists (x => x)
18-
override def propOrElse(name: String, alt: String): String = wrap(super.propOrElse(name, alt)) getOrElse alt
19-
override def setProp(name: String, value: String): String = wrap(super.setProp(name, value)).orNull
20-
override def clearProp(name: String): String = wrap(super.clearProp(name)).orNull
21-
override def envOrElse(name: String, alt: String): String = wrap(super.envOrElse(name, alt)) getOrElse alt
22-
override def envOrNone(name: String): Option[String] = wrap(super.envOrNone(name)).flatten
17+
override def propIsSet(name: String): Boolean = wrap(super.propIsSet(name)) exists (x => x)
18+
override def propOrElse(name: String, alt: => String): String = wrap(super.propOrElse(name, alt)) getOrElse alt
19+
override def setProp(name: String, value: String): String = wrap(super.setProp(name, value)).orNull
20+
override def clearProp(name: String): String = wrap(super.clearProp(name)).orNull
21+
override def envOrElse(name: String, alt: => String): String = wrap(super.envOrElse(name, alt)) getOrElse alt
22+
override def envOrNone(name: String): Option[String] = wrap(super.envOrNone(name)).flatten
2323

2424
def systemProperties: Iterator[(String, String)] = {
2525
import scala.jdk.CollectionConverters.*

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -303,5 +303,16 @@ object Annotations {
303303
case annot @ ExperimentalAnnotation(msg) => ExperimentalAnnotation(msg, annot.tree.span)
304304
}
305305
}
306-
306+
307+
object PreviewAnnotation {
308+
/** Matches and extracts the message from an instance of `@preview(msg)`
309+
* Returns `Some("")` for `@preview` with no message.
310+
*/
311+
def unapply(a: Annotation)(using Context): Option[String] =
312+
if a.symbol ne defn.PreviewAnnot then
313+
None
314+
else a.argumentConstant(0) match
315+
case Some(Constant(msg: String)) => Some(msg)
316+
case _ => Some("")
317+
}
307318
}

0 commit comments

Comments
 (0)