Skip to content

Commit

Permalink
unroll.Unroll -> scala.annotation.unroll
Browse files Browse the repository at this point in the history
  • Loading branch information
lihaoyi committed Feb 12, 2024
1 parent c0c771e commit 050c894
Show file tree
Hide file tree
Showing 28 changed files with 102 additions and 58 deletions.
54 changes: 27 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# @Unroll
# @unroll


Unroll provides an experimental `@Unroll` annotation that can be applied to methods, classes,
and constructors. `@Unroll` generates unrolled/telescoping versions of the method, starting
Unroll provides an experimental `@unroll` annotation that can be applied to methods, classes,
and constructors. `@unroll` generates unrolled/telescoping versions of the method, starting
from the annotated parameter, which are simple forwarders to the primary method or
constructor implementation. This allows you to maintain binary compatibility when adding
a new default parameter, without the boilerplate of manually defining forwarder methods.

See the following PRs that demonstrate the usage of `@Unroll` and the binary-compatibility
See the following PRs that demonstrate the usage of `@unroll` and the binary-compatibility
boilerplate that can be saved:

- https://github.com/com-lihaoyi/mainargs/pull/113/files
Expand All @@ -26,9 +26,9 @@ it has a default value, all your users would have to recompile all their code. A
*their* users would need to re-compile all their code, transitively. And so library
maintainers would suffer so their users could have a smooth upgrading experience.

With `@Unroll`, none of this is a problem anymore. You can add new parameters
With `@unroll`, none of this is a problem anymore. You can add new parameters
where-ever you like: method `def`s, `class`es, `case class`es, etc. As long as the
new parameter has a default value, you can `@Unroll` it to generate the binary-compatibility
new parameter has a default value, you can `@unroll` it to generate the binary-compatibility
stub forwarder method automatically. Happy library maintainers, happy users, everyone is happy!

See this original discussion for more context:
Expand All @@ -40,20 +40,20 @@ See this original discussion for more context:
### Methods

```scala
import unroll.Unroll
import scala.annotation.unroll

object Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0) = s + n + b + l
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l
}
```

Unrolls to:

```scala
import unroll.Unroll
import scala.annotation.unroll

object Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0) = s + n + b + l
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l

def foo(s: String, n: Int, b: Boolean) = foo(s, n, b, 0)
def foo(s: String, n: Int) = foo(s, n, true, 0)
Expand All @@ -62,19 +62,19 @@ object Unrolled{
### Classes

```scala
import unroll.Unroll
import scala.annotation.unroll

class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0){
class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0){
def foo = s + n + b + l
}
```

Unrolls to:

```scala
import unroll.Unroll
import scala.annotation.unroll

