Skip to content

Commit 7bdf89e

Browse files
authored
Merge pull request scala#10428 from dotty-staging/drop-scalaShadowing
Drop scala shadowing and DottyPredef
2 parents 1b7d63c + c351094 commit 7bdf89e

35 files changed

+267
-84
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ class Driver {
7575
inContext(ictx) {
7676
if !ctx.settings.YdropComments.value || ctx.mode.is(Mode.ReadComments) then
7777
ictx.setProperty(ContextDoc, new ContextDocstrings)
78-
if Feature.enabledBySetting(nme.Scala2Compat) then
79-
report.warning("-language:Scala2Compat will go away; use -source 3.0-migration instead")
8078
val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired)
8179
fromTastySetup(fileNames, ctx)
8280
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ object Feature:
8282
case Some(v) => v
8383
case none => sourceVersionSetting
8484

85-
def migrateTo3(using Context): Boolean =
86-
sourceVersion == `3.0-migration` || enabledBySetting(nme.Scala2Compat)
85+
def migrateTo3(using Context): Boolean = sourceVersion == `3.0-migration`
8786

8887
/** If current source migrates to `version`, issue given warning message
8988
* and return `true`, otherwise return `false`.

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

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import unpickleScala2.Scala2Unpickler.ensureConstructor
99
import scala.collection.mutable
1010
import collection.mutable
1111
import Denotations.SingleDenotation
12-
import util.SimpleIdentityMap
12+
import util.{SimpleIdentityMap, SourceFile, NoSource}
1313
import typer.ImportInfo.RootRef
1414

1515
import scala.annotation.tailrec
@@ -252,6 +252,7 @@ class Definitions {
252252
* or classes with the same name. But their binary artifacts are
253253
* in `scalaShadowing` so they don't clash with the same-named `scala`
254254
* members at runtime.
255+
* It is used only for non-bootstrapped code
255256
*/
256257
@tu lazy val ScalaShadowingPackage: TermSymbol = requiredPackage(nme.scalaShadowing)
257258

@@ -481,12 +482,12 @@ class Definitions {
481482
newPermanentSymbol(ScalaPackageClass, tpnme.IMPLICITkw, EmptyFlags, TypeBounds.empty).entered
482483
def ImplicitScrutineeTypeRef: TypeRef = ImplicitScrutineeTypeSym.typeRef
483484

484-
485485
@tu lazy val ScalaPredefModule: Symbol = requiredModule("scala.Predef")
486486
@tu lazy val Predef_conforms : Symbol = ScalaPredefModule.requiredMethod(nme.conforms_)
487487
@tu lazy val Predef_classOf : Symbol = ScalaPredefModule.requiredMethod(nme.classOf)
488488
@tu lazy val Predef_identity : Symbol = ScalaPredefModule.requiredMethod(nme.identity)
489489
@tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???)
490+
@tu lazy val ScalaPredefModuleClass: ClassSymbol = ScalaPredefModule.moduleClass.asClass
490491

491492
@tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<")
492493
@tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl)
@@ -510,7 +511,7 @@ class Definitions {
510511
// will return "null" when called recursively, see #1856.
511512
def DottyPredefModule: Symbol = {
512513
if (myDottyPredefModule == null) {
513-
myDottyPredefModule = requiredModule("dotty.DottyPredef")
514+
myDottyPredefModule = getModuleIfDefined("dotty.DottyPredef")
514515
assert(myDottyPredefModule != null)
515516
}
516517
myDottyPredefModule
@@ -782,6 +783,7 @@ class Definitions {
782783
@tu lazy val Mirror_SingletonProxyClass: ClassSymbol = requiredClass("scala.deriving.Mirror.SingletonProxy")
783784

784785
@tu lazy val LanguageModule: Symbol = requiredModule("scala.language")
786+
@tu lazy val LanguageModuleClass: Symbol = LanguageModule.moduleClass.asClass
785787
@tu lazy val LanguageExperimentalModule: Symbol = requiredModule("scala.language.experimental")
786788
@tu lazy val NonLocalReturnControlClass: ClassSymbol = requiredClass("scala.runtime.NonLocalReturnControl")
787789
@tu lazy val SelectableClass: ClassSymbol = requiredClass("scala.Selectable")
@@ -1101,6 +1103,65 @@ class Definitions {
11011103
|| sym.owner == CompiletimeOpsPackageObjectString.moduleClass && compiletimePackageStringTypes.contains(sym.name)
11021104
)
11031105

1106+
// ----- Scala-2 library patches --------------------------------------
1107+
1108+
/** The `scala.runtime.stdLibPacthes` package contains objects
1109+
* that contain defnitions that get added as members to standard library
1110+
* objects with the same name.
1111+
*/
1112+
@tu lazy val StdLibPatchesPackage: TermSymbol = requiredPackage("scala.runtime.stdLibPatches")
1113+
@tu private lazy val ScalaPredefModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.Predef").moduleClass
1114+
@tu private lazy val LanguageModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.language").moduleClass
1115+
1116+
/** If `sym` is a patched library class, the source file of its patch class,
1117+
* otherwise `NoSource`
1118+
*/
1119+
def patchSource(sym: Symbol)(using Context): SourceFile =
1120+
if sym == ScalaPredefModuleClass then ScalaPredefModuleClassPatch.source
1121+
else if sym == LanguageModuleClass then LanguageModuleClassPatch.source
1122+
else NoSource
1123+
1124+
/** A finalizer that patches standard library classes.
1125+
* It copies all non-private, non-synthetic definitions from `patchCls`
1126+
* to `denot` while changing their owners to `denot`. Before that it deletes
1127+
* any definitions of `denot` that have the same name as one of the copied
1128+
* definitions.
1129+
*
1130+
* If an object is present in both the original class and the patch class,
1131+
* it is not overwritten. Instead its members are copied recursively.
1132+
*
1133+
* To avpid running into cycles on bootstrap, patching happens only if `patchCls`
1134+
* is read from a classfile.
1135+
*/
1136+
def patchStdLibClass(denot: ClassDenotation)(using Context): Unit =
1137+
1138+
def patch2(denot: ClassDenotation, patchCls: Symbol): Unit =
1139+
val scope = denot.info.decls.openForMutations
1140+
def recurse(patch: Symbol) = patch.is(Module) && scope.lookup(patch.name).exists
1141+
if patchCls.exists then
1142+
val patches = patchCls.info.decls.filter(patch =>
1143+
!patch.isConstructor && !patch.isOneOf(PrivateOrSynthetic))
1144+
for patch <- patches if !recurse(patch) do
1145+
val e = scope.lookupEntry(patch.name)
1146+
if e != null then scope.unlink(e)
1147+
for patch <- patches do
1148+
patch.ensureCompleted()
1149+
if !recurse(patch) then
1150+
patch.denot = patch.denot.copySymDenotation(owner = denot.symbol)
1151+
scope.enter(patch)
1152+
else if patch.isClass then
1153+
patch2(scope.lookup(patch.name).asClass, patch)
1154+
1155+
def patchWith(patchCls: Symbol) =
1156+
denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted
1157+
patch2(denot, patchCls)
1158+
1159+
if denot.name == tpnme.Predef.moduleClassName && denot.symbol == ScalaPredefModuleClass then
1160+
patchWith(ScalaPredefModuleClassPatch)
1161+
else if denot.name == tpnme.language.moduleClassName && denot.symbol == LanguageModuleClass then
1162+
patchWith(LanguageModuleClassPatch)
1163+
end patchStdLibClass
1164+
11041165
// ----- Symbol sets ---------------------------------------------------
11051166

11061167
@tu lazy val AbstractFunctionType: Array[TypeRef] = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0)

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,6 @@ object StdNames {
386386
val Ref: N = "Ref"
387387
val RootPackage: N = "RootPackage"
388388
val RootClass: N = "RootClass"
389-
val Scala2Compat: N = "Scala2Compat"
390389
val Select: N = "Select"
391390
val Shape: N = "Shape"
392391
val StringContext: N = "StringContext"

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

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -428,23 +428,21 @@ object Symbols {
428428
private var mySource: SourceFile = NoSource
429429

430430
final def sourceOfClass(using Context): SourceFile = {
431-
if (!mySource.exists && !denot.is(Package))
431+
if !mySource.exists && !denot.is(Package) then
432432
// this allows sources to be added in annotations after `sourceOfClass` is first called
433-
mySource = {
434-
val file = associatedFile
435-
if (file != null && file.extension != "class") ctx.getSource(file)
436-
else {
437-
def sourceFromTopLevel(using Context) =
438-
denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match {
439-
case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match {
433+
val file = associatedFile
434+
if file != null && file.extension != "class" then
435+
mySource = ctx.getSource(file)
436+
else
437+
mySource = defn.patchSource(this)
438+
if !mySource.exists then
439+
mySource = atPhaseNoLater(flattenPhase) {
440+
denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match
441+
case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match
440442
case Some(Constant(path: String)) => ctx.getSource(path)
441443
case none => NoSource
442-
}
443444
case none => NoSource
444-
}
445-
atPhaseNoLater(flattenPhase)(sourceFromTopLevel)
446-
}
447-
}
445+
}
448446
mySource
449447
}
450448

@@ -880,6 +878,13 @@ object Symbols {
880878
staticRef(name).requiredSymbol("object", name)(_.is(Module)).asTerm
881879
}
882880

881+
/** Get module symbol if the module is either defined in current compilation run
882+
* or present on classpath. Returns NoSymbol otherwise.
883+
*/
884+
def getModuleIfDefined(path: PreName)(using Context): Symbol =
885+
staticRef(path.toTermName, generateStubs = false)
886+
.disambiguate(_.is(Module)).symbol
887+
883888
def requiredModuleRef(path: PreName)(using Context): TermRef = requiredModule(path).termRef
884889

885890
def requiredMethod(path: PreName)(using Context): TermSymbol = {

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,9 @@ class TreePickler(pickler: TastyPickler) {
764764

765765
def pickle(trees: List[Tree])(using Context): Unit = {
766766
trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree))
767-
def missing = forwardSymRefs.keysIterator.map(sym => sym.showLocated + "(line " + sym.srcPos.line + ")").toList
767+
def missing = forwardSymRefs.keysIterator
768+
.map(sym => i"${sym.showLocated} (line ${sym.srcPos.line}) #${sym.id}")
769+
.toList
768770
assert(forwardSymRefs.isEmpty, i"unresolved symbols: $missing%, % when pickling ${ctx.source}")
769771
}
770772

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,7 @@ class TreeUnpickler(reader: TastyReader,
940940
val stats = rdr.readIndexedStats(localDummy, end)
941941
tparams ++ vparams ++ stats
942942
})
943+
defn.patchStdLibClass(cls)
943944
setSpan(start,
944945
untpd.Template(constr, mappedParents, Nil, self, lazyStats)
945946
.withType(localDummy.termRef))

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ object Scala2Unpickler {
111111

112112
denot.info = tempInfo.finalized(normalizedParents)
113113
denot.ensureTypeParamsInCorrectOrder()
114+
defn.patchStdLibClass(denot)
114115
}
115116
}
116117

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,9 @@ class TreeChecker extends Phase with SymTransformer {
446446
val symbolsNotDefined = decls -- defined - constr.symbol
447447

448448
assert(symbolsNotDefined.isEmpty,
449-
i" $cls tree does not define members: ${symbolsNotDefined.toList}%, %\n" +
450-
i"expected: ${decls.toList}%, %\n" +
451-
i"defined: ${defined}%, %")
449+
i" $cls tree does not define members: ${symbolsNotDefined.toList}%, %\n" +
450+
i"expected: ${decls.toList}%, %\n" +
451+
i"defined: ${defined}%, %")
452452

453453
super.typedClassDef(cdef, cls)
454454
}
@@ -540,6 +540,12 @@ class TreeChecker extends Phase with SymTransformer {
540540
super.typedWhileDo(tree)
541541
}
542542

543+
override def typedPackageDef(tree: untpd.PackageDef)(using Context): Tree =
544+
if tree.symbol == defn.StdLibPatchesPackage then
545+
promote(tree) // don't check stdlib patches, since their symbols were highjacked by stdlib classes
546+
else
547+
super.typedPackageDef(tree)
548+
543549
override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(using Context): Tree =
544550
tree
545551

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,7 @@ class Namer { typer: Typer =>
11991199
cls.setNoInitsFlags(parentsKind(parents), untpd.bodyKind(rest))
12001200
if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(StableRealizable)
12011201
processExports(using localCtx)
1202+
defn.patchStdLibClass(denot.asClass)
12021203
}
12031204
}
12041205

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package dotty
2+
3+
object DottyPredef
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package scalaShadowing
2+
3+
class D_u_m_m_y

