Skip to content

chore: use language import instead of -Ycompile-scala2-library #23082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/CompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class CompilationUnit protected (val source: SourceFile, val info: CompilationUn
/** Is this the compilation unit of a Java file */
def isJava: Boolean = source.file.ext.isJava

def isScala2 = sourceVersion.map(_.isScala2).getOrElse(false)

/** Is this the compilation unit of a Java file, or TASTy derived from a Java file */
def typedAsJava =
val ext = source.file.ext
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ object desugar {
def isNonEnumCase = !isEnumCase && (isCaseClass || isCaseObject)
val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
// This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
val caseClassInScala2Library = isCaseClass && ctx.settings.YcompileScala2Library.value
val caseClassInScala2Library = isCaseClass && Feature.sourceVersion.isScala2

val originalTparams = constr1.leadingTypeParams
val originalVparamss = asTermOnly(constr1.trailingParamss)
Expand Down Expand Up @@ -922,7 +922,7 @@ object desugar {
val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
cpy.ValDef(vparam)(rhs = EmptyTree))
var flags = Synthetic | constr1.mods.flags & copiedAccessFlags
if ctx.settings.YcompileScala2Library.value then flags &~= Private
if Feature.sourceVersion.isScala2 then flags &~= Private
DefDef(
nme.copy,
joinParams(derivedTparams, copyFirstParams :: copyRestParamss),
Expand Down Expand Up @@ -983,7 +983,7 @@ object desugar {
else {
val appMods =
var flags = Synthetic | constr1.mods.flags & copiedAccessFlags
if ctx.settings.YcompileScala2Library.value then flags &~= Private
if Feature.sourceVersion.isScala2 then flags &~= Private
Modifiers(flags).withPrivateWithin(constr1.mods.privateWithin)
val appParamss =
derivedVparamss.nestedZipWithConserve(constrVparamss)((ap, cp) =>
Expand Down Expand Up @@ -1066,7 +1066,7 @@ object desugar {
paramss // drop leading () that got inserted by class
// TODO: drop this once we do not silently insert empty class parameters anymore
case paramss => paramss
val finalFlag = if ctx.settings.YcompileScala2Library.value then EmptyFlags else Final
val finalFlag = if Feature.sourceVersion.isScala2 then EmptyFlags else Final
// implicit wrapper is typechecked in same scope as constructor, so
// we can reuse the constructor parameters; no derived params are needed.
DefDef(
Expand Down
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Constants.Constant
import scala.collection.mutable

import scala.annotation.tailrec
import dotty.tools.dotc.config.Feature

trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>

Expand Down Expand Up @@ -466,7 +467,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
*/
private def defKind(tree: Tree)(using Context): FlagSet = unsplice(tree) match {
case EmptyTree | _: Import => NoInitsInterface
case tree: TypeDef if ctx.settings.YcompileScala2Library.value =>
case tree: TypeDef if Feature.sourceVersion.isScala2 =>
if (tree.isClassDef) EmptyFlags else NoInitsInterface
case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface
case tree: DefDef =>
Expand All @@ -479,7 +480,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
NoInitsInterface
else if tree.mods.is(Given) && tree.paramss.isEmpty then
EmptyFlags // might become a lazy val: TODO: check whether we need to suppress NoInits once we have new lazy val impl
else if ctx.settings.YcompileScala2Library.value then
else if Feature.sourceVersion.isScala2 then
EmptyFlags
else
NoInits
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ private sealed trait YSettings:
val YshowTreeIds: Setting[Boolean] = BooleanSetting(ForkSetting, "Yshow-tree-ids", "Uniquely tag all tree nodes in debugging output.")
val YfromTastyIgnoreList: Setting[List[String]] = MultiStringSetting(ForkSetting, "Yfrom-tasty-ignore-list", "file", "List of `tasty` files in jar files that will not be loaded when using -from-tasty.")
val YlegacyLazyVals: Setting[Boolean] = BooleanSetting(ForkSetting, "Ylegacy-lazy-vals", "Use legacy (pre 3.3.0) implementation of lazy vals.")
val YcompileScala2Library: Setting[Boolean] = BooleanSetting(ForkSetting, "Ycompile-scala2-library", "Used when compiling the Scala 2 standard library.")
val YprofileEnabled: Setting[Boolean] = BooleanSetting(ForkSetting, "Yprofile-enabled", "Enable profiling.")
val YprofileDestination: Setting[String] = StringSetting(ForkSetting, "Yprofile-destination", "file", "Where to send profiling output - specify a file, default is to the console.", "", depends = List(YprofileEnabled -> true))
val YprofileExternalTool: Setting[List[String]] = PhasesSetting(ForkSetting, "Yprofile-external-tool", "Enable profiling for a phase using an external tool hook. Generally only useful for a single phase.", "typer", depends = List(YprofileEnabled -> true))
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/config/SourceVersion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum SourceVersion:
case `3.7-migration`, `3.7`
case `3.8-migration`, `3.8`
// !!! Keep in sync with scala.runtime.stdlibPatches.language !!!
case `2.13`
case `future-migration`, `future`

case `never` // needed for MigrationVersion.errorFrom if we never want to issue an error
Expand All @@ -39,6 +40,8 @@ enum SourceVersion:
def enablesNamedTuples = isAtLeast(`3.7`)
def enablesBetterFors(using Context) = isAtLeast(`3.7`) && isPreviewEnabled

def isScala2 = this == `2.13`

object SourceVersion extends Property.Key[SourceVersion]:
def defaultSourceVersion = `3.7`

Expand Down
10 changes: 4 additions & 6 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1537,9 +1537,7 @@ class Definitions {
denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted
patch2(denot, patchCls)

if ctx.settings.YcompileScala2Library.value then
()
Comment on lines -1540 to -1541
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since scala.language.2 lives in the patches, we will need to patch the denotations to gain access to it. Otherwise, typer complains because the member is not found.

else if denot.name == tpnme.Predef.moduleClassName && denot.symbol == ScalaPredefModuleClass then
if denot.name == tpnme.Predef.moduleClassName && denot.symbol == ScalaPredefModuleClass then
patchWith(ScalaPredefModuleClassPatch)
else if denot.name == tpnme.language.moduleClassName && denot.symbol == LanguageModuleClass then
patchWith(LanguageModuleClassPatch)
Expand Down Expand Up @@ -1880,7 +1878,7 @@ class Definitions {
|| tp.derivesFrom(defn.PolyFunctionClass) // TODO check for refinement?

private def withSpecMethods(cls: ClassSymbol, bases: List[Name], paramTypes: Set[TypeRef]) =
if !ctx.settings.YcompileScala2Library.value then
if !Feature.sourceVersion.isScala2 then
for base <- bases; tp <- paramTypes do
cls.enter(newSymbol(cls, base.specializedName(List(tp)), Method, ExprType(tp)))
cls
Expand Down Expand Up @@ -1923,7 +1921,7 @@ class Definitions {
case List(x, y) => Tuple2SpecializedParamClasses().contains(x.classSymbol) && Tuple2SpecializedParamClasses().contains(y.classSymbol)
case _ => false
&& base.owner.denot.info.member(base.name.specializedName(args)).exists // when dotc compiles the stdlib there are no specialised classes
&& !ctx.settings.YcompileScala2Library.value // We do not add the specilized TupleN methods/classes when compiling the stdlib
&& !Feature.sourceVersion.isScala2 // We do not add the specilized TupleN methods/classes when compiling the stdlib

def isSpecializableFunction(cls: ClassSymbol, paramTypes: List[Type], retType: Type)(using Context): Boolean =
paramTypes.length <= 2
Expand All @@ -1945,7 +1943,7 @@ class Definitions {
case _ =>
false
})
&& !ctx.settings.YcompileScala2Library.value // We do not add the specilized FunctionN methods/classes when compiling the stdlib
&& !Feature.sourceVersion.isScala2 // We do not add the specilized FunctionN methods/classes when compiling the stdlib

@tu lazy val Function0SpecializedApplyNames: List[TermName] =
for r <- Function0SpecializedReturnTypes
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,10 @@ class Pickler extends Phase {
// assert that Java sources didn't reach Pickler without `-Xjava-tasty`.
assert(ctx.settings.XjavaTasty.value, "unexpected Java source file without -Xjava-tasty")
val isOutline = isJavaAttr // TODO: later we may want outline for Scala sources too

val attributes = Attributes(
sourceFile = sourceRelativePath,
scala2StandardLibrary = ctx.settings.YcompileScala2Library.value,
scala2StandardLibrary = Feature.sourceVersion.isScala2,
explicitNulls = ctx.settings.YexplicitNulls.value,
captureChecked = Feature.ccEnabled,
withPureFuns = Feature.pureFunsEnabled,
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
private var compilingScala2StdLib = false
override def initContext(ctx: FreshContext): Unit =
initContextCalled = true
compilingScala2StdLib = ctx.settings.YcompileScala2Library.value(using ctx)
compilingScala2StdLib = Feature.sourceVersion(using ctx).isScala2

val superAcc: SuperAccessors = new SuperAccessors(thisPhase)
val synthMbr: SyntheticMembers = new SyntheticMembers(thisPhase)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SymDenotations.*, Scopes.*, StdNames.*, NameOps.*, Names.*
import MegaPhase.MiniPhase

import scala.collection.mutable
import dotty.tools.dotc.config.Feature


/** This phase synthesizes specialized methods for FunctionN, this is done
Expand All @@ -25,7 +26,7 @@ class SpecializeApplyMethods extends MiniPhase with InfoTransformer {
override def description: String = SpecializeApplyMethods.description

override def isEnabled(using Context): Boolean =
!ctx.settings.scalajs.value && !ctx.settings.YcompileScala2Library.value
!ctx.settings.scalajs.value && !Feature.sourceVersion.isScala2

private def specApplySymbol(sym: Symbol, args: List[Type], ret: Type)(using Context): Symbol = {
val name = nme.apply.specializedFunction(ret, args)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import util.Spans.Span
import config.Printers.derive
import NullOpsDecorator.*
import scala.runtime.Statics
import dotty.tools.dotc.config.Feature

object SyntheticMembers {

Expand Down Expand Up @@ -79,7 +80,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {

private def existingDef(sym: Symbol, clazz: ClassSymbol)(using Context): Symbol =
val existing = sym.matchingMember(clazz.thisType)
if ctx.settings.YcompileScala2Library.value && clazz.isValueClass && (sym == defn.Any_equals || sym == defn.Any_hashCode) then
if Feature.sourceVersion.isScala2 && clazz.isValueClass && (sym == defn.Any_equals || sym == defn.Any_hashCode) then
NoSymbol
else if existing != sym && !existing.is(Deferred) then
existing
Expand Down Expand Up @@ -168,7 +169,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
case nme.productPrefix if isEnumValue => nameRef
case nme.productPrefix => ownNameLit
case nme.productElement =>
if ctx.settings.YcompileScala2Library.value then productElementBodyForScala2Compat(accessors.length, vrefss.head.head)
if Feature.sourceVersion.isScala2 then productElementBodyForScala2Compat(accessors.length, vrefss.head.head)
else productElementBody(accessors.length, vrefss.head.head)
case nme.productElementName => productElementNameBody(accessors.length, vrefss.head.head)
}
Expand Down Expand Up @@ -720,7 +721,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
val syntheticMembers = serializableObjectMethod(clazz) ::: serializableEnumValueMethod(clazz) ::: caseAndValueMethods(clazz)
checkInlining(syntheticMembers)
val impl1 = cpy.Template(impl)(body = syntheticMembers ::: impl.body)
if ctx.settings.YcompileScala2Library.value then impl1
if Feature.sourceVersion.isScala2 then impl1
else addMirrorSupport(impl1)
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class Namer { typer: Typer =>
tree match {
case tree: TypeDef if tree.isClassDef =>
var flags = checkFlags(tree.mods.flags)
if ctx.settings.YcompileScala2Library.value then
if Feature.sourceVersion.isScala2 then
flags |= Scala2x
val name = checkNoConflict(tree.name, tree.span).asTypeName
val cls =
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3206,7 +3206,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer

checkEnumParent(cls, firstParent)

if defn.ScalaValueClasses()(cls) && ctx.settings.YcompileScala2Library.value then
if defn.ScalaValueClasses()(cls) && Feature.sourceVersion.isScala2 then
constr1.symbol.resetFlag(Private)

val self1 = typed(self)(using ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible
Expand Down
6 changes: 6 additions & 0 deletions library/src/scala/runtime/stdLibPatches/language.scala
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ object language:
@compileTimeOnly("`future-migration` can only be used at compile time in import statements")
object `future-migration`

/** Set source version to 2.13. Effectively, this doesn't change the source language,
* but rather adapts the generated code as if it was compiled with Scala 2.13
*/
@compileTimeOnly("`2.13` can only be used at compile time in import statements")
private[scala] object `2.13`

/** Set source version to 3.0-migration.
*
* @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
Expand Down
6 changes: 3 additions & 3 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,7 @@ object Build {
settings(scala2LibraryBootstrappedSettings).
settings(
moduleName := "scala2-library-cc",
scalacOptions += "-Ycheck:all",
//scalacOptions += "-Ycheck:all",
)

lazy val scala2LibraryBootstrappedSettings = Seq(
Expand All @@ -1248,7 +1248,7 @@ object Build {
Seq("-sourcepath", ((Compile/sourceManaged).value / "scala-library-src").toString)
},
Compile / doc / scalacOptions += "-Ydocument-synthetic-types",
scalacOptions += "-Ycompile-scala2-library",
scalacOptions ++= Seq("-source", "2.13"),
scalacOptions += "-Yscala2-unpickler:never",
scalacOptions += "-Werror:false",
Compile / compile / logLevel.withRank(KeyRanks.Invisible) := Level.Error,
Expand Down Expand Up @@ -1698,7 +1698,7 @@ object Build {
(Test / scalaJSModuleInitializers) ++= build.TestSuiteLinkerOptions.moduleInitializers,

// Perform Ycheck after the Scala.js-specific transformation phases
scalacOptions += "-Ycheck:prepjsinterop,explicitJSClasses,addLocalJSFakeNews",
//scalacOptions += "-Ycheck:prepjsinterop,explicitJSClasses,addLocalJSFakeNews",

Test / jsEnvInput := {
val resourceDir = fetchScalaJSSource.value / "test-suite/js/src/test/resources"
Expand Down
3 changes: 3 additions & 0 deletions project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ object MiMaFilters {
// Scala.js-only class
ProblemFilters.exclude[FinalClassProblem]("scala.scalajs.runtime.AnonFunctionXXL"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.scalajs.runtime.AnonFunctionXXL.this"),

ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.2.13"),
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$2$u002E13$")
),

// Additions since last LTS
Expand Down
2 changes: 1 addition & 1 deletion project/scripts/scala2-library-tasty-mima.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ setTastyVersion $MINOR_TASTY_VERSION_SUPPORTED_BY_TASTY_MIMA 0
# We clean before to make sure all sources are recompiled using the new TASTY version.
# We clean after to make sure no other test will use the TASTy generated with this version.
# We set -Ycheck:all to check that -Ycompile-scala2-library does not gererate inconsistent trees.
"$SBT" 'clean; scala2-library-bootstrapped/clean; reload; set `scala2-library-bootstrapped`/scalacOptions += "-Ycheck:all"; scala2-library-bootstrapped/tastyMiMaReportIssues; clean; scala2-library-bootstrapped/clean'
"$SBT" 'clean; scala2-library-bootstrapped/clean; reload; scala2-library-bootstrapped/tastyMiMaReportIssues; clean; scala2-library-bootstrapped/clean'

setTastyVersion $MINOR_TASTY_VERSION $EXPERIMENTAL_TASTY_VERSION
5 changes: 4 additions & 1 deletion tests/init-global/pos/scala2-library.scala
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
//> using options -Ycompile-scala2-library
package scala

import scala.language.`2.13`

case class UninitializedFieldError(msg: String) extends RuntimeException(msg)
3 changes: 2 additions & 1 deletion tests/printing/posttyper/i22533.check
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[[syntax trees at end of posttyper]] // tests/printing/posttyper/i22533.scala
package <empty> {
package scala {
import scala.language.2.13
@SourceFile("tests/printing/posttyper/i22533.scala") trait A() extends Any {
override def equals(x: Any): Boolean = ???
override def hashCode(): Int = ???
Expand Down
1 change: 0 additions & 1 deletion tests/printing/posttyper/i22533.flags

This file was deleted.

4 changes: 3 additions & 1 deletion tests/printing/posttyper/i22533.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//> using options -Ycompile-scala2-library
package scala

import scala.language.`2.13`

trait A extends Any:
override def equals(x: Any): Boolean = ???
Expand Down
Loading