Skip to content
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

SI-6734 Synthesize companion near case class #5486

Merged
merged 2 commits into from Nov 10, 2016

Conversation

som-snytt
Copy link
Contributor

@som-snytt som-snytt commented Oct 27, 2016

Tweak the "should I synthesize now" test for
case modules, so that the tree is inserted in
the same tree as the case class.

This for the case where there are multiple package p { } trees, which happens implicitly when there is a package object p { }.

No attempt made in this quick fix to improve locality-based synthesis.

@scala-jenkins scala-jenkins added this to the 2.12.1 milestone Oct 27, 2016
Tweak the "should I synthesize now" test for
case modules, so that the tree is inserted in
the same tree as the case class.
sym.moduleClass.attachments.get[ClassForCaseCompanionAttachment] match {
case Some(att) =>
val cdef = att.caseClass
stats.exists {
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this introduce quadratic complexity in the size of the package? This method is called for every member in scope, and the test searches linearly to find a ClassDef tree.

I'm also not sure if assuming source code is going to work always. What if the case class in scope comes from binaries?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only invoked for synthetic modules of case classes with attachment introduced by Namers.

Copy link
Contributor

Choose a reason for hiding this comment

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

This code still looks strange to me. The attachment is a ClassDef, but the code does a linear search for a(nother?) ClassDef with the same symbol. Isn't it the same ClassDef? If not, why do they have the same symbol? In either case it might be good to document it.

This may be perfectly ok, but it's still not clear to me why it only treats symbols that are currently compiled (that have trees around).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently, the moduleclass has attachment pointing to a classdef; but meanwhile the in-flight classdef is something transformed, so eq fails. The test is to say, add synthetic companion only if the associated classdef is in these statements, too. (The big loop also tries to match associated synths in an ad-hoc way.)

I'll try a bigger clean-up, where the classdef bears an attachment (to mean it has an associated synthetic; similarly for other defs). Then the big loop should just traverse looking for things with synths to add; and then at the end, add whatever remaining synths belong here.

Maybe the attachment has a Tree => Boolean to match something invariant that says, yes, this tree is associated with me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would be useful for a unit with a huge number of case classes, since right now each tree is checked against all (remaining) synths. The check itself must always do work, as noted.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for explaining, I start to understand a bit more what's happening. If I understand correctly, this PR tightens the conditions under which such synthetics are generated, presumably making it "deterministic" -- the same place where the ClassDef is. But where were they added before this PR? Maybe there's an equivalent condition that doesn't require iterating?

I agree the code won't run for all stats in a package, but the typer is generally "hot", and even if this doesn't seem much, it's still going to be doing more work than before, work that's not a constant but a function of code size.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See the PR comment and test case -- they'd be added to the package tree containing the package object if that was first in source-text-order.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I stared at that test case long and hard. It's impenetrable. Thanks again for explaining. I'd really add some explanation to the test

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 just using the test case the guy submitted on the ticket. I agree that many test cases make you wonder what's being tested and require archaeology. I'll add a comment benefiting from hindsight.


//single file badimp.scala
// adding package object gives not found: type SortedMap
package object badimp
Copy link
Contributor

@dragos dragos Oct 29, 2016

Choose a reason for hiding this comment

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

How about:

// this package object used to contain the synthetic companion object of `Nodal` and fail because the 
// necessary import is not in this scope

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 funny thing is that it's not the package object, but the package introduced by desugaring that received the synthetic.

dragos
dragos previously requested changes Oct 29, 2016

package badimp {

// move before package object works
Copy link
Contributor

@dragos dragos Oct 29, 2016

Choose a reason for hiding this comment

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

This comment is more confusing than clarifying. This test case is the way it is now, and the ticket you link to gives the background and additional details.


// adding target object restores sanity
// but adding it before the import does not
//object Nodal
Copy link
Contributor

@dragos dragos Oct 29, 2016

Choose a reason for hiding this comment

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

I would remove this part as well since the ticket describes all these variations.

@retronym
Copy link
Member

LGTM

@retronym retronym dismissed dragos’s stale review November 10, 2016 06:43

Changes addressed in 4959e9f

@retronym retronym merged commit e0a0d3d into scala:2.12.x Nov 10, 2016
@dragos
Copy link
Contributor

dragos commented Nov 10, 2016

Sorry for missing this one, thanks for closing it @retronym

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants