-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix #2566: Ycheck that New
node is always enclosed in a Select
#2639
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
@@ -122,6 +122,10 @@ class TreeChecker extends Phase with SymTransformer { | |||
val squahsedPhase = ctx.squashed(prevPhase) | |||
ctx.echo(s"checking ${ctx.compilationUnit} after phase ${squahsedPhase}") | |||
|
|||
if (ctx.isAfterTyper) { |
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 is this the right place to invoke the new check? Do I need to pass a fresh context?
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.
Yes, this is the right place.
TreeChecker is always after typer, no need for the if.
@DarkDimius The regular tests pass, but the legacy and bootstrap suites fail with what looks like unrelated (to this PR) errors. Are those tests flaky? |
|
||
detect(NotFound(None), tree) match { | ||
case Found(Some(parent), child) => | ||
assert(assertion = false, i"`New` node must be wrapped in a `Select`:\n parent = ${parent.show}\n child = ${child.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.
I would put the assertion inside of the TreeAccumulator .apply
to have it fail with the accumulator stacktrace. This would allow us to attache the debugger at the moment of the assertion failure and navigate back to the trees that contained this malformed New
.
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.
That's a good idea. Will do.
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 this you might not even need the parameter of Found
and could make it a case object
// Current state of the search. We return as soon as we see the first improperly wrapped `New`. | ||
sealed trait State | ||
case class NotFound(parent: Option[tpd.Tree]) extends State | ||
case class Found(parent: Option[tpd.Tree], child: tpd.New) extends State |
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.
Why not just partent: tpd.Tree
?
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.
When I invoke the accumulator on the root of the tree, there's no parent node. But I guess I could also pass an empty Thicket?
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.
But on the root you use NotFound
. My comment is only for Found
.
For NotFound
you could maybe simplify it using some trick like the Ticket
or defining a case object Root extends State
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.
Well, when we construct the Found object,we use the optional parent from the NotFound, so the optionality trickles through the hierarchy. We can get rid of it everywhere with the Thicket.
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.
Applied your suggestion and the code is now simpler. Thanks.
@DarkDimius @nicolasstucki e.g. this test https://github.com/lampepfl/dotty/blob/master/tests/pos/functions1.scala
So should we relax the invariant? Is it ok for Annotated nodes to wrap New? (if so, which constructor gets chosen?) Xprint:tailrec shows
|
Annotations aren't systematically transformed in the pipeline and they also can contain some-what invalid trees. I think you shouldn't recurse into annotations at all. |
Tested: Verified that the test case in scala#2564 triggers the assert. Verified that the check doesn't run when we ycheck a phase before frontend.
@DarkDimius We no longer check inside annotations. PTAL. |
Friendly ping. |
Looks good to me! |
Tested:
Verified that the test case in #2564
triggers the assert.
Verified that the check doesn't run when we ycheck a phase before frontend.