Skip to content

Conversation

abeln
Copy link
Contributor

@abeln abeln commented May 24, 2017

No description provided.

@smarter
Copy link
Member

smarter commented May 24, 2017

java.util.NoSuchElementException: key not found: class Int

That looks exactly like #2468

@@ -0,0 +1,24 @@
package dotty.tools.dotc.transform
Copy link
Contributor Author

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:

  1. 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?

  2. Should we add some code that checks whether the invariant holds for all phases going forward? If so, does that code go in TreeChecker?

Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DarkDimius friendly ping

Copy link
Contributor

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.

Copy link
Contributor

@DarkDimius DarkDimius left a 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
Copy link
Contributor

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 {
Copy link
Contributor

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)) =>
Copy link
Contributor

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 = {
Copy link
Contributor Author

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?)

Copy link
Contributor

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

@abeln abeln changed the title [WIP] Fix #2456: eliminate syntactic references to Java packages Fix #2456: eliminate syntactic references to Java packages May 31, 2017
* Eliminates syntactic references to Java packages, so that there's no chance
* they accidentally end up in the backend.
*/
class ElimJavaPackages extends MiniPhaseTransform {
Copy link
Contributor Author

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?

Copy link
Contributor

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 = {
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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}")
Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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?

@DarkDimius DarkDimius merged commit 025cfa5 into scala:master Jun 2, 2017
@abeln abeln deleted the java-packages branch June 7, 2017 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants