-
Notifications
You must be signed in to change notification settings - Fork 1.1k
TailRec phase and tests for it. #117
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
@@ -427,8 +430,42 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { | |||
def mkAnd(tree1: Tree, tree2: Tree)(implicit ctx: Context) = | |||
Apply(Select(tree1, defn.Boolean_and), tree2 :: Nil) | |||
|
|||
def deriveDefDef(ddef: Tree)(applyToRhs: Tree => Tree): DefDef = ddef match { |
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.
The parameter ddef
should clearly be typed as DefDef
, not as 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.
I'd prefer to leave it as is, as otherwise callsite will be responsible for cast, and match will reside in callsite.
This way we can simplify error handling, and have it in single place for a very common case when particular type of tree is expected and modified.
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.
In all the call sites that are in this PR, the caller already has a statically typed version of the tree that it can use to pass to these methods.
For example here:
https://github.com/lampepfl/dotty/pull/117/files#diff-374479fca6aeeda64b2b850c4c611cc5R267
the identifier tree
can be rebound in the pattern so that its static type becomes CaseDef
.
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, as TailRec reconstructs execution flow, it pattern matches on type of the tree, and is able to use it this way. But common usecase in scalac(that I like) is that those methods replace trivial match-and-transform clauses.
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.
those methods replace trivial match-and-transform clauses.
Except they don't: they replace a .asInstanceOf[DefDef]
, not a match. They only work when the type of the argument is exactly the expected type, and fail with an error that is no better than a ClassCastException
if it doesn't. I would like to see a compelling call-site reason to do this before losing type-safety.
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.
AFAICT, the reason that scalac tends to weaken the type requirements to Tree
comes from the fact that typed
/typedPos
and a few others return Tree
, even in cases when you know that you'll get back the same tree.
val t: Tree = typedPos(pos)(DefDef(.....))
deriveDefDef(t)(pos)
Maybe that calls for variants of those methods instead:
def typedPosExact[T <: Tree](t: T): T
val t: DefDef = typedPosExact(pos)(DefDef(.....))
A while back, I thought that TreeCopy
was obviously too liberal in accepting Trees
, but it often makes sense to use that with different trees:
val vd : ValDef = ...
treeCopy.DefDef(vd, .., ...)
In short, it might be worth starting with more restrictive types.
LGTM |
@odersky is there anything except |
|
Helper method that tests weather this particular SymDenotation cant have overrides: eg if it's defined in module class, if it is inner method, if it is method of anonymous class, etc.
This shouldn't require any changes to backend, as all type parameters will be erased in erasure Conflicts: src/dotty/tools/dotc/core/Symbols.scala
@odersky I've removed |
Ported tailcall phase from scalac with such changes: - all transformation is done in the phase itself (previously half of the work was done in backend) - it is now able to run before uncurry - it is now a treeTransform - renamed to tailrec to make it more obvious that this phase transforms only recursive calls. For now this is a single phase which speculatively transforms DefDefs. Speculation can be potentially removed by splitting into 2 phases: one detecting which methods should be transformed second performing transformation. But, as transformation requires as same amount of work as detection, I believe it will be simpler to maintain it as a single phase. Conflicts: tests/pos/typers.scala
TailRec phase and tests for it.
Backport "Do not crash when typing a closure with unknown type, since it can occur for erroneous input" to 3.3 LTS
Ported tailcall phase from scalac with such changes:
(previously half of the work was done in backend)
this phase transforms only recursive calls.
For now this is a single phase which speculatively
transforms DefDefs.
Speculation can be potentially removed by
splitting into 2 phases:
one detecting which methods should be transformed
second performing transformation.
But, as transformation requires as same amount of work
as detection, I believe it will be simpler to maintain
it as a single phase.