class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0){
class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0){
def foo = s + n + b + l

def this(s: String, n: Int, b: Boolean) = this(s, n, b, 0)
Expand All @@ -85,12 +85,12 @@ class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0){
### Constructors

```scala
import unroll.Unroll
import scala.annotation.unroll

class Unrolled() {
var foo = ""

def this(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0) = {
def this(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = {
this()
foo = s + n + b + l
}
Expand All @@ -100,12 +100,12 @@ class Unrolled() {
Unrolls to:

```scala
import unroll.Unroll
import scala.annotation.unroll

class Unrolled() {
var foo = ""

def this(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0) = {
def this(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = {
this()
foo = s + n + b + l
}
Expand All @@ -118,19 +118,19 @@ class Unrolled() {
### Case Classes

```scala
import unroll.Unroll
import scala.annotation.unroll

case class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true){
case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){
def foo = s + n + b
}
```

Unrolls to:

```scala
import unroll.Unroll
import scala.annotation.unroll

case class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0L){
case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0L){
def this(s: String, n: Int) = this(s, n, true, 0L)
def this(s: String, n: Int, b: Boolean) = this(s, n, b, 0L)

Expand All @@ -148,10 +148,10 @@ object Unrolled{
### Abstract Methods

```scala
import unroll.Unroll
import scala.annotation.unroll

trait Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true): String
def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String
}

object Unrolled extends Unrolled{
Expand All @@ -163,7 +163,7 @@ Unrolls to:

```scala
trait Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true): String
def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String
def foo(s: String, n: Int = 1): String = foo(s, n, true)
}

Expand All @@ -172,9 +172,9 @@ object Unrolled extends Unrolled{
}
```

Note that only the abstract method needs to be `@Unroll`ed, as the generated forwarder
Note that only the abstract method needs to be `@unroll`ed, as the generated forwarder
methods are concrete. The concrete implementation `class` or `object` does not need to
`@Unroll` its implementation method, as it only needs to implement the abstract `@Unroll`ed
`@unroll` its implementation method, as it only needs to implement the abstract `@unroll`ed
method and not the concrete forwarders.

## Limitations
Expand Down
6 changes: 3 additions & 3 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,15 @@ trait UnrollModule extends Cross.Module[String]{
}

object jvm extends InnerScalaModule with ComparativePlatformScalaModule{
def unmanagedClasspath = Agg(upstreamTest.jvm.test.jar(), upstream.jvm.jar())
def unmanagedClasspath = Agg(upstreamTest.jvm.test.compile().classes, upstream.jvm.compile().classes)
}

object js extends InnerScalaJsModule with ComparativePlatformScalaModule{
def unmanagedClasspath = Agg(upstreamTest.js.test.jar(), upstream.js.jar())
def unmanagedClasspath = Agg(upstreamTest.js.test.compile().classes, upstream.js.compile().classes)
}

object native extends InnerScalaNativeModule with ComparativePlatformScalaModule{
def unmanagedClasspath = Agg(upstreamTest.native.test.jar(), upstream.native.jar())
def unmanagedClasspath = Agg(upstreamTest.native.test.compile().classes, upstream.native.compile().classes)
}
}

Expand Down
4 changes: 2 additions & 2 deletions unroll/annotation/src/Unroll.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package unroll
package scala.annotation

class Unroll extends scala.annotation.StaticAnnotation
class unroll extends scala.annotation.StaticAnnotation
2 changes: 1 addition & 1 deletion unroll/plugin/src-2/UnrollPhaseScala2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class UnrollPhaseScala2(val global: Global) extends PluginComponent with TypingT
}

def findUnrollAnnotation(params: Seq[Symbol]): Int = {
params.toList.indexWhere(_.annotations.exists(_.tpe =:= typeOf[unroll.Unroll]))
params.toList.indexWhere(_.annotations.exists(_.tpe =:= typeOf[scala.annotation.unroll]))
}

def copyValDef(vd: ValDef) = {
Expand Down
3 changes: 2 additions & 1 deletion unroll/plugin/src-3/UnrollPhaseScala3.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class UnrollPhaseScala3() extends PluginPhase {
val paramCount = annotated.paramSymss(firstValueParamClauseIndex).size
annotated
.paramSymss(firstValueParamClauseIndex)
.indexWhere(_.annotations.exists(_.symbol.fullName.toString == "unroll.Unroll")) match{
.indexWhere(_.annotations.exists(_.symbol.fullName.toString == "scala.annotation.unroll")) match{
case -1 => (None, Nil)
case startParamIndex =>
if (isCaseFromProduct) {
Expand Down Expand Up @@ -202,6 +202,7 @@ class UnrollPhaseScala3() extends PluginPhase {
val (removed0, generatedDefs) = tmpl.body.map(generateSyntheticDefs).unzip
val (None, generatedConstr) = generateSyntheticDefs(tmpl.constr)
val removed = removed0.flatten

super.transformTemplate(
cpy.Template(tmpl)(
tmpl.constr,
Expand Down
2 changes: 1 addition & 1 deletion unroll/tests/abstractClassMethod/v1/src/Unrolled.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ object Unrolled extends Unrolled{

class UnrolledCls extends Unrolled{
def foo(s: String, n: Int = 1) = s + n
}
}
4 changes: 3 additions & 1 deletion unroll/tests/abstractClassMethod/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

abstract class Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true): String
def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String
}

object Unrolled extends Unrolled{
Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/abstractClassMethod/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

abstract class Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0): String
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0): String
}

object Unrolled extends Unrolled{
Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/abstractTraitMethod/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

trait Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true): String
def foo(s: String, n: Int = 1, @unroll b: Boolean = true): String
}

object Unrolled extends Unrolled{
Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/abstractTraitMethod/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

trait Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0): String
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0): String
}

object Unrolled extends Unrolled{
Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/caseclass/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package unroll

case class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true){
import scala.annotation.unroll

case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){
def foo = s + n + b
}
4 changes: 3 additions & 1 deletion unroll/tests/caseclass/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package unroll

case class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0){
import scala.annotation.unroll

case class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0){
def foo = s + n + b + l
}
4 changes: 3 additions & 1 deletion unroll/tests/classMethod/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo(s: String, @Unroll n: Int = 1, b: Boolean = true) = s + n + b
def foo(s: String, @unroll n: Int = 1, b: Boolean = true) = s + n + b
}

4 changes: 3 additions & 1 deletion unroll/tests/classMethod/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo(s: String, @Unroll n: Int = 1, b: Boolean = true, l: Long = 0) = s + n + b + l
def foo(s: String, @unroll n: Int = 1, b: Boolean = true, l: Long = 0) = s + n + b + l
}


Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/curriedMethod/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo(s: String, @Unroll n: Int = 1, b: Boolean = true)(f: String => String) = f(s + n + b)
def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(f: String => String) = f(s + n + b)
}
4 changes: 3 additions & 1 deletion unroll/tests/curriedMethod/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo(s: String, @Unroll n: Int = 1, b: Boolean = true, l: Long = 0)(f: String => String) = f(s + n + b + l)
def foo(s: String, @unroll n: Int = 1, b: Boolean = true, l: Long = 0)(f: String => String) = f(s + n + b + l)
}


Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/genericMethod/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo[T](s: T, @Unroll n: Int = 1, b: Boolean = true) = s.toString + n + b
def foo[T](s: T, @unroll n: Int = 1, b: Boolean = true) = s.toString + n + b
}

