Skip to content

Add transparent methods #4622

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

Merged
merged 7 commits into from
Jun 7, 2018
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jun 5, 2018

0th step, building on #4620: Add transparent methods.

Copy link
Member

@dottybot dottybot left a comment

Choose a reason for hiding this comment

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

Hello, and thank you for opening this PR! 🎉

All contributors have signed the CLA, thank you! ❤️

Commit Messages

We want to keep history, but for that to actually be useful we have
some rules on how to format our commit messages (relevant xkcd).

Please stick to these guidelines for commit messages:

  1. Separate subject from body with a blank line
  2. When fixing an issue, start your commit message with Fix #<ISSUE-NBR>:
  3. Limit the subject line to 72 characters
  4. Capitalize the subject line
  5. Do not end the subject line with a period
  6. Use the imperative mood in the subject line ("Add" instead of "Added")
  7. Wrap the body at 80 characters
  8. Use the body to explain what and why vs. how

adapted from https://chris.beams.io/posts/git-commit

Have an awesome day! ☀️

@odersky
Copy link
Contributor Author

odersky commented Jun 5, 2018

@gsps I think this is the right basis to build on for step 1. Can you review this with the aim to merge early and then we add the TypeOf abstractions on top?

@gsps
Copy link
Contributor

gsps commented Jun 5, 2018

Looking through this PR I noticed lots of unrelated commits and finally saw that there's another PR that includes the prefix up to "Addressing reviewer comments". I guess I'll only do my review from that point on.

@odersky
Copy link
Contributor Author

odersky commented Jun 5, 2018

@gsps Yes, everything after #4620.

