Skip to content

Commit 3e0aa1a

Browse files
committed
Introduce @annotation.forceInline annotation
An annotation on methods that is equivalent to Dotty `inline` modifier. The annotation should be used instead of the `inline` modifier in code that needs to cross compile between Scala 2 and Dotty.
1 parent 4821e2b commit 3e0aa1a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+84
-67
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
10521052
def enclosingInlineds(implicit ctx: Context): List[Tree] =
10531053
ctx.property(InlinedCalls).getOrElse(Nil)
10541054

1055-
/** The source file where the symbol of the `@inline` method referred to by `call`
1055+
/** The source file where the symbol of the `inline` method referred to by `call`
10561056
* is defined
10571057
*/
10581058
def sourceFile(call: Tree)(implicit ctx: Context) = {

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,8 @@ class Definitions {
707707
def ImplicitAmbiguousAnnot(implicit ctx: Context) = ImplicitAmbiguousAnnotType.symbol.asClass
708708
lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef("scala.annotation.implicitNotFound")
709709
def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass
710-
lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline")
711-
def InlineAnnot(implicit ctx: Context) = InlineAnnotType.symbol.asClass
710+
lazy val ForceInlineAnnotType = ctx.requiredClassRef("scala.annotation.forceInline")
711+
def ForceInlineAnnot(implicit ctx: Context) = ForceInlineAnnotType.symbol.asClass
712712
lazy val InlineParamAnnotType = ctx.requiredClassRef("scala.annotation.internal.InlineParam")
713713
def InlineParamAnnot(implicit ctx: Context) = InlineParamAnnotType.symbol.asClass
714714
lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("scala.annotation.internal.InvariantBetween")

compiler/src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,6 @@ object Symbols {
803803
override def toString: String = value.asScala.toString()
804804
}
805805

806-
@inline def newMutableSymbolMap[T]: MutableSymbolMap[T] =
806+
@forceInline def newMutableSymbolMap[T]: MutableSymbolMap[T] =
807807
new MutableSymbolMap(new java.util.IdentityHashMap[Symbol, T]())
808808
}

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3935,7 +3935,7 @@ object Types {
39353935
abstract class VariantTraversal {
39363936
protected[core] var variance = 1
39373937

3938-
@inline protected def atVariance[T](v: Int)(op: => T): T = {
3938+
@forceInline protected def atVariance[T](v: Int)(op: => T): T = {
39393939
val saved = variance
39403940
variance = v
39413941
val res = op

compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ object MarkupParsers {
316316
}
317317

318318
/** Some try/catch/finally logic used by xLiteral and xLiteralPattern. */
319-
@inline private def xLiteralCommon(f: () => Tree, ifTruncated: String => Unit): Tree = {
319+
@forceInline private def xLiteralCommon(f: () => Tree, ifTruncated: String => Unit): Tree = {
320320
var output: Tree = null.asInstanceOf[Tree]
321321
try output = f()
322322
catch {

compiler/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ object SyntaxHighlighting {
5151
val newBuf = new StringBuilder
5252
var lastValDefToken = ""
5353

54-
@inline def keywordStart =
54+
@forceInline def keywordStart =
5555
prev == 0 || prev == ' ' || prev == '{' || prev == '(' ||
5656
prev == '\n' || prev == '[' || prev == ',' || prev == ':' ||
5757
prev == '|' || prev == '&'
5858

59-
@inline def numberStart(c: Char) =
59+
@forceInline def numberStart(c: Char) =
6060
c.isDigit && (!prev.isLetter || prev == '.' || prev == ' ' || prev == '(' || prev == '\u0000')
6161

6262
def takeChar(): Char = takeChars(1).head

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1748,7 +1748,7 @@ object messages {
17481748
val kind = "Syntax"
17491749
val msg = hl"no explicit ${"return"} allowed from inline $owner"
17501750
val explanation =
1751-
hl"""Methods marked with ${"@inline"} may not use ${"return"} statements.
1751+
hl"""Methods marked with ${"inline"} modifier may not use ${"return"} statements.
17521752
|Instead, you should rely on the last expression's value being
17531753
|returned from a method.
17541754
|"""

compiler/src/dotty/tools/dotc/reporting/trace.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import core.Mode
99

1010
object trace {
1111

12-
@inline
12+
@forceInline
1313
def onDebug[TD](question: => String)(op: => TD)(implicit ctx: Context): TD =
1414
conditionally(ctx.settings.YdebugTrace.value, question, false)(op)
1515

16-
@inline
16+
@forceInline
1717
def conditionally[TC](cond: Boolean, question: => String, show: Boolean)(op: => TC)(implicit ctx: Context): TC =
1818
if (Config.tracingEnabled) {
1919
def op1 = op
2020
if (cond) apply[TC](question, Printers.default, show)(op1)
2121
else op1
2222
} else op
2323

24-
@inline
24+
@forceInline
2525
def apply[T](question: => String, printer: Printers.Printer, showOp: Any => String)(op: => T)(implicit ctx: Context): T =
2626
if (Config.tracingEnabled) {
2727
def op1 = op
@@ -30,7 +30,7 @@ object trace {
3030
}
3131
else op
3232

33-
@inline
33+
@forceInline
3434
def apply[T](question: => String, printer: Printers.Printer, show: Boolean)(op: => T)(implicit ctx: Context): T =
3535
if (Config.tracingEnabled) {
3636
def op1 = op
@@ -39,15 +39,15 @@ object trace {
3939
}
4040
else op
4141

42-
@inline
42+
@forceInline
4343
def apply[T](question: => String, printer: Printers.Printer)(op: => T)(implicit ctx: Context): T =
4444
apply[T](question, printer, false)(op)
4545

46-
@inline
46+
@forceInline
4747
def apply[T](question: => String, show: Boolean)(op: => T)(implicit ctx: Context): T =
4848
apply[T](question, Printers.default, show)(op)
4949

50-
@inline
50+
@forceInline
5151
def apply[T](question: => String)(op: => T)(implicit ctx: Context): T =
5252
apply[T](question, Printers.default, false)(op)
5353

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ object Inliner {
229229
}
230230

231231
/** `sym` has an inline method with a known body to inline (note: definitions coming
232-
* from Scala2x class files might be `@inline`, but still lack that body.
232+
* from Scala2x class files might be `@forceInline`, but still lack that body.
233233
*/
234234
def hasBodyToInline(sym: SymDenotation)(implicit ctx: Context): Boolean =
235235
sym.isInlinedMethod && sym.hasAnnotation(defn.BodyAnnot) // TODO: Open this up for transparent methods as well
@@ -240,7 +240,7 @@ object Inliner {
240240
def bodyToInline(sym: SymDenotation)(implicit ctx: Context): Tree =
241241
sym.unforcedAnnotation(defn.BodyAnnot).get.tree
242242

243-
/** Try to inline a call to a `@inline` method. Fail with error if the maximal
243+
/** Try to inline a call to a `inline` method. Fail with error if the maximal
244244
* inline depth is exceeded.
245245
*
246246
* @param tree The call to inline
@@ -281,7 +281,7 @@ object Inliner {
281281

282282
/** Produces an inlined version of `call` via its `inlined` method.
283283
*
284-
* @param call the original call to a `@inline` method
284+
* @param call the original call to an `inline` method
285285
* @param rhsToInline the body of the inline method that replaces the call.
286286
*/
287287
class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ class Namer { typer: Typer =>
751751
if (sym.unforcedAnnotation(cls).isEmpty) {
752752
val ann = Annotation.deferred(cls, implicit ctx => typedAheadAnnotation(annotTree))
753753
sym.addAnnotation(ann)
754-
if (cls == defn.InlineAnnot && sym.is(Method, butNot = Accessor))
754+
if (cls == defn.ForceInlineAnnot && sym.is(Method, butNot = Accessor))
755755
sym.setFlag(Inline)
756756
}
757757
}

compiler/src/dotty/tools/dotc/util/Chars.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package dotty.tools.dotc
66
package util
77

8-
import scala.annotation.switch
8+
import scala.annotation.{forceInline, switch}
99
import java.lang.{Character => JCharacter}
1010
import java.lang.Character.LETTER_NUMBER
1111
import java.lang.Character.LOWERCASE_LETTER
@@ -38,7 +38,7 @@ object Chars {
3838

3939
/** Convert a character to a backslash-u escape */
4040
def char2uescape(c: Char): String = {
41-
@inline def hexChar(ch: Int): Char =
41+
@forceInline def hexChar(ch: Int): Char =
4242
(( if (ch < 10) '0' else 'A' - 10 ) + ch).toChar
4343

4444
char2uescapeArray(2) = hexChar((c >> 12) )

compiler/src/dotty/tools/dotc/util/Stats.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import collection.mutable
2020
override def default(key: String): Int = 0
2121
}
2222

23-
@inline
23+
@forceInline
2424
def record(fn: => String, n: => Int = 1) =
2525
if (enabled) doRecord(fn, n)
2626

@@ -30,7 +30,7 @@ import collection.mutable
3030
hits(name) += n
3131
}
3232

33-
@inline
33+
@forceInline
3434
def track[T](fn: String)(op: => T) =
3535
if (enabled) doTrack(fn)(op) else op
3636

@@ -42,7 +42,7 @@ import collection.mutable
4242
finally stack = stack.tail
4343
} else op
4444

45-
@inline
45+
@forceInline
4646
def trackTime[T](fn: String)(op: => T) =
4747
if (enabled) doTrackTime(fn)(op) else op
4848

compiler/src/dotty/tools/package.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package dotty
22
import scala.annotation.Annotation
33

44
package object tools {
5+
type forceInline = scala.annotation.forceInline
6+
57
class sharable extends Annotation
68
class unshared extends Annotation
79

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ class ErrorMessagesTests extends ErrorMessagesTest {
935935
@Test def noReturnInInline =
936936
checkMessagesAfter(FrontEnd.name) {
937937
"""class BadFunction {
938-
| @inline def usesReturn: Int = { return 42 }
938+
| inline def usesReturn: Int = { return 42 }
939939
|}
940940
""".stripMargin
941941
}.expect { (ictx, messages) =>

docs/docs/reference/inline.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ it in backticks, i.e.
125125

126126
@`inline` def ...
127127

128+
The Dotty compiler will ignore `@inline` annotated definitions. To cross
129+
compile between both Dotty and Scalac, one can annotate a definition with
130+
the new `@annotation.forceInline` annotation which is equivalent to the
131+
using new `inline` modifier.
132+
128133
### The definition of constant expression
129134

130135
Right-hand sides of inline values and of arguments for inline parameters

library/src/dotty/DottyPredef.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package dotty
22

3+
import scala.annotation.forceInline
4+
35
object DottyPredef {
46

57
/** A class for implicit values that can serve as implicit conversions
@@ -22,18 +24,18 @@ object DottyPredef {
2224
*/
2325
abstract class ImplicitConverter[-T, +U] extends Function1[T, U]
2426

25-
@inline final def assert(assertion: Boolean, message: => Any): Unit = {
27+
@forceInline final def assert(assertion: Boolean, message: => Any): Unit = {
2628
if (!assertion)
2729
assertFail(message)
2830
}
2931

30-
@inline final def assert(assertion: Boolean): Unit = {
32+
@forceInline final def assert(assertion: Boolean): Unit = {
3133
if (!assertion)
3234
assertFail()
3335
}
3436

3537
final def assertFail(): Unit = throw new java.lang.AssertionError("assertion failed")
3638
final def assertFail(message: => Any): Unit = throw new java.lang.AssertionError("assertion failed: " + message)
3739

38-
@inline final def implicitly[T](implicit ev: T): T = ev
40+
@forceInline final def implicitly[T](implicit ev: T): T = ev
3941
}

library/src/dotty/runtime/LazyVals.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dotty.runtime
22

3-
import scala.annotation.tailrec
3+
import scala.annotation.{tailrec, forceInline}
44

55
/**
66
* Helper methods used in thread-safe lazy vals.
@@ -24,20 +24,20 @@ object LazyVals {
2424
final val LAZY_VAL_MASK = 3L
2525
final val debug = false
2626

27-
@inline def STATE(cur: Long, ord: Int) = {
27+
@forceInline def STATE(cur: Long, ord: Int) = {
2828
val r = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
2929
if (debug)
3030
println(s"STATE($cur, $ord) = $r")
3131
r
3232
}
33-
@inline def CAS(t: Object, offset: Long, e: Long, v: Int, ord: Int) = {
33+
@forceInline def CAS(t: Object, offset: Long, e: Long, v: Int, ord: Int) = {
3434
if (debug)
3535
println(s"CAS($t, $offset, $e, $v, $ord)")
3636
val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL)
3737
val n = (e & mask) | (v.toLong << (ord * BITS_PER_LAZY_VAL))
3838
compareAndSet(t, offset, e, n)
3939
}
40-
@inline def setFlag(t: Object, offset: Long, v: Int, ord: Int) = {
40+
@forceInline def setFlag(t: Object, offset: Long, v: Int, ord: Int) = {
4141
if (debug)
4242
println(s"setFlag($t, $offset, $v, $ord)")
4343
var retry = true
@@ -56,7 +56,7 @@ object LazyVals {
5656
}
5757
}
5858
}
59-
@inline def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int) = {
59+
@forceInline def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int) = {
6060
if (debug)
6161
println(s"wait4Notification($t, $offset, $cur, $ord)")
6262
var retry = true
@@ -74,8 +74,8 @@ object LazyVals {
7474
}
7575
}
7676

77-
@inline def compareAndSet(t: Object, off: Long, e: Long, v: Long) = unsafe.compareAndSwapLong(t, off, e, v)
78-
@inline def get(t: Object, off: Long) = {
77+
@forceInline def compareAndSet(t: Object, off: Long, e: Long, v: Long) = unsafe.compareAndSwapLong(t, off, e, v)
78+
@forceInline def get(t: Object, off: Long) = {
7979
if (debug)
8080
println(s"get($t, $off)")
8181
unsafe.getLongVolatile(t, off)
@@ -87,7 +87,7 @@ object LazyVals {
8787
x => new Object()
8888
}.toArray
8989

90-
@inline def getMonitor(obj: Object, fieldId: Int = 0) = {
90+
@forceInline def getMonitor(obj: Object, fieldId: Int = 0) = {
9191
var id = (
9292
/*java.lang.System.identityHashCode(obj) + */ // should be here, but #548
9393
fieldId) % base
@@ -96,7 +96,7 @@ object LazyVals {
9696
monitors(id)
9797
}
9898

99-
@inline def getOffset(clz: Class[_], name: String) = {
99+
@forceInline def getOffset(clz: Class[_], name: String) = {
100100
val r = unsafe.objectFieldOffset(clz.getDeclaredField(name))
101101
if (debug)
102102
println(s"getOffset($clz, $name) = $r")
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package scala.annotation
2+
3+
/** An annotation on methods that is equivalent to Dotty `inline` modifier.
4+
*
5+
* The annotation should be used instead of the `inline` modifier in code
6+
* that needs to cross compile between Scala 2 and Dotty.
7+
*/
8+
class forceInline extends scala.annotation.StaticAnnotation

library/src/scala/tasty/util/ShowSourceCode.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,8 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
949949
case Annotation(annot, _) =>
950950
annot.tpe match {
951951
case Type.TypeRef(_, Type.SymRef(PackageDef("internal", _), Type.ThisType(Type.SymRef(PackageDef("annotation", _), NoPrefix())))) => false
952-
case Type.TypeRef("inline", Types.ScalaPackage()) => false
952+
case Type.TypeRef("forceInline", Type.SymRef(PackageDef("annotation", _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix())))) => false
953+
case Type.SymRef(ClassDef("forceInline", _, _, _, _), Type.SymRef(PackageDef("annotation", _), Type.ThisType(Type.SymRef(PackageDef("scala", _), NoPrefix())))) => false
953954
case _ => true
954955
}
955956
case x => throw new MatchError(x.show)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
object B {
2-
@inline def getInline: Int =
2+
@annotation.forceInline def getInline: Int =
33
A.get
44
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
object B {
2-
@inline def getInline: Double =
2+
@annotation.forceInline def getInline: Double =
33
A.get
44
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
object B {
2-
@inline def getInline: Int =
2+
@annotation.forceInline def getInline: Int =
33
sys.error("This is an expected failure when running C")
44
}

tests/neg/power.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
object Test {
22

3-
@inline
3+
@annotation.forceInline
44
def power(x: Double, n: Int): Double =
55
if (n == 0) 1.0
66
else if (n == 1) x

tests/pickling/i2166.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object Test {
2-
@inline def f = "" match { case _ => false }
2+
@annotation.forceInline def f = "" match { case _ => false }
33

44
def main(args: Array[String]): Unit = f
55
}

tests/pos/SI-7060.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
object Test {
22

3-
@inline final def mbarray_apply_minibox(array: Any, tag: Byte): Long =
3+
@annotation.forceInline final def mbarray_apply_minibox(array: Any, tag: Byte): Long =
44
if (tag == 0) {
55
array.asInstanceOf[Array[Long]](0)
66
} else

0 commit comments

Comments
 (0)