Skip to content

Remove PreName add (almost) all other implicit conversions #4077

New issue

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

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

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,4 @@ compiler/after-pickling.txt
*.dotty-ide-version

*.decompiled.out
bench/compile.txt
Copy link
Contributor

Choose a reason for hiding this comment

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

This commit LGTM

16 changes: 8 additions & 8 deletions compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
lazy val Predef_classOf: Symbol = defn.ScalaPredefModule.requiredMethod(nme.classOf)
Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer we leave PreName, but move the String -> PreName conversion to the companion object of PreName.

Copy link
Contributor Author

@OlivierBlanvillain OlivierBlanvillain Apr 12, 2018

Choose a reason for hiding this comment

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

That doesn't work as moving it the companion of PreName is not enough to make .toTermName and .toTypeName available on Strings. I guess we could have two implicit conversions, one in PreName's companion and one available by import, but I feel it would just make things worse...

Are you sure you don't like this commit as is? In my opinion, completely removing an abstraction from the code base is a clear simplification. The diff might look large but in reality, most of the line changes are about making type more precise by having the TermName/TypeName instead of PreName. The balance sheet in term of added boilerplate is also reasonable:

toTermName added: 22
toTermName removed: 12

toTypeName added: 12
toTypeName removed: 4

+4 overloaded methods with String & Name arguments

Copy link
Contributor

Choose a reason for hiding this comment

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

I still think we should leave PreName. I don't like to have to overload methods, and the problem is, if you are systematic about it (and you should be!) you will end up with a lot more overloaded methods. PreName is a single abstraction which fixes this quite nicely. For me it is really analogous to IterableOnce in collections. Before we had some overloaded methods that took Iterables and Iterators respectively. At first there were only a few. Then people complained that, by rights, some other methods should also be dual purpose, and then some others more, and so on. The introduction of IterableOnce stopped the bleeding.

I realize it's a contentious issue, but then the maxime "when in doubt, don't change it" applies.

One other thing: We have to tell everyone working on the compiler that Decorators is a highly recommended (maybe mandatory?) input. I have seen so much awkward code because people did not know about it. Is there a good place where we can put it so people will read it?


lazy val AnnotationRetentionAttr = ctx.requiredClass("java.lang.annotation.Retention")
lazy val AnnotationRetentionSourceAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("SOURCE")
lazy val AnnotationRetentionClassAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("CLASS")
lazy val AnnotationRetentionRuntimeAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("RUNTIME")
lazy val AnnotationRetentionSourceAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("SOURCE".toTermName)
lazy val AnnotationRetentionClassAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("CLASS".toTermName)
lazy val AnnotationRetentionRuntimeAttr = ctx.requiredClass("java.lang.annotation.RetentionPolicy").linkedClass.requiredValue("RUNTIME".toTermName)
lazy val JavaAnnotationClass = ctx.requiredClass("java.lang.annotation.Annotation")

def boxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map{x => // @darkdimius Are you sure this should be a def?
Expand Down Expand Up @@ -366,7 +366,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
def getAnnotPickle(jclassName: String, sym: Symbol): Option[Annotation] = None


def getRequiredClass(fullname: String): Symbol = ctx.requiredClass(fullname.toTermName)
def getRequiredClass(fullname: String): Symbol = ctx.requiredClass(fullname)

def getClassIfDefined(fullname: String): Symbol = NoSymbol // used only for android. todo: implement

Expand All @@ -376,12 +376,12 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
}

def requiredClass[T](implicit evidence: ClassTag[T]): Symbol =
ctx.requiredClass(erasureString(evidence.runtimeClass).toTermName)
ctx.requiredClass(erasureString(evidence.runtimeClass))

def requiredModule[T](implicit evidence: ClassTag[T]): Symbol = {
val moduleName = erasureString(evidence.runtimeClass)
val className = if (moduleName.endsWith("$")) moduleName.dropRight(1) else moduleName
ctx.requiredModule(className.toTermName)
ctx.requiredModule(className)
}


