From 4bb944bc542423875ba1790315f23d5f781a17fa Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 21 Nov 2020 10:47:17 +0100 Subject: [PATCH 01/13] Drop Scala2compat language feature It's been replaced a while ago by `-source 3.0-migration` --- compiler/src/dotty/tools/dotc/Driver.scala | 2 -- compiler/src/dotty/tools/dotc/config/Feature.scala | 3 +-- compiler/src/dotty/tools/dotc/core/StdNames.scala | 1 - library/src/scalaShadowing/language.scala | 3 --- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/Driver.scala b/compiler/src/dotty/tools/dotc/Driver.scala index 0dc4dcc2c90e..f24da34cc6ec 100644 --- a/compiler/src/dotty/tools/dotc/Driver.scala +++ b/compiler/src/dotty/tools/dotc/Driver.scala @@ -75,8 +75,6 @@ class Driver { inContext(ictx) { if !ctx.settings.YdropComments.value || ctx.mode.is(Mode.ReadComments) then ictx.setProperty(ContextDoc, new ContextDocstrings) - if Feature.enabledBySetting(nme.Scala2Compat) then - report.warning("-language:Scala2Compat will go away; use -source 3.0-migration instead") val fileNames = CompilerCommand.checkUsage(summary, sourcesRequired) fromTastySetup(fileNames, ctx) } diff --git a/compiler/src/dotty/tools/dotc/config/Feature.scala b/compiler/src/dotty/tools/dotc/config/Feature.scala index 169503cd464c..1984066f4f23 100644 --- a/compiler/src/dotty/tools/dotc/config/Feature.scala +++ b/compiler/src/dotty/tools/dotc/config/Feature.scala @@ -82,8 +82,7 @@ object Feature: case Some(v) => v case none => sourceVersionSetting - def migrateTo3(using Context): Boolean = - sourceVersion == `3.0-migration` || enabledBySetting(nme.Scala2Compat) + def migrateTo3(using Context): Boolean = sourceVersion == `3.0-migration` /** If current source migrates to `version`, issue given warning message * and return `true`, otherwise return `false`. diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 0bb2b9bc898b..c23d041346aa 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -386,7 +386,6 @@ object StdNames { val Ref: N = "Ref" val RootPackage: N = "RootPackage" val RootClass: N = "RootClass" - val Scala2Compat: N = "Scala2Compat" val Select: N = "Select" val Shape: N = "Shape" val StringContext: N = "StringContext" diff --git a/library/src/scalaShadowing/language.scala b/library/src/scalaShadowing/language.scala index eba8039f81c5..3e3886854bfa 100644 --- a/library/src/scalaShadowing/language.scala +++ b/library/src/scalaShadowing/language.scala @@ -225,9 +225,6 @@ object language { object genericNumberLiterals } - /** Where imported, a backwards compatibility mode for Scala2 is enabled */ - object Scala2Compat - /** Where imported, auto-tupling is disabled */ object noAutoTupling From 61cc83054dbd7b9efc12877ff78192c7d7445ab8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 10:32:32 +0100 Subject: [PATCH 02/13] Make bootstrapped DottyPredef an empty object Once we have a new bootstrap compiler we can drop it entirely. Instead of using DottyPredef, patch the Predef class when unpickling it. The patch adds all methods from a patch class scala.runtime.stdLibPatches.Predef to scala.Predef. --- .../dotty/tools/dotc/core/Definitions.scala | 17 +++++- .../src/dotty/tools/dotc/core/Symbols.scala | 31 ++++++---- .../core/unpickleScala2/Scala2Unpickler.scala | 25 ++++++++ .../tools/dotc/transform/TreeChecker.scala | 15 ++++- .../src-bootstrapped/dotty/DottyPredef.scala | 3 + .../dotty/DottyPredef.scala | 0 .../scala/runtime/stdLibPatches/Predef.scala | 47 +++++++++++++++ .../runtime/stdLibPatches/language.scala | 60 +++++++++++++++++++ tests/neg-macros/i9014.check | 8 +-- tests/neg/i9014.check | 8 +-- tests/neg/i9958.check | 2 +- tests/run/cochis-example.scala | 2 +- 12 files changed, 189 insertions(+), 29 deletions(-) create mode 100644 library/src-bootstrapped/dotty/DottyPredef.scala rename library/{src => src-non-bootstrapped}/dotty/DottyPredef.scala (100%) create mode 100644 library/src/scala/runtime/stdLibPatches/Predef.scala create mode 100644 library/src/scala/runtime/stdLibPatches/language.scala diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 5a7a27be15df..7ee9938fb409 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -9,7 +9,7 @@ import unpickleScala2.Scala2Unpickler.ensureConstructor import scala.collection.mutable import collection.mutable import Denotations.SingleDenotation -import util.SimpleIdentityMap +import util.{SimpleIdentityMap, SourceFile, NoSource} import typer.ImportInfo.RootRef import scala.annotation.tailrec @@ -186,6 +186,13 @@ class Definitions { cls } + /** If `sym` is a patched library class, the source file of its patch class, + * otherwise `NoSource` + */ + def patchSource(sym: Symbol): SourceFile = + if sym == ScalaPredefModuleClass then ScalaPredefModuleClassPatch.source + else NoSource + @tu lazy val RootClass: ClassSymbol = newPackageSymbol( NoSymbol, nme.ROOT, (root, rootcls) => ctx.base.rootLoader(root)).moduleClass.asClass @tu lazy val RootPackage: TermSymbol = newSymbol( @@ -481,13 +488,16 @@ class Definitions { newPermanentSymbol(ScalaPackageClass, tpnme.IMPLICITkw, EmptyFlags, TypeBounds.empty).entered def ImplicitScrutineeTypeRef: TypeRef = ImplicitScrutineeTypeSym.typeRef - @tu lazy val ScalaPredefModule: Symbol = requiredModule("scala.Predef") @tu lazy val Predef_conforms : Symbol = ScalaPredefModule.requiredMethod(nme.conforms_) @tu lazy val Predef_classOf : Symbol = ScalaPredefModule.requiredMethod(nme.classOf) @tu lazy val Predef_identity : Symbol = ScalaPredefModule.requiredMethod(nme.identity) @tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???) + @tu lazy val ScalaPredefModuleClass: ClassSymbol = ScalaPredefModule.moduleClass.asClass + @tu lazy val ScalaPredefModuleClassPatch: Symbol = + getModuleIfDefined("scala.runtime.stdLibPatches.Predef").moduleClass + @tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<") @tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl) @@ -510,7 +520,7 @@ class Definitions { // will return "null" when called recursively, see #1856. def DottyPredefModule: Symbol = { if (myDottyPredefModule == null) { - myDottyPredefModule = requiredModule("dotty.DottyPredef") + myDottyPredefModule = getModuleIfDefined("dotty.DottyPredef") assert(myDottyPredefModule != null) } myDottyPredefModule @@ -782,6 +792,7 @@ class Definitions { @tu lazy val Mirror_SingletonProxyClass: ClassSymbol = requiredClass("scala.deriving.Mirror.SingletonProxy") @tu lazy val LanguageModule: Symbol = requiredModule("scala.language") + @tu lazy val LanguageModuleClass: Symbol = LanguageModule.moduleClass.asClass @tu lazy val LanguageExperimentalModule: Symbol = requiredModule("scala.language.experimental") @tu lazy val NonLocalReturnControlClass: ClassSymbol = requiredClass("scala.runtime.NonLocalReturnControl") @tu lazy val SelectableClass: ClassSymbol = requiredClass("scala.Selectable") diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 601549d7ebce..e5fa24b82fa8 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -428,23 +428,21 @@ object Symbols { private var mySource: SourceFile = NoSource final def sourceOfClass(using Context): SourceFile = { - if (!mySource.exists && !denot.is(Package)) + if !mySource.exists && !denot.is(Package) then // this allows sources to be added in annotations after `sourceOfClass` is first called - mySource = { - val file = associatedFile - if (file != null && file.extension != "class") ctx.getSource(file) - else { - def sourceFromTopLevel(using Context) = - denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match { - case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match { + val file = associatedFile + if file != null && file.extension != "class" then + mySource = ctx.getSource(file) + else + mySource = defn.patchSource(this) + if !mySource.exists then + mySource = atPhaseNoLater(flattenPhase) { + denot.topLevelClass.unforcedAnnotation(defn.SourceFileAnnot) match + case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match case Some(Constant(path: String)) => ctx.getSource(path) case none => NoSource - } case none => NoSource - } - atPhaseNoLater(flattenPhase)(sourceFromTopLevel) - } - } + } mySource } @@ -880,6 +878,13 @@ object Symbols { staticRef(name).requiredSymbol("object", name)(_.is(Module)).asTerm } + /** Get module symbol if the module is either defined in current compilation run + * or present on classpath. Returns NoSymbol otherwise. + */ + def getModuleIfDefined(path: PreName)(using Context): Symbol = + staticRef(path.toTermName, generateStubs = false) + .disambiguate(_.is(Module)).symbol + def requiredModuleRef(path: PreName)(using Context): TermRef = requiredModule(path).termRef def requiredMethod(path: PreName)(using Context): TermSymbol = { diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index e138a5fc89c0..54a9157b8401 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -111,7 +111,32 @@ object Scala2Unpickler { denot.info = tempInfo.finalized(normalizedParents) denot.ensureTypeParamsInCorrectOrder() + if denot.name == tpnme.Predef.moduleClassName && denot.symbol == defn.ScalaPredefModuleClass then + denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted + patchStdLibClass(denot, defn.ScalaPredefModuleClassPatch) } + + /** A finalizer that patches standard library classes. + * It copies all non-private, non-synthetic definitions from `patchCls` + * to `denot` while changing their owners to `denot`. Before that it deletes + * any definitions of `denot` that have the same name as one of the copied + * definitions. + * + * To avpid running into cycles on bootstrap, patching happens only if `patchCls` + * is read from a classfile. + */ + private def patchStdLibClass(denot: ClassDenotation, patchCls: Symbol)(using Context): Unit = + val scope = denot.info.decls.openForMutations + if patchCls.exists then + val patches = patchCls.info.decls.filter(patch => + !patch.isConstructor && !patch.isOneOf(PrivateOrSynthetic)) + for patch <- patches do + val e = scope.lookupEntry(patch.name) + if e != null then scope.unlink(e) + for patch <- patches do + patch.ensureCompleted() + patch.denot = patch.denot.copySymDenotation(owner = denot.symbol) + scope.enter(patch) } /** Unpickle symbol table information descending from a class and/or module root diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index ec677c7eb762..8aad17494a79 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -417,6 +417,13 @@ class TreeChecker extends Phase with SymTransformer { assert(tree.qual.tpe.isInstanceOf[ThisType], i"expect prefix of Super to be This, actual = ${tree.qual}") super.typedSuper(tree, pt) + /** Definition of `sym` should be excluded from checks. + * We need to do that for stdlib patch classes, since their symbols have been + * appropriated by other stdlib classes. + */ + private def exclude(sym: Symbol)(using Context): Boolean = + sym == defn.ScalaPredefModuleClassPatch + private def checkOwner(tree: untpd.Tree)(using Context): Unit = { def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean = symOwner == ctxOwner || @@ -445,12 +452,14 @@ class TreeChecker extends Phase with SymTransformer { val symbolsNotDefined = decls -- defined - constr.symbol - assert(symbolsNotDefined.isEmpty, + if exclude(cls) then + promote(cdef) + else + assert(symbolsNotDefined.isEmpty, i" $cls tree does not define members: ${symbolsNotDefined.toList}%, %\n" + i"expected: ${decls.toList}%, %\n" + i"defined: ${defined}%, %") - - super.typedClassDef(cdef, cls) + super.typedClassDef(cdef, cls) } override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = diff --git a/library/src-bootstrapped/dotty/DottyPredef.scala b/library/src-bootstrapped/dotty/DottyPredef.scala new file mode 100644 index 000000000000..2dfcb0381e36 --- /dev/null +++ b/library/src-bootstrapped/dotty/DottyPredef.scala @@ -0,0 +1,3 @@ +package dotty + +object DottyPredef \ No newline at end of file diff --git a/library/src/dotty/DottyPredef.scala b/library/src-non-bootstrapped/dotty/DottyPredef.scala similarity index 100% rename from library/src/dotty/DottyPredef.scala rename to library/src-non-bootstrapped/dotty/DottyPredef.scala diff --git a/library/src/scala/runtime/stdLibPatches/Predef.scala b/library/src/scala/runtime/stdLibPatches/Predef.scala new file mode 100644 index 000000000000..4c25c1febadf --- /dev/null +++ b/library/src/scala/runtime/stdLibPatches/Predef.scala @@ -0,0 +1,47 @@ +package scala.runtime.stdLibPatches + +object Predef: + import compiletime.summonFrom + + inline def assert(inline assertion: Boolean, inline message: => Any): Unit = + if !assertion then scala.runtime.Scala3RunTime.assertFailed(message) + + inline def assert(inline assertion: Boolean): Unit = + if !assertion then scala.runtime.Scala3RunTime.assertFailed() + + /** + * Retrieve the single value of a type with a unique inhabitant. + * + * @example {{{ + * object Foo + * val foo = valueOf[Foo.type] + * // foo is Foo.type = Foo + * + * val bar = valueOf[23] + * // bar is 23.type = 23 + * }}} + * @group utilities + */ + inline def valueOf[T]: T = summonFrom { + case ev: ValueOf[T] => ev.value + } + + /** Summon a given value of type `T`. Usually, the argument is not passed explicitly. + * + * @tparam T the type of the value to be summoned + * @return the given value typed as the provided type parameter + */ + inline def summon[T](using x: T): x.type = x + + // Extension methods for working with explicit nulls + + /** Strips away the nullability from a value. + * e.g. + * val s1: String|Null = "hello" + * val s: String = s1.nn + * + * Note that `.nn` performs a checked cast, so if invoked on a null value it'll throw an NPE. + */ + extension [T](x: T | Null) inline def nn: x.type & T = + scala.runtime.Scala3RunTime.nn(x) +end Predef diff --git a/library/src/scala/runtime/stdLibPatches/language.scala b/library/src/scala/runtime/stdLibPatches/language.scala new file mode 100644 index 000000000000..d9f9e224cbd9 --- /dev/null +++ b/library/src/scala/runtime/stdLibPatches/language.scala @@ -0,0 +1,60 @@ +package scala.runtime.stdLibPatches + +/** Scala 3 additions to the `scala.language` object. + */ +object language: + + /** The experimental object contains features that have been recently added but have not + * been thoroughly tested in production yet. + * + * Experimental features '''may undergo API changes''' in future releases, so production + * code should not rely on them. + * + * Programmers are encouraged to try out experimental features and + * [[http://issues.scala-lang.org report any bugs or API inconsistencies]] + * they encounter so they can be improved in future releases. + * + * @group experimental + */ + object experimental: + + /** Experimental support for richer dependent types */ + object dependent + + /** Experimental support for named type arguments */ + object namedTypeArguments + + /** Experimental support for generic number literals */ + object genericNumberLiterals + end experimental + + /** Where imported, auto-tupling is disabled */ + object noAutoTupling + + /** Where imported, loose equality using eqAny is disabled */ + object strictEquality + + /** Where imported, ad hoc extensions of non-open classes in other + * compilation units are allowed. + * + * '''Why control the feature?''' Ad-hoc extensions should usually be avoided + * since they typically cannot rely on an "internal" contract between a class + * and its extensions. Only open classes need to specify such a contract. + * Ad-hoc extensions might break for future versions of the extended class, + * since the extended class is free to change its implementation without + * being constrained by an internal contract. + * + * '''Why allow it?''' An ad-hoc extension can sometimes be necessary, + * for instance when mocking a class in a testing framework, or to work + * around a bug or missing feature in the original class. Nevertheless, + * such extensions should be limited in scope and clearly documented. + * That's why the language import is required for them. + */ + object adhocExtensions + + /** Source version */ + object `3.0-migration` + object `3.0` + object `3.1-migration` + object `3.1` +end language diff --git a/tests/neg-macros/i9014.check b/tests/neg-macros/i9014.check index 563152f76ee0..76f328f9ef4a 100644 --- a/tests/neg-macros/i9014.check +++ b/tests/neg-macros/i9014.check @@ -2,9 +2,9 @@ -- Error: tests/neg-macros/i9014/Test_2.scala:1:23 --------------------------------------------------------------------- 1 |val tests = summon[Bar] // error | ^ - | no implicit argument of type Bar was found for parameter x of method summon in object DottyPredef. - | I found: + | no implicit argument of type Bar was found for parameter x of method summon in object Predef. + | I found: | - | given_Bar + | given_Bar | - | But method given_Bar does not match type Bar. + | But method given_Bar does not match type Bar. diff --git a/tests/neg/i9014.check b/tests/neg/i9014.check index 74d5d7f05cfe..b7a399f5cb75 100644 --- a/tests/neg/i9014.check +++ b/tests/neg/i9014.check @@ -1,9 +1,9 @@ -- Error: tests/neg/i9014.scala:4:25 ----------------------------------------------------------------------------------- 4 | val tests = summon[Bar] // error | ^ - | no implicit argument of type Bar was found for parameter x of method summon in object DottyPredef. - | I found: + | no implicit argument of type Bar was found for parameter x of method summon in object Predef. + | I found: | - | Bar.given_Bar + | Bar.given_Bar | - | But method given_Bar in object Bar does not match type Bar. + | But method given_Bar in object Bar does not match type Bar. diff --git a/tests/neg/i9958.check b/tests/neg/i9958.check index 23fd7a6195e3..92de7faae086 100644 --- a/tests/neg/i9958.check +++ b/tests/neg/i9958.check @@ -1,7 +1,7 @@ -- Error: tests/neg/i9958.scala:1:30 ----------------------------------------------------------------------------------- 1 |val x = summon[[X] =>> (X, X)] // error | ^ - | no implicit argument of type [X] =>> (X, X) was found for parameter x of method summon in object DottyPredef + | no implicit argument of type [X] =>> (X, X) was found for parameter x of method summon in object Predef -- [E007] Type Mismatch Error: tests/neg/i9958.scala:8:10 -------------------------------------------------------------- 8 |def b = f(a) // error | ^ diff --git a/tests/run/cochis-example.scala b/tests/run/cochis-example.scala index 657c90406508..4f32b00b6ddb 100644 --- a/tests/run/cochis-example.scala +++ b/tests/run/cochis-example.scala @@ -1,5 +1,5 @@ -import Predef.{$conforms => _} +import Predef.{assert, $conforms => _} trait A { given id[X] as (X => X) = x => x def trans[X](x: X)(using f: X => X) = f(x) // (2) From 4f705c07f0f566cd96e54d895254224b1967f02d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 12:15:39 +0100 Subject: [PATCH 03/13] Drop scalaShadowing after bootstrap Instead, patch the `scala.language` object in the same way we patch `scala.Predef`. We leave a dummy file in scalaShadowing, since the build requires the package to exist. When we have a new bootstrap compiler, we should drop `scalaShadowing` entirely. --- .../dotty/tools/dotc/core/Definitions.scala | 13 ++++++--- .../core/unpickleScala2/Scala2Unpickler.scala | 4 ++- .../tools/dotc/transform/TreeChecker.scala | 27 +++++++++---------- .../scalaShadowing/D_u_m_m_y.scala | 3 +++ .../scalaShadowing/language.scala | 0 .../runtime/stdLibPatches/language.scala | 19 ++++++++++++- 6 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 library/src-bootstrapped/scalaShadowing/D_u_m_m_y.scala rename library/{src => src-non-bootstrapped}/scalaShadowing/language.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 7ee9938fb409..93ff55c6ac81 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -191,6 +191,7 @@ class Definitions { */ def patchSource(sym: Symbol): SourceFile = if sym == ScalaPredefModuleClass then ScalaPredefModuleClassPatch.source + else if sym == LanguageModuleClass then LanguageModuleClassPatch.source else NoSource @tu lazy val RootClass: ClassSymbol = newPackageSymbol( @@ -259,9 +260,18 @@ class Definitions { * or classes with the same name. But their binary artifacts are * in `scalaShadowing` so they don't clash with the same-named `scala` * members at runtime. + * It is used only for non-bootstrapped code */ @tu lazy val ScalaShadowingPackage: TermSymbol = requiredPackage(nme.scalaShadowing) + /** The `scala.runtime.stdLibPacthes` package is contains objects + * that contain defnitions that get added as members to standard library + * objects with the same name. + */ + @tu lazy val StdLibPatchesPackage: TermSymbol = requiredPackage("scala.runtime.stdLibPatches") + @tu lazy val ScalaPredefModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.Predef").moduleClass + @tu lazy val LanguageModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.language").moduleClass + /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter) * because after erasure the Any and AnyVal references get remapped to the Object methods * which would result in a double binding assertion failure. @@ -493,10 +503,7 @@ class Definitions { @tu lazy val Predef_classOf : Symbol = ScalaPredefModule.requiredMethod(nme.classOf) @tu lazy val Predef_identity : Symbol = ScalaPredefModule.requiredMethod(nme.identity) @tu lazy val Predef_undefined: Symbol = ScalaPredefModule.requiredMethod(nme.???) - @tu lazy val ScalaPredefModuleClass: ClassSymbol = ScalaPredefModule.moduleClass.asClass - @tu lazy val ScalaPredefModuleClassPatch: Symbol = - getModuleIfDefined("scala.runtime.stdLibPatches.Predef").moduleClass @tu lazy val SubTypeClass: ClassSymbol = requiredClass("scala.<:<") @tu lazy val SubType_refl: Symbol = SubTypeClass.companionModule.requiredMethod(nme.refl) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 54a9157b8401..ec13f56635fb 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -112,8 +112,9 @@ object Scala2Unpickler { denot.info = tempInfo.finalized(normalizedParents) denot.ensureTypeParamsInCorrectOrder() if denot.name == tpnme.Predef.moduleClassName && denot.symbol == defn.ScalaPredefModuleClass then - denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted patchStdLibClass(denot, defn.ScalaPredefModuleClassPatch) + else if denot.name == tpnme.language.moduleClassName && denot.symbol == defn.LanguageModuleClass then + patchStdLibClass(denot, defn.LanguageModuleClassPatch) } /** A finalizer that patches standard library classes. @@ -126,6 +127,7 @@ object Scala2Unpickler { * is read from a classfile. */ private def patchStdLibClass(denot: ClassDenotation, patchCls: Symbol)(using Context): Unit = + denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted val scope = denot.info.decls.openForMutations if patchCls.exists then val patches = patchCls.info.decls.filter(patch => diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 8aad17494a79..01a1c8de4913 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -417,13 +417,6 @@ class TreeChecker extends Phase with SymTransformer { assert(tree.qual.tpe.isInstanceOf[ThisType], i"expect prefix of Super to be This, actual = ${tree.qual}") super.typedSuper(tree, pt) - /** Definition of `sym` should be excluded from checks. - * We need to do that for stdlib patch classes, since their symbols have been - * appropriated by other stdlib classes. - */ - private def exclude(sym: Symbol)(using Context): Boolean = - sym == defn.ScalaPredefModuleClassPatch - private def checkOwner(tree: untpd.Tree)(using Context): Unit = { def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean = symOwner == ctxOwner || @@ -452,14 +445,12 @@ class TreeChecker extends Phase with SymTransformer { val symbolsNotDefined = decls -- defined - constr.symbol - if exclude(cls) then - promote(cdef) - else - assert(symbolsNotDefined.isEmpty, - i" $cls tree does not define members: ${symbolsNotDefined.toList}%, %\n" + - i"expected: ${decls.toList}%, %\n" + - i"defined: ${defined}%, %") - super.typedClassDef(cdef, cls) + assert(symbolsNotDefined.isEmpty, + i" $cls tree does not define members: ${symbolsNotDefined.toList}%, %\n" + + i"expected: ${decls.toList}%, %\n" + + i"defined: ${defined}%, %") + + super.typedClassDef(cdef, cls) } override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = @@ -549,6 +540,12 @@ class TreeChecker extends Phase with SymTransformer { super.typedWhileDo(tree) } + override def typedPackageDef(tree: untpd.PackageDef)(using Context): Tree = + if tree.symbol == defn.StdLibPatchesPackage then + promote(tree) // don't check stdlib patches, since their symbols were highjacked by stdlib classes + else + super.typedPackageDef(tree) + override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(using Context): Tree = tree diff --git a/library/src-bootstrapped/scalaShadowing/D_u_m_m_y.scala b/library/src-bootstrapped/scalaShadowing/D_u_m_m_y.scala new file mode 100644 index 000000000000..8e39ae8b28bd --- /dev/null +++ b/library/src-bootstrapped/scalaShadowing/D_u_m_m_y.scala @@ -0,0 +1,3 @@ +package scalaShadowing + +class D_u_m_m_y diff --git a/library/src/scalaShadowing/language.scala b/library/src-non-bootstrapped/scalaShadowing/language.scala similarity index 100% rename from library/src/scalaShadowing/language.scala rename to library/src-non-bootstrapped/scalaShadowing/language.scala diff --git a/library/src/scala/runtime/stdLibPatches/language.scala b/library/src/scala/runtime/stdLibPatches/language.scala index d9f9e224cbd9..d96cc2d5ab17 100644 --- a/library/src/scala/runtime/stdLibPatches/language.scala +++ b/library/src/scala/runtime/stdLibPatches/language.scala @@ -1,6 +1,6 @@ package scala.runtime.stdLibPatches -/** Scala 3 additions to the `scala.language` object. +/** Scala 3 additions and replacements to the `scala.language` object. */ object language: @@ -18,6 +18,23 @@ object language: */ object experimental: + /** Where enabled, Scala 2 macro definitions are allowed. Scala 2 macro implementations and + * macro applications are unaffected; they can be used anywhere. A Scala 2 macro definition + * must be accompanied by a Scala 3 macro definition with the same signature. + * + * '''Why introduce the feature?''' Scala 2 macros promise to make the language more regular, + * replacing ad-hoc language constructs with a general powerful abstraction + * capability that can express them. Macros are also a more disciplined and + * powerful replacement for compiler plugins. + * + * '''Why control it?''' For their very power, macros can lead to code that is hard + * to debug and understand. + * + * This is not required by Scala 3 macros as `inline` controls the basic generative macros. + * More add-hoc macros must contain the import of reflection in thier code, making this import redundant. + */ + implicit lazy val macros: languageFeature.experimental.macros = languageFeature.experimental.macros + /** Experimental support for richer dependent types */ object dependent From 65af1c6c6095aff580b198bb59dbe8749745ce4f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 12:39:06 +0100 Subject: [PATCH 04/13] Concentrate all stdlib patch code in Definitions --- .../dotty/tools/dotc/core/Definitions.scala | 64 ++++++++++++++----- .../core/unpickleScala2/Scala2Unpickler.scala | 28 +------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 93ff55c6ac81..68815faf2c20 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -186,14 +186,6 @@ class Definitions { cls } - /** If `sym` is a patched library class, the source file of its patch class, - * otherwise `NoSource` - */ - def patchSource(sym: Symbol): SourceFile = - if sym == ScalaPredefModuleClass then ScalaPredefModuleClassPatch.source - else if sym == LanguageModuleClass then LanguageModuleClassPatch.source - else NoSource - @tu lazy val RootClass: ClassSymbol = newPackageSymbol( NoSymbol, nme.ROOT, (root, rootcls) => ctx.base.rootLoader(root)).moduleClass.asClass @tu lazy val RootPackage: TermSymbol = newSymbol( @@ -264,13 +256,6 @@ class Definitions { */ @tu lazy val ScalaShadowingPackage: TermSymbol = requiredPackage(nme.scalaShadowing) - /** The `scala.runtime.stdLibPacthes` package is contains objects - * that contain defnitions that get added as members to standard library - * objects with the same name. - */ - @tu lazy val StdLibPatchesPackage: TermSymbol = requiredPackage("scala.runtime.stdLibPatches") - @tu lazy val ScalaPredefModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.Predef").moduleClass - @tu lazy val LanguageModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.language").moduleClass /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter) * because after erasure the Any and AnyVal references get remapped to the Object methods @@ -1119,6 +1104,55 @@ class Definitions { || sym.owner == CompiletimeOpsPackageObjectString.moduleClass && compiletimePackageStringTypes.contains(sym.name) ) + // ----- Scala-2 library patches -------------------------------------- + + /** The `scala.runtime.stdLibPacthes` package contains objects + * that contain defnitions that get added as members to standard library + * objects with the same name. + */ + @tu lazy val StdLibPatchesPackage: TermSymbol = requiredPackage("scala.runtime.stdLibPatches") + @tu private lazy val ScalaPredefModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.Predef").moduleClass + @tu private lazy val LanguageModuleClassPatch: Symbol = getModuleIfDefined("scala.runtime.stdLibPatches.language").moduleClass + + /** If `sym` is a patched library class, the source file of its patch class, + * otherwise `NoSource` + */ + def patchSource(sym: Symbol)(using Context): SourceFile = + if sym == ScalaPredefModuleClass then ScalaPredefModuleClassPatch.source + else if sym == LanguageModuleClass then LanguageModuleClassPatch.source + else NoSource + + /** A finalizer that patches standard library classes. + * It copies all non-private, non-synthetic definitions from `patchCls` + * to `denot` while changing their owners to `denot`. Before that it deletes + * any definitions of `denot` that have the same name as one of the copied + * definitions. + * + * To avpid running into cycles on bootstrap, patching happens only if `patchCls` + * is read from a classfile. + */ + def patchStdLibClass(denot: ClassDenotation)(using Context): Unit = + + def patchWith(patchCls: Symbol) = + denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted + val scope = denot.info.decls.openForMutations + if patchCls.exists then + val patches = patchCls.info.decls.filter(patch => + !patch.isConstructor && !patch.isOneOf(PrivateOrSynthetic)) + for patch <- patches do + val e = scope.lookupEntry(patch.name) + if e != null then scope.unlink(e) + for patch <- patches do + patch.ensureCompleted() + patch.denot = patch.denot.copySymDenotation(owner = denot.symbol) + scope.enter(patch) + + 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) + end patchStdLibClass + // ----- Symbol sets --------------------------------------------------- @tu lazy val AbstractFunctionType: Array[TypeRef] = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index ec13f56635fb..33b755ab8a75 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -111,34 +111,8 @@ object Scala2Unpickler { denot.info = tempInfo.finalized(normalizedParents) denot.ensureTypeParamsInCorrectOrder() - if denot.name == tpnme.Predef.moduleClassName && denot.symbol == defn.ScalaPredefModuleClass then - patchStdLibClass(denot, defn.ScalaPredefModuleClassPatch) - else if denot.name == tpnme.language.moduleClassName && denot.symbol == defn.LanguageModuleClass then - patchStdLibClass(denot, defn.LanguageModuleClassPatch) + defn.patchStdLibClass(denot) } - - /** A finalizer that patches standard library classes. - * It copies all non-private, non-synthetic definitions from `patchCls` - * to `denot` while changing their owners to `denot`. Before that it deletes - * any definitions of `denot` that have the same name as one of the copied - * definitions. - * - * To avpid running into cycles on bootstrap, patching happens only if `patchCls` - * is read from a classfile. - */ - private def patchStdLibClass(denot: ClassDenotation, patchCls: Symbol)(using Context): Unit = - denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted - val scope = denot.info.decls.openForMutations - if patchCls.exists then - val patches = patchCls.info.decls.filter(patch => - !patch.isConstructor && !patch.isOneOf(PrivateOrSynthetic)) - for patch <- patches do - val e = scope.lookupEntry(patch.name) - if e != null then scope.unlink(e) - for patch <- patches do - patch.ensureCompleted() - patch.denot = patch.denot.copySymDenotation(owner = denot.symbol) - scope.enter(patch) } /** Unpickle symbol table information descending from a class and/or module root From acda51cf44130ed3f85a562c25c7cd9ed4a4ac47 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 12:49:45 +0100 Subject: [PATCH 05/13] Also patch stdlib classes when compiling from source --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 01671224b73d..ac6ad8ac4694 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1199,6 +1199,7 @@ class Namer { typer: Typer => cls.setNoInitsFlags(parentsKind(parents), untpd.bodyKind(rest)) if (cls.isNoInitsClass) cls.primaryConstructor.setFlag(StableRealizable) processExports(using localCtx) + defn.patchStdLibClass(denot.asClass) } } From c07169a5008dcf505aad5ce6a502f7c574fd1a9c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 13:34:21 +0100 Subject: [PATCH 06/13] Update semanticdb check files --- tests/semanticdb/expect/Advanced.expect.scala | 4 +- .../expect/Annotations.expect.scala | 2 +- .../semanticdb/expect/Anonymous.expect.scala | 2 +- tests/semanticdb/expect/Classes.expect.scala | 2 +- .../expect/ImplicitConversion.expect.scala | 2 +- .../expect/InstrumentTyper.expect.scala | 4 +- tests/semanticdb/expect/Methods.expect.scala | 2 +- .../semanticdb/expect/Synthetic.expect.scala | 2 +- .../expect/semanticdb-Flags.expect.scala | 2 +- .../expect/semanticdb-Types.expect.scala | 4 +- tests/semanticdb/metac.expect | 58 +++++++++---------- 11 files changed, 42 insertions(+), 42 deletions(-) diff --git a/tests/semanticdb/expect/Advanced.expect.scala b/tests/semanticdb/expect/Advanced.expect.scala index a3b8cfd1bc1a..d52b8cecf668 100644 --- a/tests/semanticdb/expect/Advanced.expect.scala +++ b/tests/semanticdb/expect/Advanced.expect.scala @@ -1,7 +1,7 @@ package advanced -import scala.language/*->scalaShadowing::language.*/.higherKinds/*->scalaShadowing::language.higherKinds.*/ -import scala.language/*->scalaShadowing::language.*/.reflectiveCalls/*->scalaShadowing::language.reflectiveCalls.*/ +import scala.language/*->scala::language.*/.higherKinds/*->scala::language.higherKinds.*/ +import scala.language/*->scala::language.*/.reflectiveCalls/*->scala::language.reflectiveCalls.*/ import scala.reflect.Selectable/*->scala::reflect::Selectable.*/.reflectiveSelectable/*->scala::reflect::Selectable.reflectiveSelectable().*/ diff --git a/tests/semanticdb/expect/Annotations.expect.scala b/tests/semanticdb/expect/Annotations.expect.scala index f36f02686f8f..88fd55279508 100644 --- a/tests/semanticdb/expect/Annotations.expect.scala +++ b/tests/semanticdb/expect/Annotations.expect.scala @@ -2,7 +2,7 @@ package annot import com.javacp.annot._ import scala.annotation.meta._ -import scala.language/*->scalaShadowing::language.*/.experimental/*->scalaShadowing::language.experimental.*/.macros/*->scalaShadowing::language.experimental.macros.*/ +import scala.language/*->scala::language.*/.experimental/*->scala::language.experimental.*/.macros/*->scala::language.experimental.macros.*/ @ClassAnnotation/*->com::javacp::annot::ClassAnnotation#*/ class Annotations/*<-annot::Annotations#*/[@TypeParameterAnnotation/*->com::javacp::annot::TypeParameterAnnotation#*/ T/*<-annot::Annotations#[T]*/](@ParameterAnnotation/*->com::javacp::annot::ParameterAnnotation#*/ x/*<-annot::Annotations#x.*/: T/*->annot::Annotations#[T]*/) { self/*<-local0*/: AnyRef/*->scala::AnyRef#*/ => diff --git a/tests/semanticdb/expect/Anonymous.expect.scala b/tests/semanticdb/expect/Anonymous.expect.scala index ee2d433facb5..655bafc719a0 100644 --- a/tests/semanticdb/expect/Anonymous.expect.scala +++ b/tests/semanticdb/expect/Anonymous.expect.scala @@ -1,5 +1,5 @@ package example -import scala.language/*->scalaShadowing::language.*/.higherKinds/*->scalaShadowing::language.higherKinds.*/ +import scala.language/*->scala::language.*/.higherKinds/*->scala::language.higherKinds.*/ class Anonymous/*<-example::Anonymous#*/ { this: Anonymous/*->example::Anonymous#*/ => diff --git a/tests/semanticdb/expect/Classes.expect.scala b/tests/semanticdb/expect/Classes.expect.scala index 7df634e2808a..af092703c250 100644 --- a/tests/semanticdb/expect/Classes.expect.scala +++ b/tests/semanticdb/expect/Classes.expect.scala @@ -1,5 +1,5 @@ package classes -import scala.language/*->scalaShadowing::language.*/.experimental/*->scalaShadowing::language.experimental.*/.macros/*->scalaShadowing::language.experimental.macros.*/ +import scala.language/*->scala::language.*/.experimental/*->scala::language.experimental.*/.macros/*->scala::language.experimental.macros.*/ class C1/*<-classes::C1#*/(val x1/*<-classes::C1#x1.*/: Int/*->scala::Int#*/) extends AnyVal/*->scala::AnyVal#*//*->scala::AnyVal#``().*/ class C2/*<-classes::C2#*/(val x2/*<-classes::C2#x2.*/: Int/*->scala::Int#*/) extends AnyVal/*->scala::AnyVal#*//*->scala::AnyVal#``().*/ diff --git a/tests/semanticdb/expect/ImplicitConversion.expect.scala b/tests/semanticdb/expect/ImplicitConversion.expect.scala index 07b7a8eea820..d9e6612680bb 100644 --- a/tests/semanticdb/expect/ImplicitConversion.expect.scala +++ b/tests/semanticdb/expect/ImplicitConversion.expect.scala @@ -1,6 +1,6 @@ package example -import scala.language/*->scalaShadowing::language.*/.implicitConversions/*->scalaShadowing::language.implicitConversions.*/ +import scala.language/*->scala::language.*/.implicitConversions/*->scala::language.implicitConversions.*/ class ImplicitConversion/*<-example::ImplicitConversion#*/ { import ImplicitConversion/*->example::ImplicitConversion.*/._ diff --git a/tests/semanticdb/expect/InstrumentTyper.expect.scala b/tests/semanticdb/expect/InstrumentTyper.expect.scala index 5cd370ce3b42..d847130f9fcf 100644 --- a/tests/semanticdb/expect/InstrumentTyper.expect.scala +++ b/tests/semanticdb/expect/InstrumentTyper.expect.scala @@ -1,8 +1,8 @@ package example import scala.annotation.meta.param/*->scala::annotation::meta::param.*/ -import scala.language/*->scalaShadowing::language.*/.existentials/*->scalaShadowing::language.existentials.*/ -import scala.language/*->scalaShadowing::language.*/.higherKinds/*->scalaShadowing::language.higherKinds.*/ +import scala.language/*->scala::language.*/.existentials/*->scala::language.existentials.*/ +import scala.language/*->scala::language.*/.higherKinds/*->scala::language.higherKinds.*/ import types.Test/*->types::Test.*/._ class InstrumentTyper/*<-example::InstrumentTyper#*/ { self/*<-local0*/: AnyRef/*->scala::AnyRef#*/ => diff --git a/tests/semanticdb/expect/Methods.expect.scala b/tests/semanticdb/expect/Methods.expect.scala index 56198e4320f4..8190bf0308d1 100644 --- a/tests/semanticdb/expect/Methods.expect.scala +++ b/tests/semanticdb/expect/Methods.expect.scala @@ -1,7 +1,7 @@ package example import scala.math.Ordering/*->scala::math::Ordering.*//*->scala::math::Ordering#*/ -import scala.language/*->scalaShadowing::language.*/.existentials/*->scalaShadowing::language.existentials.*/ +import scala.language/*->scala::language.*/.existentials/*->scala::language.existentials.*/ class Methods/*<-example::Methods#*/[T/*<-example::Methods#[T]*/] { class List/*<-example::Methods#List#*/[T/*<-example::Methods#List#[T]*/] diff --git a/tests/semanticdb/expect/Synthetic.expect.scala b/tests/semanticdb/expect/Synthetic.expect.scala index 61f32ee72ce7..0f95d9d0b01f 100644 --- a/tests/semanticdb/expect/Synthetic.expect.scala +++ b/tests/semanticdb/expect/Synthetic.expect.scala @@ -1,6 +1,6 @@ package example -import scala.language/*->scalaShadowing::language.*/.implicitConversions/*->scalaShadowing::language.implicitConversions.*/ +import scala.language/*->scala::language.*/.implicitConversions/*->scala::language.implicitConversions.*/ class Synthetic/*<-example::Synthetic#*/ { List/*->scala::package.List.*//*->scala::collection::IterableFactory#apply().*/(1).map/*->scala::collection::immutable::List#map().*/(_ +/*->scala::Int#`+`(+4).*/ 2) diff --git a/tests/semanticdb/expect/semanticdb-Flags.expect.scala b/tests/semanticdb/expect/semanticdb-Flags.expect.scala index f36f0899c1ea..fe920433e231 100644 --- a/tests/semanticdb/expect/semanticdb-Flags.expect.scala +++ b/tests/semanticdb/expect/semanticdb-Flags.expect.scala @@ -1,6 +1,6 @@ package flags -import scala.language/*->scalaShadowing::language.*/.experimental/*->scalaShadowing::language.experimental.*/.macros/*->scalaShadowing::language.experimental.macros.*/ +import scala.language/*->scala::language.*/.experimental/*->scala::language.experimental.*/.macros/*->scala::language.experimental.macros.*/ package object p { p/*<-flags::p::package.*/rivate lazy val x/*<-flags::p::package.x.*/ = 1 diff --git a/tests/semanticdb/expect/semanticdb-Types.expect.scala b/tests/semanticdb/expect/semanticdb-Types.expect.scala index cffc325c8410..122579d42a9e 100644 --- a/tests/semanticdb/expect/semanticdb-Types.expect.scala +++ b/tests/semanticdb/expect/semanticdb-Types.expect.scala @@ -1,7 +1,7 @@ package types -import scala.language/*->scalaShadowing::language.*/.existentials/*->scalaShadowing::language.existentials.*/ -import scala.language/*->scalaShadowing::language.*/.higherKinds/*->scalaShadowing::language.higherKinds.*/ +import scala.language/*->scala::language.*/.existentials/*->scala::language.existentials.*/ +import scala.language/*->scala::language.*/.higherKinds/*->scala::language.higherKinds.*/ class ann/*<-types::ann#*/[T/*<-types::ann#[T]*/](x/*<-types::ann#x.*/: T/*->types::ann#[T]*/) extends scala.annotation.StaticAnnotation/*->scala::annotation::StaticAnnotation#*/ class ann1/*<-types::ann1#*/ extends scala.annotation.StaticAnnotation/*->scala::annotation::StaticAnnotation#*/ diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 1322835bb039..c06e74120f70 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -91,11 +91,11 @@ local10 => val local e3x Occurrences: [0:8..0:16): advanced <- advanced/ [2:7..2:12): scala -> scala/ -[2:13..2:21): language -> scalaShadowing/language. -[2:22..2:33): higherKinds -> scalaShadowing/language.higherKinds. +[2:13..2:21): language -> scala/language. +[2:22..2:33): higherKinds -> scala/language.higherKinds. [3:7..3:12): scala -> scala/ -[3:13..3:21): language -> scalaShadowing/language. -[3:22..3:37): reflectiveCalls -> scalaShadowing/language.reflectiveCalls. +[3:13..3:21): language -> scala/language. +[3:22..3:37): reflectiveCalls -> scala/language.reflectiveCalls. [5:7..5:12): scala -> scala/ [5:13..5:20): reflect -> scala/reflect/ [5:21..5:31): Selectable -> scala/reflect/Selectable. @@ -224,9 +224,9 @@ Occurrences: [3:13..3:23): annotation -> scala/annotation/ [3:24..3:28): meta -> scala/annotation/meta/ [4:7..4:12): scala -> scala/ -[4:13..4:21): language -> scalaShadowing/language. -[4:22..4:34): experimental -> scalaShadowing/language.experimental. -[4:35..4:41): macros -> scalaShadowing/language.experimental.macros. +[4:13..4:21): language -> scala/language. +[4:22..4:34): experimental -> scala/language.experimental. +[4:35..4:41): macros -> scala/language.experimental.macros. [6:1..6:16): ClassAnnotation -> com/javacp/annot/ClassAnnotation# [7:6..7:17): Annotations <- annot/Annotations# [7:17..7:17): <- annot/Annotations#``(). @@ -298,8 +298,8 @@ local1 => final class $anon Occurrences: [0:8..0:15): example <- example/ [1:7..1:12): scala -> scala/ -[1:13..1:21): language -> scalaShadowing/language. -[1:22..1:33): higherKinds -> scalaShadowing/language.higherKinds. +[1:13..1:21): language -> scala/language. +[1:22..1:33): higherKinds -> scala/language.higherKinds. [3:6..3:15): Anonymous <- example/Anonymous# [4:2..4:2): <- example/Anonymous#``(). [4:8..4:17): Anonymous -> example/Anonymous# @@ -454,9 +454,9 @@ local3 => val local local Occurrences: [0:8..0:15): classes <- classes/ [1:7..1:12): scala -> scala/ -[1:13..1:21): language -> scalaShadowing/language. -[1:22..1:34): experimental -> scalaShadowing/language.experimental. -[1:35..1:41): macros -> scalaShadowing/language.experimental.macros. +[1:13..1:21): language -> scala/language. +[1:22..1:34): experimental -> scala/language.experimental. +[1:35..1:41): macros -> scala/language.experimental.macros. [2:6..2:8): C1 <- classes/C1# [2:8..2:8): <- classes/C1#``(). [2:13..2:15): x1 <- classes/C1#x1. @@ -1373,8 +1373,8 @@ example/ImplicitConversion.newAny2stringadd. => final object newAny2stringadd Occurrences: [0:8..0:15): example <- example/ [2:7..2:12): scala -> scala/ -[2:13..2:21): language -> scalaShadowing/language. -[2:22..2:41): implicitConversions -> scalaShadowing/language.implicitConversions. +[2:13..2:21): language -> scala/language. +[2:22..2:41): implicitConversions -> scala/language.implicitConversions. [4:6..4:24): ImplicitConversion <- example/ImplicitConversion# [5:2..5:2): <- example/ImplicitConversion#``(). [5:9..5:27): ImplicitConversion -> example/ImplicitConversion. @@ -1481,11 +1481,11 @@ Occurrences: [2:24..2:28): meta -> scala/annotation/meta/ [2:29..2:34): param -> scala/annotation/meta/param. [3:7..3:12): scala -> scala/ -[3:13..3:21): language -> scalaShadowing/language. -[3:22..3:34): existentials -> scalaShadowing/language.existentials. +[3:13..3:21): language -> scala/language. +[3:22..3:34): existentials -> scala/language.existentials. [4:7..4:12): scala -> scala/ -[4:13..4:21): language -> scalaShadowing/language. -[4:22..4:33): higherKinds -> scalaShadowing/language.higherKinds. +[4:13..4:21): language -> scala/language. +[4:22..4:33): higherKinds -> scala/language.higherKinds. [5:7..5:12): types -> types/ [5:13..5:17): Test -> types/Test. [7:6..7:21): InstrumentTyper <- example/InstrumentTyper# @@ -1937,8 +1937,8 @@ Occurrences: [2:18..2:26): Ordering -> scala/math/Ordering. [2:18..2:26): Ordering -> scala/math/Ordering# [3:7..3:12): scala -> scala/ -[3:13..3:21): language -> scalaShadowing/language. -[3:22..3:34): existentials -> scalaShadowing/language.existentials. +[3:13..3:21): language -> scala/language. +[3:22..3:34): existentials -> scala/language.existentials. [5:6..5:13): Methods <- example/Methods# [5:13..5:13): <- example/Methods#``(). [5:14..5:15): T <- example/Methods#[T] @@ -2496,8 +2496,8 @@ local9 => param b Occurrences: [0:8..0:15): example <- example/ [2:7..2:12): scala -> scala/ -[2:13..2:21): language -> scalaShadowing/language. -[2:22..2:41): implicitConversions -> scalaShadowing/language.implicitConversions. +[2:13..2:21): language -> scala/language. +[2:22..2:41): implicitConversions -> scala/language.implicitConversions. [4:6..4:15): Synthetic <- example/Synthetic# [5:2..5:2): <- example/Synthetic#``(). [5:2..5:6): List -> scala/package.List. @@ -3362,9 +3362,9 @@ local1 => case val method t Occurrences: [0:8..0:13): flags <- flags/ [2:7..2:12): scala -> scala/ -[2:13..2:21): language -> scalaShadowing/language. -[2:22..2:34): experimental -> scalaShadowing/language.experimental. -[2:35..2:41): macros -> scalaShadowing/language.experimental.macros. +[2:13..2:21): language -> scala/language. +[2:22..2:34): experimental -> scala/language.experimental. +[2:35..2:41): macros -> scala/language.experimental.macros. [4:15..5:3): <- flags/p/package. [5:2..5:3): p -> flags/p/ [5:19..5:20): x <- flags/p/package.x. @@ -3601,11 +3601,11 @@ types/ann2#``(). => primary ctor Occurrences: [0:8..0:13): types <- types/ [2:7..2:12): scala -> scala/ -[2:13..2:21): language -> scalaShadowing/language. -[2:22..2:34): existentials -> scalaShadowing/language.existentials. +[2:13..2:21): language -> scala/language. +[2:22..2:34): existentials -> scala/language.existentials. [3:7..3:12): scala -> scala/ -[3:13..3:21): language -> scalaShadowing/language. -[3:22..3:33): higherKinds -> scalaShadowing/language.higherKinds. +[3:13..3:21): language -> scala/language. +[3:22..3:33): higherKinds -> scala/language.higherKinds. [5:6..5:9): ann <- types/ann# [5:9..5:9): <- types/ann#``(). [5:10..5:11): T <- types/ann#[T] From 3643f50d8d29c96ac1bd8bb01bb39faee23fca0c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 15:05:58 +0100 Subject: [PATCH 07/13] Don't overwrite language.experimental Patch its members recursively instead. --- .../dotty/tools/dotc/core/Definitions.scala | 20 +++++++++++++------ .../tools/dotc/core/tasty/TreePickler.scala | 4 +++- .../runtime/stdLibPatches/language.scala | 17 ---------------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 68815faf2c20..c6caa8efc551 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -256,7 +256,6 @@ class Definitions { */ @tu lazy val ScalaShadowingPackage: TermSymbol = requiredPackage(nme.scalaShadowing) - /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter) * because after erasure the Any and AnyVal references get remapped to the Object methods * which would result in a double binding assertion failure. @@ -1133,19 +1132,28 @@ class Definitions { */ def patchStdLibClass(denot: ClassDenotation)(using Context): Unit = - def patchWith(patchCls: Symbol) = - denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted + def recurse(patch: Symbol) = + patch.name.toString.startsWith("experimental") + + def patch2(denot: ClassDenotation, patchCls: Symbol): Unit = val scope = denot.info.decls.openForMutations if patchCls.exists then val patches = patchCls.info.decls.filter(patch => !patch.isConstructor && !patch.isOneOf(PrivateOrSynthetic)) - for patch <- patches do + for patch <- patches if !recurse(patch) do val e = scope.lookupEntry(patch.name) if e != null then scope.unlink(e) for patch <- patches do patch.ensureCompleted() - patch.denot = patch.denot.copySymDenotation(owner = denot.symbol) - scope.enter(patch) + if !recurse(patch) then + patch.denot = patch.denot.copySymDenotation(owner = denot.symbol) + scope.enter(patch) + else if patch.isClass then + patch2(scope.lookup(patch.name).asClass, patch) + + def patchWith(patchCls: Symbol) = + denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted + patch2(denot, patchCls) if denot.name == tpnme.Predef.moduleClassName && denot.symbol == ScalaPredefModuleClass then patchWith(ScalaPredefModuleClassPatch) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 1dbb3068720e..c2d39f5d6ee9 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -764,7 +764,9 @@ class TreePickler(pickler: TastyPickler) { def pickle(trees: List[Tree])(using Context): Unit = { trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree)) - def missing = forwardSymRefs.keysIterator.map(sym => sym.showLocated + "(line " + sym.srcPos.line + ")").toList + def missing = forwardSymRefs.keysIterator + .map(sym => i"${sym.showLocated} (line ${sym.srcPos.line}) #${sym.id}") + .toList assert(forwardSymRefs.isEmpty, i"unresolved symbols: $missing%, % when pickling ${ctx.source}") } diff --git a/library/src/scala/runtime/stdLibPatches/language.scala b/library/src/scala/runtime/stdLibPatches/language.scala index d96cc2d5ab17..30ce6f550c57 100644 --- a/library/src/scala/runtime/stdLibPatches/language.scala +++ b/library/src/scala/runtime/stdLibPatches/language.scala @@ -18,23 +18,6 @@ object language: */ object experimental: - /** Where enabled, Scala 2 macro definitions are allowed. Scala 2 macro implementations and - * macro applications are unaffected; they can be used anywhere. A Scala 2 macro definition - * must be accompanied by a Scala 3 macro definition with the same signature. - * - * '''Why introduce the feature?''' Scala 2 macros promise to make the language more regular, - * replacing ad-hoc language constructs with a general powerful abstraction - * capability that can express them. Macros are also a more disciplined and - * powerful replacement for compiler plugins. - * - * '''Why control it?''' For their very power, macros can lead to code that is hard - * to debug and understand. - * - * This is not required by Scala 3 macros as `inline` controls the basic generative macros. - * More add-hoc macros must contain the import of reflection in thier code, making this import redundant. - */ - implicit lazy val macros: languageFeature.experimental.macros = languageFeature.experimental.macros - /** Experimental support for richer dependent types */ object dependent From bf7bb55feeccea9ec71f98ceff67c161fa20e7e5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 15:10:27 +0100 Subject: [PATCH 08/13] Generalize condition for recursive patches --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index c6caa8efc551..bd4bc00a4ec6 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1127,16 +1127,17 @@ class Definitions { * any definitions of `denot` that have the same name as one of the copied * definitions. * + * If an object is present in both the original class and the patch class, + * it is not overwritten. Instead its members are copied recursively. + * * To avpid running into cycles on bootstrap, patching happens only if `patchCls` * is read from a classfile. */ def patchStdLibClass(denot: ClassDenotation)(using Context): Unit = - def recurse(patch: Symbol) = - patch.name.toString.startsWith("experimental") - def patch2(denot: ClassDenotation, patchCls: Symbol): Unit = val scope = denot.info.decls.openForMutations + def recurse(patch: Symbol) = patch.is(Module) && scope.lookup(patch.name).exists if patchCls.exists then val patches = patchCls.info.decls.filter(patch => !patch.isConstructor && !patch.isOneOf(PrivateOrSynthetic)) From 188a2a747163abb40efa2e26aa7550774d0bcc46 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 17:10:18 +0100 Subject: [PATCH 09/13] Replace Scala2compat option in community build --- community-build/community-projects/endpoints4s | 2 +- community-build/community-projects/scalaz | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community-build/community-projects/endpoints4s b/community-build/community-projects/endpoints4s index b271e1d48a81..43c9d9bba39a 160000 --- a/community-build/community-projects/endpoints4s +++ b/community-build/community-projects/endpoints4s @@ -1 +1 @@ -Subproject commit b271e1d48a8184b98f5c64064d6c37e5d9c8f1eb +Subproject commit 43c9d9bba39aa316c0b9132595ff4e260c05ae0b diff --git a/community-build/community-projects/scalaz b/community-build/community-projects/scalaz index c36beee0d025..7d9d32a66127 160000 --- a/community-build/community-projects/scalaz +++ b/community-build/community-projects/scalaz @@ -1 +1 @@ -Subproject commit c36beee0d0256bb4c791ca112e49053da734cd1a +Subproject commit 7d9d32a6612784713c09e9cde8507d34ed9d8f25 From d48ab809eca9ce849e5369ea994aeb4e2267a2ce Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 22 Nov 2020 17:33:58 +0100 Subject: [PATCH 10/13] Don't refer to DottyPredef in community build --- community-build/community-projects/endpoints4s | 2 +- community-build/community-projects/scalaz | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community-build/community-projects/endpoints4s b/community-build/community-projects/endpoints4s index 43c9d9bba39a..b271e1d48a81 160000 --- a/community-build/community-projects/endpoints4s +++ b/community-build/community-projects/endpoints4s @@ -1 +1 @@ -Subproject commit 43c9d9bba39aa316c0b9132595ff4e260c05ae0b +Subproject commit b271e1d48a8184b98f5c64064d6c37e5d9c8f1eb diff --git a/community-build/community-projects/scalaz b/community-build/community-projects/scalaz index 7d9d32a66127..c36beee0d025 160000 --- a/community-build/community-projects/scalaz +++ b/community-build/community-projects/scalaz @@ -1 +1 @@ -Subproject commit 7d9d32a6612784713c09e9cde8507d34ed9d8f25 +Subproject commit c36beee0d0256bb4c791ca112e49053da734cd1a From 27058ab429316cdf2c2e490efd6a113b01648342 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 23 Nov 2020 21:44:13 +0100 Subject: [PATCH 11/13] Patch stdlib classes also when unpickling from Tasty --- compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a8b33bb1df1c..c5983336fbff 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -940,6 +940,7 @@ class TreeUnpickler(reader: TastyReader, val stats = rdr.readIndexedStats(localDummy, end) tparams ++ vparams ++ stats }) + defn.patchStdLibClass(cls) setSpan(start, untpd.Template(constr, mappedParents, Nil, self, lazyStats) .withType(localDummy.termRef)) From d365f695383ecf47ff4bca557b0dbaf72968ebe8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 24 Nov 2020 10:05:08 +0100 Subject: [PATCH 12/13] Drop Scala2Compat again in CB With so much churn it's almost impossible to keep up. --- community-build/community-projects/endpoints4s | 2 +- community-build/community-projects/scalaz | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community-build/community-projects/endpoints4s b/community-build/community-projects/endpoints4s index b271e1d48a81..43c9d9bba39a 160000 --- a/community-build/community-projects/endpoints4s +++ b/community-build/community-projects/endpoints4s @@ -1 +1 @@ -Subproject commit b271e1d48a8184b98f5c64064d6c37e5d9c8f1eb +Subproject commit 43c9d9bba39aa316c0b9132595ff4e260c05ae0b diff --git a/community-build/community-projects/scalaz b/community-build/community-projects/scalaz index c36beee0d025..7d9d32a66127 160000 --- a/community-build/community-projects/scalaz +++ b/community-build/community-projects/scalaz @@ -1 +1 @@ -Subproject commit c36beee0d0256bb4c791ca112e49053da734cd1a +Subproject commit 7d9d32a6612784713c09e9cde8507d34ed9d8f25 From c351094f371729bb83d74fbaa8face9252ca4f12 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 24 Nov 2020 13:01:22 +0100 Subject: [PATCH 13/13] Fix CB yet again --- community-build/community-projects/sourcecode | 2 +- community-build/community-projects/utest | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community-build/community-projects/sourcecode b/community-build/community-projects/sourcecode index 52a013531b34..3dafa7729510 160000 --- a/community-build/community-projects/sourcecode +++ b/community-build/community-projects/sourcecode @@ -1 +1 @@ -Subproject commit 52a013531b343afa3f984efd3352f42935e16ab6 +Subproject commit 3dafa7729510e12b70e7891096ae7b07d9414791 diff --git a/community-build/community-projects/utest b/community-build/community-projects/utest index 4201fc41d25f..ccb1a7e519df 160000 --- a/community-build/community-projects/utest +++ b/community-build/community-projects/utest @@ -1 +1 @@ -Subproject commit 4201fc41d25f5fa1385392d101b8b5b58c1ba1fe +Subproject commit ccb1a7e519dfe60f1a10e5fda3b6315037ce8a57