4 changes: 3 additions & 1 deletion unroll/tests/genericMethod/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo[T](s: T, @Unroll n: Int = 1, b: Boolean = true, l: Long = 0) = s.toString + n + b + l
def foo[T](s: T, @unroll n: Int = 1, b: Boolean = true, l: Long = 0) = s.toString + n + b + l
}


Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/methodWithImplicit/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo(s: String, @Unroll n: Int = 1, b: Boolean = true)(implicit f: String => String) = f(s + n + b)
def foo(s: String, @unroll n: Int = 1, b: Boolean = true)(implicit f: String => String) = f(s + n + b)
}
4 changes: 3 additions & 1 deletion unroll/tests/methodWithImplicit/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

class Unrolled{
def foo(s: String, @Unroll n: Int = 1, b: Boolean = true, l: Long = 0)(implicit f: String => String) = f(s + n + b + l)
def foo(s: String, @unroll n: Int = 1, b: Boolean = true, l: Long = 0)(implicit f: String => String) = f(s + n + b + l)
}


Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/objectMethod/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

object Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true) = s + n + b
def foo(s: String, n: Int = 1, @unroll b: Boolean = true) = s + n + b
}


Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/objectMethod/v3/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package unroll

import scala.annotation.unroll

object Unrolled{
def foo(s: String, n: Int = 1, @Unroll b: Boolean = true, l: Long = 0) = s + n + b + l
def foo(s: String, n: Int = 1, @unroll b: Boolean = true, l: Long = 0) = s + n + b + l
}


Expand Down
4 changes: 3 additions & 1 deletion unroll/tests/primaryConstructor/v2/src/Unrolled.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package unroll

class Unrolled(s: String, n: Int = 1, @Unroll b: Boolean = true){
import scala.annotation.unroll

class Unrolled(s: String, n: Int = 1, @unroll b: Boolean = true){
def foo = s + n + b
}

0 comments on commit 050c894

Please sign in to comment.