Expand Down Expand Up @@ -1193,8 +1193,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma
val arity = field.meth.tpe.widenDealias.paramTypes.size - _1.size
val returnsUnit = field.meth.tpe.widenDealias.resultType.classSymbol == UnitClass
if (returnsUnit)
ctx.requiredClass(("scala.compat.java8.JProcedure" + arity).toTermName)
else ctx.requiredClass(("scala.compat.java8.JFunction" + arity).toTermName)
ctx.requiredClass("scala.compat.java8.JProcedure" + arity)
else ctx.requiredClass("scala.compat.java8.JFunction" + arity)
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions compiler/src/dotty/tools/dotc/core/Decorators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,10 @@ import printing.Formatting._

/** This object provides useful implicit decorators for types defined elsewhere */
object Decorators {

/** Turns Strings into PreNames, adding toType/TermName methods */
implicit class PreNamedString(val s: String) extends AnyVal with PreName {
implicit class StringDecorator(val s: String) extends AnyVal {
def toTypeName: TypeName = typeName(s)
def toTermName: TermName = termName(s)
def toText(printer: Printer): Text = Str(s)
}

implicit class StringDecorator(val s: String) extends AnyVal {
def splitWhere(f: Char => Boolean, doDropIndex: Boolean): Option[(String, String)] = {
def splitAt(idx: Int, doDropIndex: Boolean): Option[(String, String)] =
if (idx == -1) None
Expand Down
35 changes: 17 additions & 18 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ class Definitions {
lazy val OpsPackageVal = ctx.newCompletePackageSymbol(RootClass, nme.OPS_PACKAGE).entered
lazy val OpsPackageClass = OpsPackageVal.moduleClass.asClass

lazy val ScalaPackageVal = ctx.requiredPackage("scala")
lazy val ScalaMathPackageVal = ctx.requiredPackage("scala.math")
lazy val ScalaPackageVal = ctx.requiredPackage(nme.scala_)
lazy val ScalaMathPackageVal = ctx.requiredPackage("scala.math".toTermName)
lazy val ScalaPackageClass = {
val cls = ScalaPackageVal.moduleClass.asClass
cls.info.decls.openForMutations.useSynthesizer(
Expand All @@ -212,8 +212,8 @@ class Definitions {
cls
}
lazy val ScalaPackageObjectRef = ctx.requiredModuleRef("scala.package")
lazy val JavaPackageVal = ctx.requiredPackage("java")
lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang")
lazy val JavaPackageVal = ctx.requiredPackage(nme.java)
lazy val JavaLangPackageVal = ctx.requiredPackage(jnme.JavaLang)
// fundamental modules
lazy val SysPackage = ctx.requiredModule("scala.sys.package")
lazy val Sys_errorR = SysPackage.moduleClass.requiredMethodRef(nme.error)
Expand Down Expand Up @@ -336,13 +336,13 @@ class Definitions {
lazy val ScalaPredefModuleRef = ctx.requiredModuleRef("scala.Predef")
def ScalaPredefModule(implicit ctx: Context) = ScalaPredefModuleRef.symbol

lazy val Predef_ConformsR = ScalaPredefModule.requiredClass("<:<").typeRef
lazy val Predef_ConformsR = ScalaPredefModule.requiredClass("<:<".toTypeName).typeRef
def Predef_Conforms(implicit ctx: Context) = Predef_ConformsR.symbol
lazy val Predef_conformsR = ScalaPredefModule.requiredMethodRef("$conforms")
lazy val Predef_conformsR = ScalaPredefModule.requiredMethodRef(nme.conforms_)
def Predef_conforms(implicit ctx: Context) = Predef_conformsR.symbol
lazy val Predef_classOfR = ScalaPredefModule.requiredMethodRef("classOf")
lazy val Predef_classOfR = ScalaPredefModule.requiredMethodRef(nme.classOf)
def Predef_classOf(implicit ctx: Context) = Predef_classOfR.symbol
lazy val Predef_undefinedR = ScalaPredefModule.requiredMethodRef("???")
lazy val Predef_undefinedR = ScalaPredefModule.requiredMethodRef(nme.???)
def Predef_undefined(implicit ctx: Context) = Predef_undefinedR.symbol
// The set of all wrap{X, Ref}Array methods, where X is a value type
val Predef_wrapArray = new PerRun[collection.Set[Symbol]]({ implicit ctx =>
Expand All @@ -354,7 +354,7 @@ class Definitions {
def ScalaRuntimeModule(implicit ctx: Context) = ScalaRuntimeModuleRef.symbol
def ScalaRuntimeClass(implicit ctx: Context) = ScalaRuntimeModule.moduleClass.asClass

def runtimeMethodRef(name: PreName) = ScalaRuntimeModule.requiredMethodRef(name)
def runtimeMethodRef(name: TermName) = ScalaRuntimeModule.requiredMethodRef(name)
def ScalaRuntime_dropR(implicit ctx: Context) = runtimeMethodRef(nme.drop)
def ScalaRuntime_drop(implicit ctx: Context) = ScalaRuntime_dropR.symbol

Expand All @@ -365,8 +365,8 @@ class Definitions {
def ScalaStaticsModule(implicit ctx: Context) = ScalaStaticsModuleRef.symbol
def ScalaStaticsClass(implicit ctx: Context) = ScalaStaticsModule.moduleClass.asClass

def staticsMethodRef(name: PreName) = ScalaStaticsModule.requiredMethodRef(name)
def staticsMethod(name: PreName) = ScalaStaticsModule.requiredMethod(name)
def staticsMethodRef(name: TermName) = ScalaStaticsModule.requiredMethodRef(name)
def staticsMethod(name: TermName): TermSymbol = ScalaStaticsModule.requiredMethod(name)

// Dotty deviation: we cannot use a lazy val here because lazy vals in dotty
// will return "null" when called recursively, see #1856.
Expand All @@ -381,13 +381,13 @@ class Definitions {

def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol

lazy val Predef_ImplicitConverterR = DottyPredefModule.requiredClass("ImplicitConverter").typeRef
lazy val Predef_ImplicitConverterR = DottyPredefModule.requiredClass("ImplicitConverter".toTypeName).typeRef
def Predef_ImplicitConverter(implicit ctx: Context) = Predef_ImplicitConverterR.symbol

lazy val DottyArraysModuleRef = ctx.requiredModuleRef("dotty.runtime.Arrays")
def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol
def newGenericArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newGenericArray")
def newArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newArray")
def newGenericArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newGenericArray".toTermName)
def newArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newArray".toTermName)

lazy val NilModuleRef = ctx.requiredModuleRef("scala.collection.immutable.Nil")
def NilModule(implicit ctx: Context) = NilModuleRef.symbol
Expand Down Expand Up @@ -494,7 +494,7 @@ class Definitions {
lazy val BoxedUnitType: TypeRef = ctx.requiredClassRef("scala.runtime.BoxedUnit")
def BoxedUnitClass(implicit ctx: Context) = BoxedUnitType.symbol.asClass

def BoxedUnit_UNIT(implicit ctx: Context) = BoxedUnitClass.linkedClass.requiredValue("UNIT")
def BoxedUnit_UNIT(implicit ctx: Context) = BoxedUnitClass.linkedClass.requiredValue("UNIT".toTermName)

lazy val BoxedBooleanType: TypeRef = ctx.requiredClassRef("java.lang.Boolean")
def BoxedBooleanClass(implicit ctx: Context) = BoxedBooleanType.symbol.asClass
Expand Down Expand Up @@ -635,8 +635,8 @@ class Definitions {
lazy val QuotedType_applyR = QuotedTypeModule.requiredMethodRef(nme.apply)
def QuotedType_apply(implicit ctx: Context) = QuotedType_applyR.symbol

def Unpickler_unpickleExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr")
def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")
def Unpickler_unpickleExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr".toTermName)
def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType".toTermName)

lazy val EqType = ctx.requiredClassRef("scala.Eq")
def EqClass(implicit ctx: Context) = EqType.symbol.asClass
Expand Down Expand Up @@ -1186,5 +1186,4 @@ class Definitions {
_isInitialized = true
}
}

}
64 changes: 35 additions & 29 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import config.Config
import util.common._
Copy link
Contributor

Choose a reason for hiding this comment

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

This commit LGTM

import collection.mutable.ListBuffer
import Decorators.SymbolIteratorDecorator
import SymDenotations.LazyType

/** Denotations represent the meaning of symbols and named types.
* The following diagram shows how the principal types of denotations
Expand Down Expand Up @@ -171,12 +172,19 @@ object Denotations {
*
* @param symbol The referencing symbol, or NoSymbol is none exists
*/
abstract class Denotation(val symbol: Symbol) extends PreDenotation with printing.Showable {

abstract class Denotation(val symbol: Symbol, protected var myInfo: Type) extends PreDenotation with printing.Showable {
type AsSeenFromResult <: Denotation

/** The type info of the denotation, exists only for non-overloaded denotations */
def info(implicit ctx: Context): Type
/** The type info.
* The info is an instance of TypeType iff this is a type denotation
* Uncompleted denotations set myInfo to a LazyType.
*/
final def info(implicit ctx: Context): Type = {
def completeInfo = { // Written this way so that `info` is small enough to be inlined
this.asInstanceOf[SymDenotation].completeFrom(myInfo.asInstanceOf[LazyType]); info
}
if (myInfo.isInstanceOf[LazyType]) completeInfo else myInfo
}

/** The type info, or, if this is a SymDenotation where the symbol
* is not yet completed, the completer
Expand Down Expand Up @@ -287,13 +295,14 @@ object Denotations {
denot.symbol
}

def requiredMethod(name: PreName)(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(_ is Method).asTerm
def requiredMethodRef(name: PreName)(implicit ctx: Context): TermRef =
def requiredMethod(name: TermName)(implicit ctx: Context): TermSymbol =
info.member(name).requiredSymbol(_ is Method).asTerm

def requiredMethodRef(name: TermName)(implicit ctx: Context): TermRef =
requiredMethod(name).termRef

def requiredMethod(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermSymbol = {
info.member(name.toTermName).requiredSymbol { x =>
def requiredMethod(name: TermName, argTypes: List[Type])(implicit ctx: Context): TermSymbol = {
info.member(name).requiredSymbol { x =>
(x is Method) && {
x.info.paramInfoss match {
case paramInfos :: Nil => paramInfos.corresponds(argTypes)(_ =:= _)
Expand All @@ -302,19 +311,18 @@ object Denotations {
}
}.asTerm
}
def requiredMethodRef(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermRef =

def requiredMethodRef(name: TermName, argTypes: List[Type])(implicit ctx: Context): TermRef =
requiredMethod(name, argTypes).termRef

def requiredValue(name: PreName)(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(_.info.isParameterless).asTerm
def requiredValueRef(name: PreName)(implicit ctx: Context): TermRef =
requiredValue(name).termRef
def requiredValue(name: TermName)(implicit ctx: Context): TermSymbol =
info.member(name).requiredSymbol(_.info.isParameterless).asTerm

def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
def requiredClass(name: TypeName)(implicit ctx: Context): ClassSymbol =
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass

def requiredType(name: PreName)(implicit ctx: Context): TypeSymbol =
info.member(name.toTypeName).requiredSymbol(_.isType).asType
def requiredType(name: TypeName)(implicit ctx: Context): TypeSymbol =
info.member(name).requiredSymbol(_.isType).asType

/** The alternative of this denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
Expand Down Expand Up @@ -646,7 +654,7 @@ object Denotations {
}

/** A non-overloaded denotation */
abstract class SingleDenotation(symbol: Symbol) extends Denotation(symbol) {
abstract class SingleDenotation(symbol: Symbol, initInfo: Type) extends Denotation(symbol, initInfo) {
protected def newLikeThis(symbol: Symbol, info: Type): SingleDenotation

final def name(implicit ctx: Context): Name = symbol.name
Expand Down Expand Up @@ -1076,34 +1084,32 @@ object Denotations {
}
}

abstract class NonSymSingleDenotation(symbol: Symbol) extends SingleDenotation(symbol) {
def infoOrCompleter: Type
def info(implicit ctx: Context) = infoOrCompleter
abstract class NonSymSingleDenotation(symbol: Symbol, initInfo: Type) extends SingleDenotation(symbol, initInfo) {
def infoOrCompleter: Type = initInfo
def isType = infoOrCompleter.isInstanceOf[TypeType]
}

class UniqueRefDenotation(
symbol: Symbol,
val infoOrCompleter: Type,
initValidFor: Period) extends NonSymSingleDenotation(symbol) {
initInfo: Type,
initValidFor: Period) extends NonSymSingleDenotation(symbol, initInfo) {
validFor = initValidFor
override def hasUniqueSym: Boolean = true
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new UniqueRefDenotation(s, i, validFor)
}

class JointRefDenotation(
symbol: Symbol,
val infoOrCompleter: Type,
initValidFor: Period) extends NonSymSingleDenotation(symbol) {
initInfo: Type,
initValidFor: Period) extends NonSymSingleDenotation(symbol, initInfo) {
validFor = initValidFor
override def hasUniqueSym = false
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = new JointRefDenotation(s, i, validFor)
}

class ErrorDenotation(implicit ctx: Context) extends NonSymSingleDenotation(NoSymbol) {
class ErrorDenotation(implicit ctx: Context) extends NonSymSingleDenotation(NoSymbol, NoType) {
override def exists = false
override def hasUniqueSym = false
def infoOrCompleter = NoType
validFor = Period.allInRun(ctx.runId)
protected def newLikeThis(s: Symbol, i: Type): SingleDenotation = this
}
Expand Down Expand Up @@ -1185,9 +1191,9 @@ object Denotations {

/** An overloaded denotation consisting of the alternatives of both given denotations.
*/
case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation(NoSymbol) with MultiPreDenotation {
case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation(NoSymbol, NoType) with MultiPreDenotation {
final def infoOrCompleter = multiHasNot("info")
final def info(implicit ctx: Context) = infoOrCompleter
// final def info(implicit ctx: Context) = infoOrCompleter
final def validFor = denot1.validFor & denot2.validFor
final def isType = false
final def hasUniqueSym = false
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.security.MessageDigest
import scala.annotation.switch
import scala.io.Codec
import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._
import Decorators.PreNamedString
import Decorators.StringDecorator
import util.{Chars, NameTransformer}
import Chars.isOperatorPart
import Definitions._
Expand Down Expand Up @@ -58,7 +58,7 @@ object NameOps {
case _ => false
}

def likeSpaced(n: PreName): N =
def likeSpaced(n: Name): N =
(if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N]

def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR
Expand Down
10 changes: 1 addition & 9 deletions compiler/src/dotty/tools/dotc/core/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ import java.util.HashMap
object Names {
import NameKinds._

/** A common class for things that can be turned into names.
* Instances are both names and strings, the latter via a decorator.
*/
trait PreName extends Any with Showable {
def toTypeName: TypeName
def toTermName: TermName
}

implicit def eqName: Eq[Name, Name] = Eq

/** A common superclass of Name and Symbol. After bootstrap, this should be
Expand All @@ -39,7 +31,7 @@ object Names {
* in a name table. A derived term name adds a tag, and possibly a number
* or a further simple name to some other name.
*/
abstract class Name extends Designator with PreName {
abstract class Name extends Designator with Showable {

/** A type for names of the same kind as this name */
type ThisName <: Name
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import scala.annotation.switch
import Names._
import Symbols._
import Contexts._
import Decorators.PreNamedString
import Decorators.StringDecorator
import util.NameTransformer
import scala.collection.breakOut

Expand Down Expand Up @@ -393,7 +393,7 @@ object StdNames {
val ClassManifestFactory: N = "ClassManifestFactory"
val classOf: N = "classOf"
val clone_ : N = "clone"
// val conforms : N = "conforms" // Dotty deviation: no special treatment of conforms, so the occurrence of the name here would cause to unintended implicit shadowing. Should find a less common name for it in Predef.
val conforms_ : N = "$conforms"
val copy: N = "copy"
val currentMirror: N = "currentMirror"
val create: N = "create"
Expand Down
Loading