-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Remove PreName add (almost) all other implicit conversions #4077
Conversation
test performance please |
performance test scheduled: 2 job(s) in queue, 0 running. |
Performance test finished successfully: Visit http://dotty-bench.epfl.ch/4077/ to see the changes. Benchmarks is based on merging with master (4be2e76) |
It does not seem to get us any performance gain. And there is quite a bit of duplication, in particular by duplicating InheritedCache. So I am dubious this is actually an improvement. regarding PreName: yes we need relatively few overloads if we drop it, but that is not the end of the story. The problem is that in the future there will be constant hassles that a method exists for Name but not for String or vice versa, which will require either annoying conversions or more ad-hoc overloads. So I would actually be in favor of keeping PreName in as well. |
d78fefb
to
e6b24fb
Compare
@odersky I remove the InheritedCache commit, I agree it was too much duplication. Regarding the PreName commit I updated it to minimize of number of I believe the PreName change is worth doing for readability alone. The change was actually motivated by a real life confusion: @gsps came to my office a few weeks asking "how do I convert a String to PreName?", we spent ~10 minutes pocking around the code trying to figure things out, and finally had to resort to compiling Definitions.scala with |
Looking at the diffs I am still not convinced about |
e6b24fb
to
e429912
Compare
PreName was abusing the implementation of implicit class by using the underlying implicit conversion. For instance, several method form Definitions where expecting an argument of type PreName and called with a String. This commit completely removes the PreName abstraction by explicitly calling .toTermName and .toTypeName as required. This change should be beneficial for both readability (more precise types) and performance. Indeed by "pushing out" all the calls to .toTermName and .toTypeName to the call site, these methods will never use virtual dispatch. To keep the concisness of string literals a couple of methods where duplicated to take String arguments (and forward to the TypeName/TermName version).
e429912
to
a33c99d
Compare
The few additional I newly pushed commits remove all the other implicit conversions, with the exception of these two to use |
FlagConjunction relyvily relied on implicit conversion and was boxing/unboxing on every use. This commit remove the FlagConjunction abstraction, replacing by the following two constructs: - .isBoth(flagA, and = flagB) instead of is(allOf(flagA, flagB)) - .isBoth(Private, and = Local) instead of is(PrivateLocal) & co - .isClassTypeParam / .isJavaTrait / .isParamForwarder as their translation into flags is non trivial.
a33c99d
to
c49d246
Compare
@@ -73,3 +73,4 @@ compiler/after-pickling.txt | |||
*.dotty-ide-version | |||
|
|||
*.decompiled.out | |||
bench/compile.txt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
@@ -134,7 +134,7 @@ object Types { | |||
} | |||
|
|||
/** Is this type different from NoType? */ | |||
def exists: Boolean = true | |||
final def exists: Boolean = !this.eq(NoType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use this.ne(NoType)
, otherwise this commit LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM to me also
@@ -91,7 +91,7 @@ object Trees { | |||
/** The type of the tree. In case of an untyped tree, | |||
* an UnAssignedTypeException is thrown. (Overridden by empty trees) | |||
*/ | |||
def tpe: T @uncheckedVariance = { | |||
final def tpe: T @uncheckedVariance = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
def ensureMethodic(implicit ctx: Context): Type = self match { | ||
case self: MethodicType => self | ||
case _ => if (ctx.erasedTypes) MethodType(Nil, self) else ExprType(self) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
implicit def positionCoord(pos: Position): Coord = | ||
def indexCoord(n: Int): Coord = new Coord(n + 1) | ||
|
||
def pos2coord(pos: Position): Coord = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I am skeptical about merging this.
val undoMsg = Ansi.Color.Blue(Ansi.Str.parse(" ...undoing last action, `Alt -` or `Esc -` to redo")) | ||
val cannotUndoMsg = Ansi.Color.Blue(Ansi.Str.parse(" ...no more actions to undo")) | ||
val redoMsg = Ansi.Color.Blue(Ansi.Str.parse(" ...redoing last action")) | ||
val cannotRedoMsg = Ansi.Color.Blue(Ansi.Str.parse(" ...no more actions to redo")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this one.
@@ -716,7 +716,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma | |||
def isDeprecated: Boolean = false | |||
def isMutable: Boolean = sym is Flags.Mutable | |||
def hasAbstractFlag: Boolean = | |||
(sym is Flags.Abstract) || (sym is Flags.JavaInterface) || (sym is Flags.Trait) | |||
(sym is Flags.Abstract) || (sym is Flags.Trait) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because is(JavaInterface) implies is(Trait): https://github.com/lampepfl/dotty/blob/84bf2fac1aac3f381f2f3f68cc8a7dde538aca95/compiler/src/dotty/tools/dotc/core/Flags.scala#L614
(fs >>> TYPESHIFT) == (flags.bits >>> TYPESHIFT) | ||
} | ||
/** Does this flag set have both of the given flags? */ | ||
def isBoth(flags: FlagSet, and: FlagSet): Boolean = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through all commits except the test commits and added my opinion to each.
@@ -154,9 +154,9 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma | |||
lazy val Predef_classOf: Symbol = defn.ScalaPredefModule.requiredMethod(nme.classOf) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 Iterable
s and Iterator
s 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?
@@ -23,6 +23,7 @@ import config.Config | |||
import util.common._ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
@@ -134,7 +134,7 @@ object Types { | |||
} | |||
|
|||
/** Is this type different from NoType? */ | |||
def exists: Boolean = true | |||
final def exists: Boolean = !this.eq(NoType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM to me also
@@ -685,9 +685,6 @@ object Contexts { | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit LGTM
@@ -260,9 +260,9 @@ object desugar { | |||
@sharable private val synthetic = Modifiers(Synthetic) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this commit should not be merged. There is a reason for rawMods/modsDeco: mods
should not be called on a typed tree because there mods
is typically outdated - one should consult symbol.flags
instead. The setup here makes sure that in code working with typed trees using a
import tpd._
import, mods
is not visible, because modsDeco
is not in scope. So this is a safety measure, not a convenience implicit.
implicit def positionCoord(pos: Position): Coord = | ||
def indexCoord(n: Int): Coord = new Coord(n + 1) | ||
|
||
def pos2coord(pos: Position): Coord = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I am skeptical about merging this.
@@ -601,7 +601,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, | |||
" := " ~ tp.toText(printer) | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not an improvement, lots of nitty gritty boilerplate to add.
@@ -828,8 +828,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma | |||
def freshLocal(cunit: CompilationUnit, name: String, tpe: Type, pos: Position, flags: Flags): Symbol = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SymUtils
is not used much, to this commit looks smallish. But we should use it more often because it gives us a way to add methods without overloading SymDenotation. In that case I think it is essential that it works for Symbol
and SymDenotation
in the same way. So my vote is to leave this as is.
/** A decorator that provides methods for modeling type application */ | ||
class TypeApplications(val self: Type) extends AnyVal { | ||
trait TypeApplications extends Any { | ||
def self: Type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will cause a box for every method call. So don't think this is an improvement.
@@ -47,17 +47,17 @@ object StdNames { | |||
} | |||
|
|||
abstract class DefinedNames[N <: Name] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the current version.
@@ -44,12 +44,14 @@ class ReplTest extends ReplDriver( | |||
def storedOutput(): String = | |||
stripColor(out.asInstanceOf[StoringPrintStream].flushStored()) | |||
|
|||
protected implicit def toParsed(expr: String)(implicit state: State): Parsed = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a better solution is to expose a compile
method in ReplTest
that takes a String
This is followup to #3986 than removes a few virtual calls that the JIT complained about.