From d3de543a418bf89bc1ac79e40e9265287ce16dd6 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 29 Nov 2017 16:56:14 +0100 Subject: [PATCH] Simplify Scala 2 trait support Drop vestigial code related to Scala 2.11 support. In particular, we created a fake impl class in AugmentScala2Trait only to add its members to the trait in LinkScala2Impls. We now directly add the members to the trait in LinkScala2Impls. We could potentially simplify things even further by getting rid of LinkScala2Impls since the static `foo$` methods in Scala 2 traits always forward to instance methods `foo`, but that could have performance implication as detailed in #5928, so we keep things as-is for now, but eventually we should either switch Dotty trait encoding to also use static forwarders, or not use them at all. --- .../tools/backend/jvm/BTypesFromSymbols.scala | 2 +- .../tools/backend/jvm/BackendInterface.scala | 1 - .../backend/jvm/DottyBackendInterface.scala | 5 +- .../dotty/tools/backend/sjs/JSCodeGen.scala | 8 -- .../dotty/tools/backend/sjs/JSEncoding.scala | 3 - compiler/src/dotty/tools/dotc/Compiler.scala | 2 +- .../src/dotty/tools/dotc/core/Flags.scala | 24 ++--- compiler/src/dotty/tools/dotc/core/Mode.scala | 3 - .../src/dotty/tools/dotc/core/NameOps.scala | 8 -- .../src/dotty/tools/dotc/core/StdNames.scala | 1 - .../tools/dotc/core/SymDenotations.scala | 7 +- .../dotc/core/classfile/ClassfileParser.scala | 2 - .../core/unpickleScala2/PickleBuffer.scala | 1 - .../core/unpickleScala2/Scala2Flags.scala | 1 - .../core/unpickleScala2/Scala2Unpickler.scala | 2 - .../tools/dotc/printing/PlainPrinter.scala | 1 - .../tools/dotc/printing/RefinedPrinter.scala | 1 - .../tools/dotc/tastyreflect/KernelImpl.scala | 1 - .../dotc/transform/AugmentScala2Traits.scala | 100 ++++++------------ .../dotc/transform/LinkScala2Impls.scala | 71 ++++++------- .../dotty/tools/dotc/transform/Mixin.scala | 40 ++++--- .../dotty/tools/dotc/transform/MixinOps.scala | 1 + .../tools/dotc/transform/SelectStatic.scala | 1 - .../dotty/tools/dotc/transform/SymUtils.scala | 6 -- .../src/scala/tasty/reflect/FlagsOps.scala | 3 - library/src/scala/tasty/reflect/Kernel.scala | 1 - .../src/scala/tasty/reflect/Printers.scala | 2 - .../dotty/semanticdb/SemanticdbConsumer.scala | 2 +- 28 files changed, 102 insertions(+), 198 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala index 09120f742156..8044bb7496e8 100644 --- a/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala +++ b/compiler/src/dotty/tools/backend/jvm/BTypesFromSymbols.scala @@ -61,7 +61,7 @@ class BTypesFromSymbols[I <: BackendInterface](val int: I) extends BTypes { } private def setClassInfo(classSym: Symbol, classBType: ClassBType): ClassBType = { - val superClassSym = if (classSym.isImplClass) ObjectClass else classSym.superClass + val superClassSym = classSym.superClass assert( if (classSym == ObjectClass) superClassSym == NoSymbol diff --git a/compiler/src/dotty/tools/backend/jvm/BackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/BackendInterface.scala index 11f251ae0600..091e3eecd78b 100644 --- a/compiler/src/dotty/tools/backend/jvm/BackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/BackendInterface.scala @@ -484,7 +484,6 @@ abstract class BackendInterface extends BackendInterfaceDefinitions { def isStrictFP: Boolean def isLabel: Boolean def hasPackageFlag: Boolean - def isImplClass: Boolean def isInterface: Boolean def isGetter: Boolean def isSetter: Boolean diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index a5683b5afe02..e2fcb3c61e38 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -666,7 +666,6 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def isStrictFP: Boolean = false // todo: implement def isLabel: Boolean = sym is Flags.Label def hasPackageFlag: Boolean = sym is Flags.Package - def isImplClass: Boolean = sym is Flags.ImplClass def isInterface: Boolean = (sym is Flags.PureInterface) || (sym is Flags.Trait) def isGetter: Boolean = toDenot(sym).isGetter def isSetter: Boolean = toDenot(sym).isSetter @@ -683,7 +682,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def isFinal: Boolean = sym is Flags.Final def isStaticMember: Boolean = (sym ne NoSymbol) && - ((sym is Flags.JavaStatic) || (owner is Flags.ImplClass) || toDenot(sym).hasAnnotation(ctx.definitions.ScalaStaticAnnot)) + ((sym is Flags.JavaStatic) || toDenot(sym).hasAnnotation(ctx.definitions.ScalaStaticAnnot)) // guard against no sumbol cause this code is executed to select which call type(static\dynamic) to use to call array.clone def isBottomClass: Boolean = (sym ne defn.NullClass) && (sym ne defn.NothingClass) @@ -701,7 +700,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma def isNonBottomSubClass(other: Symbol): Boolean = sym.derivesFrom(other) def hasAnnotation(ann: Symbol): Boolean = toDenot(sym).hasAnnotation(ann) def shouldEmitForwarders: Boolean = - (sym is Flags.Module) && !(sym is Flags.ImplClass) && sym.isStatic + (sym is Flags.Module) && sym.isStatic def isJavaEntryPoint: Boolean = CollectEntryPoints.isJavaEntryPoint(sym) def isClassConstructor: Boolean = toDenot(sym).isClassConstructor diff --git a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala index 90839465a6e1..9476d43cb380 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala @@ -1575,8 +1575,6 @@ class JSCodeGen()(implicit ctx: Context) { genApplyJSMethodGeneric(tree, sym, genExpr(receiver), genActualJSArgs(sym, args), isStat) /*else genApplyJSClassMethod(genExpr(receiver), sym, genActualArgs(sym, args))*/ - } else if (foreignIsImplClass(sym.owner)) { - genTraitImplApply(sym, args.map(genExpr)) } else if (sym.isClassConstructor) { // Calls to constructors are always statically linked genApplyMethodStatically(genExpr(receiver), sym, genActualArgs(sym, args)) @@ -2022,12 +2020,6 @@ class JSCodeGen()(implicit ctx: Context) { toIRType(patchedResultType(method))) } - /** Gen a call to a Scala2 impl class method. */ - private def genTraitImplApply(method: Symbol, arguments: List[js.Tree])( - implicit pos: Position): js.Tree = { - genApplyStatic(method, arguments) - } - /** Gen a call to a non-exposed method of a non-native JS class. */ private def genApplyJSClassMethod(receiver: js.Tree, method: Symbol, arguments: List[js.Tree])(implicit pos: Position): js.Tree = { diff --git a/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala b/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala index 95ee81515edf..a18bceb165b4 100644 --- a/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala +++ b/compiler/src/dotty/tools/backend/sjs/JSEncoding.scala @@ -185,9 +185,6 @@ object JSEncoding { js.Ident(localNames.localSymbolName(sym), Some(sym.unexpandedName.decoded)) } - def foreignIsImplClass(sym: Symbol)(implicit ctx: Context): Boolean = - sym.name.endsWith(nme.IMPL_CLASS_SUFFIX.toString) - def encodeClassType(sym: Symbol)(implicit ctx: Context): jstpe.Type = { if (sym == defn.ObjectClass) jstpe.AnyType else if (isJSType(sym)) jstpe.AnyType diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 0157a095cd0b..96404798a651 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -81,7 +81,7 @@ class Compiler { new ElimByName, // Expand by-name parameter references new CollectNullableFields, // Collect fields that can be nulled out after use in lazy initialization new ElimOuterSelect, // Expand outer selections - new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings + new AugmentScala2Traits, // Augments Scala2 traits with additional members needed for mixin composition. new ResolveSuper, // Implement super accessors and add forwarders to trait methods new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify. diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index dca30ce1f82c..479b6753a09e 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -340,6 +340,8 @@ object Flags { /** An unpickled Scala 2.x class */ final val Scala2x: FlagSet = typeFlag(26, "") + final val Scala2xTrait: FlagSet = Scala2x | Trait + final val SuperAccessorOrScala2x: FlagSet = Scala2x.toCommonFlags /** A method that has default params */ @@ -413,11 +415,6 @@ object Flags { /** Symbol is a self name */ final val SelfName: FlagSet = termFlag(54, "") - /** Symbol is an implementation class of a Scala2 trait */ - final val ImplClass: FlagSet = typeFlag(54, "") - - final val SelfNameOrImplClass: FlagSet = SelfName.toCommonFlags - /** An existentially bound symbol (Scala 2.x only) */ final val Scala2ExistentialCommon: FlagSet = commonFlag(55, "") final val Scala2Existential: FlagSet = Scala2ExistentialCommon.toTypeFlags @@ -428,14 +425,11 @@ object Flags { /** A module variable (Scala 2.x only) */ final val Scala2ModuleVar: FlagSet = termFlag(57, "") - /** A Scala 2.12 trait that has been augmented with static members */ - final val Scala_2_12_Augmented: FlagSet = typeFlag(57, "") - - /** A definition that's initialized before the super call (Scala 2.x only) */ - final val Scala2PreSuper: FlagSet = termFlag(58, "") - - /** A Scala 2.12 or higher trait */ - final val Scala_2_12_Trait: FlagSet = typeFlag(58, "") + /** A Scala 2.x trait that has been partially augmented. + * This is set in `AugmentScala2Trait` and reset in `LinkScala2Impls` + * when the trait is fully augmented. + */ + final val Scala2xPartiallyAugmented: FlagSet = typeFlag(57, "") /** A macro */ final val Macro: FlagSet = commonFlag(59, "") @@ -497,7 +491,7 @@ object Flags { * is completed) */ final val AfterLoadFlags: FlagSet = - FromStartFlags | AccessFlags | Final | AccessorOrSealed | LazyOrTrait | SelfNameOrImplClass + FromStartFlags | AccessFlags | Final | AccessorOrSealed | LazyOrTrait | SelfName.toCommonFlags assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags) // TODO: Should check that FromStartFlags do not change in completion @@ -549,7 +543,7 @@ object Flags { /** Flags that can apply to a module class */ final val RetainedModuleClassFlags: FlagSet = RetainedModuleValAndClassFlags | - ImplClass | Enum | Opaque + Enum | Opaque /** Flags that are copied from a synthetic companion to a user-defined one * when the two are merged. See: Namer.mergeCompanionDefs diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 1d794486aea1..57fd67956205 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -69,9 +69,6 @@ object Mode { /** We are currently unpickling Scala2 info */ val Scala2Unpickling: Mode = newMode(13, "Scala2Unpickling") - /** We are currently unpickling from Java 8 or higher */ - val Java8Unpickling: Mode = newMode(14, "Java8Unpickling") - /** Use Scala2 scheme for overloading and implicit resolution */ val OldOverloadingResolution: Mode = newMode(15, "OldOverloadingResolution") diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 7f26a68687fe..91b1d611bee2 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -141,14 +141,6 @@ object NameOps { name.replace { case VariantName(invariant, _) => invariant } } - def implClassName: N = likeSpacedN(name ++ tpnme.IMPL_CLASS_SUFFIX) - - def traitOfImplClassName: N = { - val suffix = tpnme.IMPL_CLASS_SUFFIX.toString - assert(name.endsWith(suffix), name) - likeSpacedN(name.mapLast(_.dropRight(suffix.length))) - } - def errorName: N = likeSpacedN(name ++ nme.ERROR) /** Map variance value -1, +1 to 0, 1 */ diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index 85d4d4832f1b..2f89a4eb18f6 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -128,7 +128,6 @@ object StdNames { val EMPTY_PACKAGE: N = "" val EXCEPTION_RESULT_PREFIX: N = "exceptionResult" val EXPAND_SEPARATOR: N = str.EXPAND_SEPARATOR - val IMPL_CLASS_SUFFIX: N = "$class" val IMPORT: N = "" val MODULE_SUFFIX: N = str.MODULE_SUFFIX val OPS_PACKAGE: N = "" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index ab0e9b3ed9d4..84e8384d3459 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -650,9 +650,6 @@ object SymDenotations { /** is this the constructor of a class? */ final def isClassConstructor: Boolean = name == nme.CONSTRUCTOR - /** Is this the constructor of a trait? */ - final def isImplClassConstructor: Boolean = name == nme.TRAIT_CONSTRUCTOR - /** Is this the constructor of a trait or a class */ final def isConstructor: Boolean = name.isConstructorName @@ -757,7 +754,6 @@ object SymDenotations { || boundary.isRoot || (accessWithin(boundary) || accessWithinLinked(boundary)) && ( !(this is Local) - || (owner is ImplClass) // allow private local accesses to impl class members || isCorrectThisType(pre) ) || (this is Protected) && @@ -1901,8 +1897,7 @@ object SymDenotations { override def primaryConstructor(implicit ctx: Context): Symbol = { def constrNamed(cname: TermName) = info.decls.denotsNamed(cname).last.symbol // denotsNamed returns Symbols in reverse order of occurrence - if (this.is(ImplClass)) constrNamed(nme.TRAIT_CONSTRUCTOR) // ignore normal constructor - else if (this.is(Package)) NoSymbol + if (this.is(Package)) NoSymbol else constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR)) } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 66b9079b299e..790b6cc403e8 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -99,8 +99,6 @@ class ClassfileParser( throw new IOException(s"class file '${in.file}' has wrong magic number 0x${toHexString(magic)}, should be 0x${toHexString(JAVA_MAGIC)}") val minorVersion = in.nextChar.toInt val majorVersion = in.nextChar.toInt - if (majorVersion >= JAVA8_MAJOR_VERSION) - Scala2UnpicklingMode |= Mode.Java8Unpickling if ((majorVersion < JAVA_MAJOR_VERSION) || ((majorVersion == JAVA_MAJOR_VERSION) && (minorVersion < JAVA_MINOR_VERSION))) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala index 0c97afb20d15..78014fba2ce6 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/PickleBuffer.scala @@ -230,7 +230,6 @@ object PickleBuffer { LAZY -> Lazy, MIXEDIN -> (MixedIn, Scala2Existential), EXPANDEDNAME -> Scala2ExpandedName, - IMPLCLASS -> (Scala2PreSuper, ImplClass), SPECIALIZED -> Specialized, VBRIDGE -> EmptyFlags, VARARGS -> JavaVarargs, diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala index 5025a7a54997..1624f90e80fc 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Flags.scala @@ -80,7 +80,6 @@ object Scala2Flags { final val MIXEDIN = 1L << 35 // term member has been mixed in final val EXISTENTIAL = 1L << 35 // type is an existential parameter or skolem final val EXPANDEDNAME = 1L << 36 // name has been expanded with class suffix - final val IMPLCLASS = 1L << 37 // symbol is an implementation class final val TRANS_FLAG = 1L << 38 // transient flag guaranteed to be reset after each phase. final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 62fc814003df..d7d934d2805d 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -474,8 +474,6 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas def finishSym(sym: Symbol): Symbol = { if (sym.isClass) { sym.setFlag(Scala2x) - if (flags.is(Trait) && ctx.mode.is(Mode.Java8Unpickling)) - sym.setFlag(Scala_2_12_Trait) } if (!(isRefinementClass(sym) || isUnpickleRoot(sym) || (sym is Scala2Existential))) { val owner = sym.owner diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index a30ddea7af1c..34e26a4b8ceb 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -368,7 +368,6 @@ class PlainPrinter(_ctx: Context) extends Printer { else if (sym.isAnonymousClass) "anonymous class" else if (flags is ModuleClass) "module class" else if (flags is ModuleVal) "module" - else if (flags is ImplClass) "implementation class" else if (flags is Trait) "trait" else if (sym.isClass) "class" else if (sym.isType) "type" diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 8a03f518e634..b5cc53874251 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -833,7 +833,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (flags is Package) "package" else if (sym.isPackageObject) "package object" else if (flags is Module) "object" - else if (flags is ImplClass) "class" else if (sym.isClassConstructor) "constructor" else super.kindString(sym) } diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala b/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala index 87d9791322fb..2dfa27bde725 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala @@ -1611,7 +1611,6 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util. def Flags_ModuleClass: Flags = core.Flags.ModuleClass def Flags_PrivateLocal: Flags = core.Flags.PrivateLocal def Flags_Package: Flags = core.Flags.Package - def Flags_ImplClass: Flags = core.Flags.ImplClass // // QUOTED SEAL/UNSEAL diff --git a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala index b1ba4d987131..d63d7303a1f4 100644 --- a/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala +++ b/compiler/src/dotty/tools/dotc/transform/AugmentScala2Traits.scala @@ -14,93 +14,59 @@ import Annotations._ import StdNames._ import NameOps._ import NameKinds.{ExpandedName, TraitSetterName} +import ast.Trees._ object AugmentScala2Traits { val name: String = "augmentScala2Traits" } -/** This phase augments Scala2 traits with implementation classes and with additional members - * needed for mixin composition. - * These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline. - * Specifically, it adds +/** This phase augments Scala2 traits with additional members needed for mixin composition. * - * - an implementation class which defines a trait constructor and trait method implementations - * - trait setters for vals defined in traits + * These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline. * - * Furthermore, it expands the names of all private getters and setters as well as super accessors in the trait and makes - * them not-private. + * Specifically, we: + * - Mark all lazy val fields as @volatile to get the proper Scala 2 semantics. + * - Add trait setters for vals defined in traits. + * - Expand the names of all private getters and setters as well as super accessors in the trait and make + * not-private. */ -class AugmentScala2Traits extends MiniPhase with IdentityDenotTransformer with FullParameterization { thisPhase => +class AugmentScala2Traits extends MiniPhase with IdentityDenotTransformer { thisPhase => import ast.tpd._ override def changesMembers: Boolean = true override def phaseName: String = AugmentScala2Traits.name - override def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context): Symbol = NoSymbol - override def transformTemplate(impl: Template)(implicit ctx: Context): Template = { val cls = impl.symbol.owner.asClass - for (mixin <- cls.mixins) - if (mixin.is(Scala2x)) - augmentScala2Trait(mixin, cls) + for (mixin <- cls.mixins if mixin.is(Scala2x) && !mixin.is(Scala2xPartiallyAugmented)) + augmentScala2Trait(mixin) impl } - private def augmentScala2Trait(mixin: ClassSymbol, cls: ClassSymbol)(implicit ctx: Context): Unit = { - if (mixin.implClass.is(Scala2x)) () // nothing to do, mixin was already augmented - else { - //println(i"creating new implclass for $mixin ${mixin.implClass}") - val ops = new MixinOps(cls, thisPhase) - import ops._ - - val implClass = ctx.newCompleteClassSymbol( - owner = mixin.owner, - name = mixin.name.implClassName, - flags = Abstract | Scala2x | ImplClass, - parents = defn.ObjectType :: Nil, - assocFile = mixin.assocFile).enteredAfter(thisPhase) - - def implMethod(meth: TermSymbol): Symbol = { - val mold = - if (meth.isConstructor) - meth.copySymDenotation( - name = nme.TRAIT_CONSTRUCTOR, - info = MethodType(Nil, defn.UnitType)) - else meth.ensureNotPrivate - meth.copy( - owner = implClass, - name = mold.name.asTermName, - flags = Method | JavaStatic, - info = fullyParameterizedType(mold.info, mixin)) - } - - def traitSetter(getter: TermSymbol) = - getter.copy( - name = getter.ensureNotPrivate.name - .expandedName(getter.owner, TraitSetterName) - .asTermName.setterName, - flags = Method | Accessor, - info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) + private def augmentScala2Trait(mixin: ClassSymbol)(implicit ctx: Context): Unit = { + def traitSetter(getter: TermSymbol) = + getter.copy( + name = getter.ensureNotPrivate.name + .expandedName(getter.owner, TraitSetterName) + .asTermName.setterName, + flags = Method | Accessor, + info = MethodType(getter.info.resultType :: Nil, defn.UnitType)) - for (sym <- mixin.info.decls) { - if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred)) - implClass.enter(implMethod(sym.asTerm)) - if (sym.isGetter) - if (sym.is(Lazy)) { - if (!sym.hasAnnotation(defn.VolatileAnnot)) - sym.addAnnotation(Annotation(defn.VolatileAnnot, Nil)) - } - else if (!sym.is(Deferred) && !sym.setter.exists && - !sym.info.resultType.isInstanceOf[ConstantType]) - traitSetter(sym.asTerm).enteredAfter(thisPhase) - if ((sym.is(PrivateAccessor) && !sym.name.is(ExpandedName) && - (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. - || sym.isSuperAccessor) // scala2 superaccessors are pickled as private, but are compiled as public expanded - sym.ensureNotPrivate.installAfter(thisPhase) - } - ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %") - ctx.log(i"Scala2x impl decls of $mixin = ${implClass.info.decls.toList.map(_.showDcl)}%\n %") + for (sym <- mixin.info.decls) { + if (sym.isGetter) + if (sym.is(Lazy)) { + if (!sym.hasAnnotation(defn.VolatileAnnot)) + sym.addAnnotation(Annotation(defn.VolatileAnnot, Nil)) + } + else if (!sym.is(Deferred) && !sym.setter.exists && + !sym.info.resultType.isInstanceOf[ConstantType]) + traitSetter(sym.asTerm).enteredAfter(thisPhase) + if ((sym.is(PrivateAccessor) && !sym.name.is(ExpandedName) && + (sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set. + || sym.isSuperAccessor) // scala2 superaccessors are pickled as private, but are compiled as public expanded + sym.ensureNotPrivate.installAfter(thisPhase) } + mixin.setFlag(Scala2xPartiallyAugmented) } } diff --git a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala index a6768fced4ec..f84eb86f2a42 100644 --- a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala +++ b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala @@ -18,16 +18,11 @@ import NameKinds.ImplMethName * * super[M].f(args) * - * where M is a Scala 2.11 trait implemented by the current class to + * where M is a Scala 2.x trait implemented by the current class to * - * M$class.f(this, args) + * M.f$(this, args) * - * provided the implementation class M$class defines a corresponding function `f`. - * If M is a Scala 2.12 or newer trait, rewrite to - * - * M.f(this, args) - * - * where f is a static member of M. + * where f$ is a static member of M. */ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhase => import ast.tpd._ @@ -39,32 +34,40 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas // Adds as a side effect static members to traits which can confuse Mixin, // that's why it is runsAfterGroupOf - /** Copy definitions from implementation class to trait itself */ - private def augmentScala_2_12_Trait(mixin: ClassSymbol)(implicit ctx: Context): Unit = { - def info_2_12(sym: Symbol) = sym.info match { - case mt @ MethodType(paramNames @ nme.SELF :: _) => - // 2.12 seems to always assume the enclsing mixin class as self type parameter, - // whereas 2.11 used the self type of this class instead. - val selfType :: otherParamTypes = mt.paramInfos - MethodType(paramNames, mixin.typeRef :: otherParamTypes, mt.resType) - case info => info + private def addStaticForwarders(mixin: ClassSymbol)(implicit ctx: Context): Unit = { + val ops = new MixinOps(mixin, thisPhase) + import ops._ + + def newImpl(meth: TermSymbol): Symbol = { + def staticInfo(tp: Type) = tp match { + case mt: MethodType => + MethodType(nme.SELF :: mt.paramNames, mixin.typeRef :: mt.paramInfos, mt.resType) + } + val mold = + if (meth.isConstructor) + meth.copySymDenotation( + name = nme.TRAIT_CONSTRUCTOR, + info = MethodType(Nil, defn.UnitType)) + else meth.ensureNotPrivate + meth.copy( + owner = mixin, + name = if (meth.isConstructor) mold.name.asTermName else ImplMethName(mold.name.asTermName), + flags = Method | JavaStatic, + info = staticInfo(mold.info) + ) } - def newImpl(sym: TermSymbol): Symbol = sym.copy( - owner = mixin, - name = if (sym.isConstructor) sym.name else ImplMethName(sym.name), - info = info_2_12(sym) - ) - for (sym <- mixin.implClass.info.decls) - newImpl(sym.asTerm).enteredAfter(thisPhase) + for (sym <- mixin.info.decls) { + if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred)) + newImpl(sym.asTerm).enteredAfter(thisPhase) + } + // The trait is now fully augmented so the flag isn't needed anymore. + mixin.resetFlag(Scala2xPartiallyAugmented) } override def prepareForTemplate(impl: Template)(implicit ctx: Context): Context = { val cls = impl.symbol.owner.asClass - for (mixin <- cls.mixins) - if (mixin.is(Scala_2_12_Trait, butNot = Scala_2_12_Augmented)) { - augmentScala_2_12_Trait(mixin) - mixin.setFlag(Scala_2_12_Augmented) - } + for (mixin <- cls.mixins if (mixin.is(Scala2xPartiallyAugmented))) + addStaticForwarders(mixin) ctx } @@ -72,14 +75,10 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas def currentClass = ctx.owner.enclosingClass.asClass app match { case Apply(sel @ Select(Super(_, _), _), args) - if sel.symbol.owner.is(Scala2xTrait) && currentClass.mixins.contains(sel.symbol.owner) => + if sel.symbol.owner.is(Scala2x) && currentClass.mixins.contains(sel.symbol.owner) => val impl = implMethod(sel.symbol) if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withSpan(app.span) else app // could have been an abstract method in a trait linked to from a super constructor - case Apply(sel, args) - if sel.symbol.maybeOwner.is(ImplClass) && sel.symbol.owner.traitOfImplClass.is(Scala_2_12_Trait) => - val impl = implMethod(sel.symbol) - cpy.Apply(app)(ref(impl), args) case _ => app } @@ -89,9 +88,7 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = { val implName = ImplMethName(meth.name.asTermName) val cls = meth.owner - if (cls.is(ImplClass)) - cls.traitOfImplClass.info.decl(implName).atSignature(meth.signature).symbol - else if (cls.is(Scala_2_12_Trait)) + if (cls.is(Scala2xTrait)) if (meth.isConstructor) cls.info.decl(nme.TRAIT_CONSTRUCTOR).symbol else diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index bc925f6a9aad..1d7029c8433b 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -59,19 +59,23 @@ object Mixin { * 3.2 (done in `traitInits`) For every concrete trait getter ` def x(): T` in M * which is not a parameter accessor, in order of textual occurrence, produce the following: * - * 3.2.1 If `x` is also a member of `C`, and M is a Dotty trait: + * 3.2.1 If `x` is also a member of `C`, and is a lazy val, + * + * lazy val x: T = super[M].x + * + * 3.2.2 If `x` is also a member of `C`, and M is a Dotty trait, * * def x(): T = super[M].initial$x() * - * 3.2.2 If `x` is also a member of `C`, and M is a Scala 2.x trait: + * 3.2.3 If `x` is also a member of `C`, and M is a Scala 2.x trait: * * def x(): T = _ * - * 3.2.3 If `x` is not a member of `C`, and M is a Dotty trait: + * 3.2.4 If `x` is not a member of `C`, and M is a Dotty trait: * * super[M].initial$x() * - * 3.2.4 If `x` is not a member of `C`, and M is a Scala2.x trait, nothing gets added. + * 3.2.5 If `x` is not a member of `C`, and M is a Scala2.x trait, nothing gets added. * * * 3.3 (done in `superCallOpt`) The call: @@ -111,7 +115,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => else sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred) sym1.ensureNotPrivate } - else if (sym.isConstructor && sym.owner.is(Trait)) + else if (sym.isConstructor && sym.owner.is(Trait, butNot = Scala2x)) sym.copySymDenotation( name = nme.TRAIT_CONSTRUCTOR, info = MethodType(Nil, sym.info.resultType)) @@ -220,26 +224,20 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => def default = Underscore(getter.info.resultType) def initial = transformFollowing(superRef(initializer(getter)).appliedToNone) - /** A call to the implementation of `getter` in `mixin`'s implementation class */ - def lazyGetterCall = { - def canbeImplClassGetter(sym: Symbol) = sym.info.firstParamTypes match { - case t :: Nil => t.isDirectRef(mixin) - case _ => false - } - val implClassGetter = mixin.implClass.info.nonPrivateDecl(getter.name) - .suchThat(canbeImplClassGetter).symbol - ref(mixin.implClass).select(implClassGetter).appliedTo(This(cls)) - } - if (isCurrent(getter) || getter.name.is(ExpandedName)) { val rhs = - if (was(getter, ParamAccessor)) nextArgument() - else if (isScala2x) - if (getter.is(Lazy, butNot = Module)) lazyGetterCall + if (was(getter, ParamAccessor)) + nextArgument() + else if (isScala2x) { + if (getter.is(Lazy, butNot = Module)) + initial else if (getter.is(Module)) New(getter.info.resultType, List(This(cls))) - else Underscore(getter.info.resultType) - else initial + else + Underscore(getter.info.resultType) + } + else + initial // transformFollowing call is needed to make memoize & lazy vals run transformFollowing(DefDef(implementation(getter.asTerm), rhs)) } diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index a78ee88886da..611c621f8750 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -63,6 +63,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(implicit ctx: Cont def needsDisambiguation = competingMethods.exists(x=> !(x is Deferred)) // multiple implementations are available def hasNonInterfaceDefinition = competingMethods.exists(!_.owner.is(Trait)) // there is a definition originating from class + !meth.isConstructor && meth.is(Method, butNot = PrivateOrAccessorOrDeferred) && (meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition || needsJUnit4Fix(meth) ) && isCurrent(meth) diff --git a/compiler/src/dotty/tools/dotc/transform/SelectStatic.scala b/compiler/src/dotty/tools/dotc/transform/SelectStatic.scala index 761d092da972..0203d456b68b 100644 --- a/compiler/src/dotty/tools/dotc/transform/SelectStatic.scala +++ b/compiler/src/dotty/tools/dotc/transform/SelectStatic.scala @@ -25,7 +25,6 @@ class SelectStatic extends MiniPhase with IdentityDenotTransformer { def isStaticMember = (sym is Flags.Module) && sym.initial.maybeOwner.initial.isStaticOwner || (sym is Flags.JavaStatic) || - (sym.maybeOwner is Flags.ImplClass) || sym.hasAnnotation(ctx.definitions.ScalaStaticAnnot) val isStaticRef = !sym.is(Package) && !sym.maybeOwner.is(Package) && isStaticMember val tree1 = diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 355bef8f1268..af4c991b37be 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -111,12 +111,6 @@ class SymUtils(val self: Symbol) extends AnyVal { def isField(implicit ctx: Context): Boolean = self.isTerm && !self.is(Method) - def implClass(implicit ctx: Context): Symbol = - self.owner.info.decl(self.name.implClassName).symbol - - def traitOfImplClass(implicit ctx: Context): Symbol = - self.owner.info.decl(self.name.traitOfImplClassName).symbol - def annotationsCarrying(meta: ClassSymbol)(implicit ctx: Context): List[Annotation] = self.annotations.filter(_.symbol.hasAnnotation(meta)) diff --git a/library/src/scala/tasty/reflect/FlagsOps.scala b/library/src/scala/tasty/reflect/FlagsOps.scala index 4b5422fbc4af..0b52f1a3a416 100644 --- a/library/src/scala/tasty/reflect/FlagsOps.scala +++ b/library/src/scala/tasty/reflect/FlagsOps.scala @@ -115,9 +115,6 @@ trait FlagsOps extends Core { /** Is this symbol a package */ def Package: Flags = kernel.Flags_Package - - /** Is this symbol an implementation class of a Scala2 trait */ - def ImplClass: Flags = kernel.Flags_ImplClass } } diff --git a/library/src/scala/tasty/reflect/Kernel.scala b/library/src/scala/tasty/reflect/Kernel.scala index 00a1b5c4f94e..237b507bdc47 100644 --- a/library/src/scala/tasty/reflect/Kernel.scala +++ b/library/src/scala/tasty/reflect/Kernel.scala @@ -1321,7 +1321,6 @@ trait Kernel { def Flags_ModuleClass: Flags def Flags_PrivateLocal: Flags def Flags_Package: Flags - def Flags_ImplClass: Flags // // QUOTED SEAL/UNSEAL diff --git a/library/src/scala/tasty/reflect/Printers.scala b/library/src/scala/tasty/reflect/Printers.scala index 7bdc718789c5..1049dfc2a247 100644 --- a/library/src/scala/tasty/reflect/Printers.scala +++ b/library/src/scala/tasty/reflect/Printers.scala @@ -164,7 +164,6 @@ trait Printers if (flags.is(Flags.ModuleClass)) flagList += "Flags.ModuleClass" if (flags.is(Flags.PrivateLocal)) flagList += "Flags.PrivateLocal" if (flags.is(Flags.Package)) flagList += "Flags.Package" - if (flags.is(Flags.ImplClass)) flagList += "Flags.ImplClass" flagList.result().mkString(" | ") } @@ -540,7 +539,6 @@ trait Printers if (flags.is(Flags.ModuleClass)) flagList += "moduleClass" if (flags.is(Flags.PrivateLocal)) flagList += "private[this]" if (flags.is(Flags.Package)) flagList += "package" - if (flags.is(Flags.ImplClass)) flagList += "implClass" flagList.result().mkString("/*", " ", "*/") } diff --git a/semanticdb/src/dotty/semanticdb/SemanticdbConsumer.scala b/semanticdb/src/dotty/semanticdb/SemanticdbConsumer.scala index 91981fb6ed4c..63de499a730d 100644 --- a/semanticdb/src/dotty/semanticdb/SemanticdbConsumer.scala +++ b/semanticdb/src/dotty/semanticdb/SemanticdbConsumer.scala @@ -321,7 +321,7 @@ class SemanticdbConsumer(sourceFilePath: java.nio.file.Path) extends TastyConsum } def isStaticMember(implicit ctx: Context): Boolean = symbol.exists && - (symbol.flags.is(Flags.Static) || symbol.owner.flags.is(Flags.ImplClass) || + (symbol.flags.is(Flags.Static) || /*symbol.annots.find(_ == ctx.definitions.ScalaStaticAnnot)*/ false) def isStaticConstructor(implicit ctx: Context): Boolean = {