library/src/scalaShadowing/language.scala renamed to library/src-non-bootstrapped/scalaShadowing/language.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,6 @@ object language {
225225
object genericNumberLiterals
226226
}
227227

228-
/** Where imported, a backwards compatibility mode for Scala2 is enabled */
229-
object Scala2Compat
230-
231228
/** Where imported, auto-tupling is disabled */
232229
object noAutoTupling
233230

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package scala.runtime.stdLibPatches
2+
3+
object Predef:
4+
import compiletime.summonFrom
5+
6+
inline def assert(inline assertion: Boolean, inline message: => Any): Unit =
7+
if !assertion then scala.runtime.Scala3RunTime.assertFailed(message)
8+
9+
inline def assert(inline assertion: Boolean): Unit =
10+
if !assertion then scala.runtime.Scala3RunTime.assertFailed()
11+
12+
/**
13+
* Retrieve the single value of a type with a unique inhabitant.
14+
*
15+
* @example {{{
16+
* object Foo
17+
* val foo = valueOf[Foo.type]
18+
* // foo is Foo.type = Foo
19+
*
20+
* val bar = valueOf[23]
21+
* // bar is 23.type = 23
22+
* }}}
23+
* @group utilities
24+
*/
25+
inline def valueOf[T]: T = summonFrom {
26+
case ev: ValueOf[T] => ev.value
27+
}
28+
29+
/** Summon a given value of type `T`. Usually, the argument is not passed explicitly.
30+
*
31+
* @tparam T the type of the value to be summoned
32+
* @return the given value typed as the provided type parameter
33+
*/
34+
inline def summon[T](using x: T): x.type = x
35+
36+
// Extension methods for working with explicit nulls
37+
38+
/** Strips away the nullability from a value.
39+
* e.g.
40+
* val s1: String|Null = "hello"
41+
* val s: String = s1.nn
42+
*
43+
* Note that `.nn` performs a checked cast, so if invoked on a null value it'll throw an NPE.
44+
*/
45+
extension [T](x: T | Null) inline def nn: x.type & T =
46+
scala.runtime.Scala3RunTime.nn(x)
47+
end Predef
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package scala.runtime.stdLibPatches
2+
3+
/** Scala 3 additions and replacements to the `scala.language` object.
4+
*/
5+
object language:
6+
7+
/** The experimental object contains features that have been recently added but have not
8+
* been thoroughly tested in production yet.
9+
*
10+
* Experimental features '''may undergo API changes''' in future releases, so production
11+
* code should not rely on them.
12+
*
13+
* Programmers are encouraged to try out experimental features and
14+
* [[http://issues.scala-lang.org report any bugs or API inconsistencies]]
15+
* they encounter so they can be improved in future releases.
16+
*
17+
* @group experimental
18+
*/
19+
object experimental:
20+
21+
/** Experimental support for richer dependent types */
22+
object dependent
23+
24+
/** Experimental support for named type arguments */
25+
object namedTypeArguments
26+
27+
/** Experimental support for generic number literals */
28+
object genericNumberLiterals
29+
end experimental
30+
31+
/** Where imported, auto-tupling is disabled */
32+
object noAutoTupling
33+
34+
/** Where imported, loose equality using eqAny is disabled */
35+
object strictEquality
36+
37+
/** Where imported, ad hoc extensions of non-open classes in other
38+
* compilation units are allowed.
39+
*
40+
* '''Why control the feature?''' Ad-hoc extensions should usually be avoided
41+
* since they typically cannot rely on an "internal" contract between a class
42+
* and its extensions. Only open classes need to specify such a contract.
43+
* Ad-hoc extensions might break for future versions of the extended class,
44+
* since the extended class is free to change its implementation without
45+
* being constrained by an internal contract.
46+
*
47+
* '''Why allow it?''' An ad-hoc extension can sometimes be necessary,
48+
* for instance when mocking a class in a testing framework, or to work
49+
* around a bug or missing feature in the original class. Nevertheless,
50+
* such extensions should be limited in scope and clearly documented.
51+
* That's why the language import is required for them.
52+
*/
53+
object adhocExtensions
54+
55+
/** Source version */
56+
object `3.0-migration`
57+
object `3.0`
58+
object `3.1-migration`
59+
object `3.1`
60+
end language

0 commit comments

Comments
 (0)