Skip to content

support merging companion objects in expanded trees #2057

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 2 commits into from
Mar 9, 2017

Conversation

liufengyun
Copy link
Contributor

@liufengyun liufengyun commented Mar 7, 2017

Support merging companion objects in expanded trees

Previous implementation is problematic when there are multiple transforms before typer:

  1. There might be objects needing merging that only exist in the expanded trees, which cannot be handled by the previous algorithm.

  2. There may be companion object and class defined only in the expanded trees, the previous algorithm doesn't create links for them.

This PR simplifies the companion object merging logic and fixes the problems above.

In fact, this PR supports multiple pre-typer transform during expansion. The protocol is that the expansion of a statement is either a flattened thicket or a non-thicket tree.

@liufengyun liufengyun changed the title support merging companion objects in expanded trees [WIP] support merging companion objects in expanded trees Mar 7, 2017
Previous implementation is problematic when there are multiple
transforms before typer:

1. There might be objects needing merging that only exist in the
expanded trees, which cannot be handled by the previous algorithm.

2. There may be companion object and class defined only in the
expanded trees, the previous algorithm doesn't create links for them.

This PR simplifies the companion object merging logic and
fixes the problems above.

In fact, this PR supports multiple pre-typer transform during expansion.
The protocol is that the expansion of a MemberDef is either a flattened
thicket or a non-thicket tree.
@liufengyun liufengyun changed the title [WIP] support merging companion objects in expanded trees support merging companion objects in expanded trees Mar 7, 2017
@liufengyun liufengyun requested a review from odersky March 7, 2017 15:01
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

Otherwise LGTM

mdef.putAttachment(ExpandedTree, Thicket(vdef :: mcls1 :: rest))
moduleDef(typName) = mcls1
cdef.putAttachment(ExpandedTree, Thicket(cls :: crest))
def valid(mdef: MemberDef): Boolean = !mdef.mods.is(Package) && mdef.mods.is(Module)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shorter and mode efficient:

mdef.mods.is(Module, butNot = Package)

case Thicket(trees) => // companion object always expands to thickets
trees.map {
case mcls @ TypeDef(name, impl: Template) if valid(mcls) =>
if (moduleClsDef.contains(name)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd use a get instead of contains + apply:

moduleClsDef.get(name) match {
  case Some((stat1, mcls1 @ TypeDef(_, impl1: Template)) => ...
  case None => ...

if (moduleClsDef.contains(name)) {
val (stat1, mcls1 @ TypeDef(_, impl1: Template)) = moduleClsDef(name)
if (mcls.mods.is(Synthetic) && !mcls1.mods.is(Synthetic)) { // merge synthetic into user-defined module
removeInExpanded(stat, mcls)
Copy link
Contributor

Choose a reason for hiding this comment

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

Factor the two preceding and the next two lines into a separate local method mergeIfSynthetic(synthCls, userCls. Then the whole 12 line if-else can be expressed as

mergeIfSynthetic(mcls, mcls1)
mergeIfSynthetic(mcls1, mcls)

moduleClsDef(name) = (stat, mcls2)
}
else {
// redefinition of objects or case classes, handled elsewhere
Copy link
Contributor

Choose a reason for hiding this comment

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

You mean, we have a double definition? (Just asking for clarification)

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, I mean double definition. I'll refine the comment for clarity.

case vdef @ ValDef(name, _, _) if valid(vdef) =>
if (moduleValDef.contains(name)) {
val (stat1, vdef1) = moduleValDef(name)
if (vdef.mods.is(Synthetic) && !vdef1.mods.is(Synthetic)) // merge synthetic into user-defined module
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar remarks as for module defs apply here. Probably better to factor out in a method mergeIfSynthetic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The comments are addressed in the latest commit.

For the last one, I think it's probably good to keep it as it is, as the processing is not symmetric as the case above, and the code is simple and short. Refactoring into a method seems to make readability worse.

@odersky odersky merged commit 391aaa1 into scala:master Mar 9, 2017
@allanrenucci allanrenucci deleted the merge-companion branch December 14, 2017 19:23
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.

2 participants