-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #2456: eliminate syntactic references to Java packages #2528
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
Conversation
That looks exactly like #2468 |
@@ -0,0 +1,24 @@ | |||
package dotty.tools.dotc.transform |
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.
@DarkDimius a couple of follow-up questions:
-
Adding this feels a bit hacky, because it's potentially masking bugs in subsequent phases if those subsequent phases accidentally pass a Java package to the backend.
Or, to rephrase the above: if a phase passes a java package as a value to the backend,
1.1 Is it their responsibility to not do that?
1.2 Or are we now saying that the compiler guarantees that no such references exist, past ElimJavaPackages? -
Should we add some code that checks whether the invariant holds for all phases going forward? If so, does that code go in TreeChecker?
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.
Adding this feels a bit hacky, because it's potentially masking bugs in subsequent phases if those subsequent phases accidentally pass a Java package to the backend.
Most of the phases in Dotty perform some transformation that adds a new invariant that should not be broken by future phases.
1.1 Is it their responsibility to not do that?
1.2 Or are we now saying that the compiler guarantees that no such references exist, past ElimJavaPackages?
It is their responsibility not to do that, as long as ElimJavaPackages is able to blame them :-)
This is why you should add a checkPostcondition method that will check that package references did not re-appear. TreeChecker will call this method during Ycheck.
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.
@DarkDimius friendly ping
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.
It's funny how now with the new github system we can have comments with wrong review dates. See reply in a comment above.
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.
Sorry, forgot to press the "submit" button.
@@ -0,0 +1,24 @@ | |||
package dotty.tools.dotc.transform |
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.
Adding this feels a bit hacky, because it's potentially masking bugs in subsequent phases if those subsequent phases accidentally pass a Java package to the backend.
Most of the phases in Dotty perform some transformation that adds a new invariant that should not be broken by future phases.
1.1 Is it their responsibility to not do that?
1.2 Or are we now saying that the compiler guarantees that no such references exist, past ElimJavaPackages?
It is their responsibility not to do that, as long as ElimJavaPackages is able to blame them :-)
This is why you should add a checkPostcondition method that will check that package references did not re-appear. TreeChecker will call this method during Ycheck.
override def phaseName: String = "elimJavaPackages" | ||
|
||
override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { | ||
tree.denot.info match { |
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.
tree.tpe
|
||
override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { | ||
tree.denot.info match { | ||
case myTpe@TypeRef(prefix, _) if prefix.termSymbol.flags.is(allOf(Package, JavaDefined)) => |
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.
the overload that takes FlagConjunction
does not use a value-class and is less efficient than the one that takes a FlagSet. It's better to do two separate tests here.
} | ||
} | ||
|
||
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { |
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.
@DarkDimius I added the postcondition, but is there a way to run all the tests with -Ycheck enabled? (Is that done by default in the CI?)
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.
Both CI and local test suite runs by default with Ychecks enabled.
https://github.com/lampepfl/dotty/blob/master/compiler/test/dotc/tests.scala#L71
* Eliminates syntactic references to Java packages, so that there's no chance | ||
* they accidentally end up in the backend. | ||
*/ | ||
class ElimJavaPackages extends MiniPhaseTransform { |
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.
Should I be extending DenotTransformer here? I'd think InfoTransformer doesn't apply, because the type of the tree is unchanged. But maybe IdentityDenotTransformer then?
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.
InfoTransformer doesn't apply, because the type of the tree
DenotTransformer are required when you change "type of a name", i.e. Denotation.
E.g. if a method/field used to return one type, but now returns another. Or if it takes more agruments. Or if a field became a method. Or if new methods\fields\types\classes are introduced.
You don't need to extend DenotTransformer here if are rebuilding trees that won't affect typing of "names". This phase doesn't.
/** | ||
* Is the given tree a syntactic reference to a Java package? | ||
*/ | ||
private def isJavaPackage(tree: Tree)(implicit ctx: Context): 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.
If you do private def isJavaPackage(tree: Select)...
you will not need the first match
.
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.
You should do it in checkPostCondition
where performance is not really needed.
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.
Done. PTAL.
After typechecking, replace TypeRefs trees of the form Select(p, _) : tpe@TypeRef where p refers to a Java package, by Ident(tpe)
|
||
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = { | ||
if (isJavaPackage(tree)) { | ||
assert(tree.tpe.isInstanceOf[TypeRef], s"Expected tree with type TypeRef, but got ${tree.tpe.show}") |
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.
How performance-sensitive is the miniphase code? Should I get rid of the assertion (and the asInstanceOf call below) in favour of some code duplication?
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.
Selects are one the the most common nodes, so transformSelects should be fast:
#510
isInstanceOf & asInstanceOf checks are very fast on HotSpot, the slower part is allocation of a lambda that is the second argument of assert.
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.
Ok, so should I get rid of the assert, or are we good to go here?
No description provided.