-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Tailrec patrol #7876
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
Tailrec patrol #7876
Conversation
- mark methods that are tailrec as such - make some more methods tailrec by making them final
- mark methods that are tailrec as such - make some more methods tailrec by making them final
- mark methods that are tailrec as such - make some more methods tailrec by making them final
| def loop(cases: List[CaseDef]): Option[CaseDef] = cases match { | ||
| case head :: next :: _ if isDefault(head) => Some(next) // subsumed by the next case, but faster | ||
| case head :: rest if !isGuardedCase(head) || head.guard.tpe =:= ConstantTrue => rest find caseImplies(head) orElse loop(rest) | ||
| case head :: rest if !isGuardedCase(head) || head.guard.tpe =:= ConstantTrue => rest find caseImplies(head) match { case s @ Some(_) => s case None => loop(rest) } |
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.
Hand inlined orElse to enable tail call elimination.
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'm especially impressed by the hardened resistance to semicolon.
| if (p(this)) this else outer.nextEnclosing(p) | ||
| @tailrec | ||
| final def nextEnclosing(p: Context => Boolean): Context = | ||
| if (this eq NoContext) this else if (p(this)) this else outer.nextEnclosing(p) |
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.
Removed override in NoContext to make this self-contained and final.
|
|
||
| def isStrictFP: Boolean = !isDeferred && (hasAnnotation(ScalaStrictFPAttr) || originalOwner.isStrictFP) | ||
| @tailrec | ||
| final def isStrictFP: Boolean = this != NoSymbol && !isDeferred && (hasAnnotation(ScalaStrictFPAttr) || originalOwner.isStrictFP) |
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.
Removed override in NoSymbol to make this self-contained and final.
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.
TIL.
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 meant about the change in receiver.)
| if (this eq NoSymbol) this | ||
| else if (isTopLevel) { | ||
| if (isClass) this else moduleClass | ||
| } else owner.enclosingTopLevelClass |
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.
Removed override in NoSymbol to make this self-contained and final.
| if (this eq NoSymbol) this | ||
| else if (isTopLevel) { | ||
| if (isClass) this else moduleClass.orElse(this) | ||
| } else originalOwner.originalEnclosingTopLevelClassOrDummy |
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.
Removed override in NoSymbol to make this self-contained and final.
ab8fadc to
803f4d0
Compare
803f4d0 to
8aae5b2
Compare
| case s @ Some(str) => s | ||
| case None => lookupVariable(vble, site.owner) | ||
| } | ||
| } |
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.
hand inlined orElse to enable tail call elimination
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.
case s @ Some(_) avoids unused var. Or case s @ Some(str @ _) for baroque effect.
Recursion didn't come up in the discussions about "avoid match on options".
|
| checkHeadAssoc(leftAssoc) | ||
|
|
||
| @tailrec | ||
| def loop(top: Tree): Tree = if (canReduce) { |
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.
Would be nice if -Xlint:loop enabled tailrec warning on anything called loop.
|
The current news in the airline industry focusing on automation and pilot training has me thinking about automation in software production. |
|
The extra vertical space makes me wonder if tailrec should be assumed and for the rare case when I prefer to burn a stack frame, I can add It could be emitted as either warning or error, like |
|
|
||
| /** Reset package class to state at typer (not sure what this is needed for?) | ||
| */ | ||
| @tailrec |
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.
Since we are at it, can we make this private[this]. In fact, can we backport #7127 to 2.12.x?
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.
Someone could volunteer for private this patrol. Also, if they're not going to make private mean private this in scala 3, then -Xlint:private should make recommendations and -Xlint-fix should scalafix them.
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 like to keep this PR focussed on the one cross-cutting improvement.
In general, 2.12.x development should start winding down, so backports need to pay their way
| def format(width: Int, writer: Writer): Unit = { | ||
| type FmtState = (Int, Boolean, Document) | ||
|
|
||
| @tailrec |
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.
BTW, would the pattern case List() two lines below be more efficient if it were case Nil?
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.
or case _: Nil.type. Where is the empty list posse?
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.
TIL UnapplySeqWrapper. Not sure whether to say "mind blown" or "code blown". Maybe this is why blandishments about List() are dangerous.
| // scala/bug#3971 unwrapping to the outermost Apply helps prevent confusion with the | ||
| // error message point. | ||
| def callee = { | ||
| @tailrec |
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.
Can we make the callee into a val or a lazy val? It looks to be called twice in the issueError, which is called from the match below.
|
Responding to my previous comment, Paul tried |
reverts a small part of scala#7876 caught by community build
|
#7936 reverts a small piece of this. it's unfortunate that not all non-final classes that are extension points for scala-parallel-collections have comments marking them as such. |
Uh oh!
There was an error while loading. Please reload this page.