@@ -363,7 +363,10 @@ object Flags {
/** Symbol is a Java default method */
final val DefaultMethod = termFlag(38, "<defaultmethod>")

/** Symbol is a Java enum */
/** Labelled with `transparent` modifier */
final val Transparent = termFlag(39, "transparent")
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not make transparent a commonFlag, if we use it that way below anyways?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since there are no transparent types, it should not apply to them.

@@ -779,7 +779,13 @@ object SymDenotations {

def isSkolem: Boolean = name == nme.SKOLEM

def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor)
def isInlinedMethod(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.

I think the method's and the flag's name should match (so probably isInlineMethod, i.e. minus the d).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was thinking if we keep something like inline as a modifier we should rename it to inlined instead. Then we don't have a clash with the @inline annotation, and it's a bit cleaner. transparent and inlined are both adjectives, whereas it's a stretch to call inline an adjective.

@@ -90,6 +90,11 @@ object Inliner {
}
}

def isLocal(sym: Symbol, inlineMethod: Symbol)(implicit ctx: Context) =
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem to be used anywhere. (The following commit does use it.)

@@ -1113,7 +1113,7 @@ class Namer { typer: Typer =>

// println(s"final inherited for $sym: ${inherited.toString}") !!!
// println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}")
def isInline = sym.is(FinalOrInline, butNot = Method | Mutable)
def isInline = sym.is(FinalOrInlineOrTransparent, butNot = Method | Mutable)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if it's worth adding Transparent to the exception here, since the handling of return types of transparent methods in widenRhs will have to be more different anyways (it should be allowed to infer a TermRef, for instance; think transparent def unapply(x: Foo) = x)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that was only done as a temporary measure because I could not decide yet whether Java final constants should be called inline(d) or transparent. Probably transparent, but for now it's inline.

@@ -1128,7 +1128,8 @@ class Namer { typer: Typer =>
// it would be erased to BoxedUnit.
def dealiasIfUnit(tp: Type) = if (tp.isRef(defn.UnitClass)) defn.UnitType else tp

val rhsCtx = ctx.addMode(Mode.InferringReturnType)
var rhsCtx = ctx.addMode(Mode.InferringReturnType)
if (sym.isTransparentMethod) rhsCtx = rhsCtx.addMode(Mode.TransparentBody)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure TransparentBody should be a Mode. If it is, shouldn't it also be set in the other tree traversing helpers besides typer, i.e., TreeAccumulator and MegaPhase#transformTree? All of those have localContext helpers (in case of typer its in NamerContextOps, the other two are local defs) which currently set the owner, among other things.

As an alternative, we could deduce whether we are in a transparent context by walking the context's owner chain and checking for Transparent. Ideally that query would be cached by the context (and its descendants).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Since it's a single bit we cache, it could still go into the Mode structure (context fields are a precious resource). But it could be maintained fully automatically. I'll do that change.

@@ -104,14 +94,14 @@ object Inliner {
* to have the inlined method as owner.
*/
def registerInlineInfo(
sym: SymDenotation, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
sym.unforcedAnnotation(defn.BodyAnnot) match {
inlined: Symbol, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Docs should be updated. Maybe call it inlineSym, since it's not inlined at this point?

@@ -0,0 +1,31 @@
object Test extends App {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe give this file and its '.check' companion a more descriptive name like transparent.scala or TransparentToNat.scala?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I planned to extend this test with more typelevel operations as we go along.

super.transform(accessorIfNeeded(tree))
}

override def transform(tree: Tree)(implicit ctx: Context): Tree =
Copy link
Contributor

Choose a reason for hiding this comment

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

(I have no useful comment, but I will say that I don't understand Inliner well enough yet to really judge this change.)

@odersky
Copy link
Contributor Author

odersky commented Jun 6, 2018

@gsps Regarding the next step, I was wondering whether TypeOf(tree, underlying) can be modelled as as an annotated type underlying @TypeOf(tree) or AnnotatedType(underyling, tpd.Apply(tpd.ref(defn.ToTypeAnnot), tree)) in internal representation? This would avoid having to add a new case to all typemaps etc.

The downside is that currently annotations on types are forgotten in a large number of cases, which would not be correct in this case. On the other hand, there are a number of other possible annotations that conceptually should behave the same as TypeOf, i.e. they are generally seen as
unknown subtypes of their underlying types. @olhotak worked on mutable/immutable classifiers that would fall into that category. Or units of measure. So maybe it's worthwhile to create a new trait of, say, SubTypeAnnotation which annotation classes can inherit. Types annotated with annotations deriving from SubTypeAnnotation would keep their annotation in most contexts, and they would be treated as subtypes of their underlying type. We'd have to go with a fine comb through all the occurrences of stripAnnotation to make this work.

Note: This would not affect surface syntax, where we'd still keep { tree }.

@OlivierBlanvillain
Copy link
Contributor

@odersky Regarding your last comment, I think it would be more work to change the handling annotated type rather than simply adding a new type. It should maybe be done as a separate generalization step? I feel than TypeOf is going to have a large impact on typer than other potential annotations like mutable/immutable...

@odersky odersky force-pushed the add-transparent-2 branch from 2cd1590 to 101fe52 Compare June 6, 2018 09:14
@odersky
Copy link
Contributor Author

odersky commented Jun 6, 2018

@OlivierBlanvillain I agree it would be easier to get started with a new form of type. But in the end, we will want to refactor to avoid the duplication.

odersky added 7 commits June 6, 2018 14:13
Currently we have both inline and transparent. It is expected that we will drop inline
in the future.
 - avoid computing owner of NoSymbol
This was the enclosing class instead of the method containing the annotation.
Fixing this is surprisingly hard.
 - premature optimization, we can just inspect the owner chain,
 - if we need it, it should be an automatically updated cache
@odersky odersky force-pushed the add-transparent-2 branch from 2bae1f6 to b359c7d Compare June 6, 2018 12:14
@odersky
Copy link
Contributor Author

odersky commented Jun 6, 2018

#4620 is in now. Rebased on top of current master.

@odersky
Copy link
Contributor Author

odersky commented Jun 6, 2018

I believe if we can do it, it would be ultimately better to base this on AnnotatedType. The reason is that any work we do along that path benefits the whole. The potential downside is that it might detract us from the immediate purpose. I'll take a look how hard it would be to change annotations.

Copy link
Contributor

@OlivierBlanvillain OlivierBlanvillain left a comment

Choose a reason for hiding this comment

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

LGTM!

@odersky odersky mentioned this pull request Jun 6, 2018
@odersky odersky merged commit c3469da into scala:master Jun 7, 2018
@allanrenucci allanrenucci deleted the add-transparent-2 branch June 7, 2018 08:10
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