aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-09-06 13:20:39 +0200
committerMartin Odersky <odersky@gmail.com>2016-10-02 16:11:21 +0200
commit19ab7ab10fabe7113f45063ffd2b6cc6abcc3329 (patch)
tree3672315832460f5d636074fc2c387d243597cff5
parentbd0660ef100ee1a41bd56267d9e95c9e6dd74d5e (diff)
downloaddotty-19ab7ab10fabe7113f45063ffd2b6cc6abcc3329.tar.gz
dotty-19ab7ab10fabe7113f45063ffd2b6cc6abcc3329.tar.bz2
dotty-19ab7ab10fabe7113f45063ffd2b6cc6abcc3329.zip
Make inline annotation @scala.inline.
Drop @dotty.annotation.inline. This will inline all @inline marked methods in Scala for which a body is known (i.e. that are either compiled in the same run or have Tasty trees available). Option -Yno-inline suppresses inlining. This is needed for the moment because some @inline methods access private members or members that are otherwise inaccessible at the call-site. Also fixes some problems in Inliner - make sure type arguments to inline calls re fully defined - don't forget recursive calls in typeMap - don't forget positions in treeMap - drop dead code dealing with outer.
-rw-r--r--src/dotty/annotation/inline.scala8
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala1
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala2
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Inliner.scala42
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala2
-rw-r--r--src/dotty/tools/dotc/util/Stats.scala4
-rw-r--r--test/dotc/tests.scala4
-rw-r--r--tests/neg/inlineAccess.scala15
-rw-r--r--tests/neg/inlineAccess/C_1.scala2
-rw-r--r--tests/neg/power.scala2
-rw-r--r--tests/run/inline/inlines_1.scala10
-rw-r--r--tests/run/inlinePower/power_1.scala2
-rw-r--r--tests/run/inlinedAssign.scala6
15 files changed, 41 insertions, 67 deletions
diff --git a/src/dotty/annotation/inline.scala b/src/dotty/annotation/inline.scala
deleted file mode 100644
index ff4ca08b6..000000000
--- a/src/dotty/annotation/inline.scala
+++ /dev/null
@@ -1,8 +0,0 @@
-package dotty.annotation
-
-import scala.annotation.Annotation
-
-/** Unlike scala.inline, this one forces inlining in the Typer
- * Should be replaced by keyword when we switch over completely to dotty
- */
-class inline extends Annotation \ No newline at end of file
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index d05ae0803..42e761c2e 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -186,6 +186,7 @@ class ScalaSettings extends Settings.SettingGroup {
val Yexplainlowlevel = BooleanSetting("-Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).")
val YshowVarBounds = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds")
+ val YnoInline = BooleanSetting("-Yno-inline", "Suppress inlining.")
val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize"
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 64f50173c..691e0aeba 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -42,7 +42,7 @@ object Decorators {
*/
implicit class ListDecorator[T](val xs: List[T]) extends AnyVal {
- @inline final def mapconserve[U](f: T => U): List[U] = {
+ final def mapconserve[U](f: T => U): List[U] = {
@tailrec
def loop(mapped: ListBuffer[U], unchanged: List[U], pending: List[T]): List[U] =
if (pending.isEmpty) {
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index c9a3ef4de..8bf340337 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -466,7 +466,7 @@ class Definitions {
def DeprecatedAnnot(implicit ctx: Context) = DeprecatedAnnotType.symbol.asClass
lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef("scala.annotation.implicitNotFound")
def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass
- lazy val InlineAnnotType = ctx.requiredClassRef("dotty.annotation.inline")
+ lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline")
def InlineAnnot(implicit ctx: Context) = InlineAnnotType.symbol.asClass
lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InvariantBetween")
def InvariantBetweenAnnot(implicit ctx: Context) = InvariantBetweenAnnotType.symbol.asClass
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index 68ed972e1..f3777473d 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -140,16 +140,16 @@ trait Reporting { this: Context =>
def debugwarn(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
if (this.settings.debug.value) warning(msg, pos)
- @dotty.annotation.inline
+ @inline
def debugTraceIndented[TD](question: => String, printer: Printers.Printer = Printers.default, show: Boolean = false)(op: => TD): TD =
conditionalTraceIndented(this.settings.debugTrace.value, question, printer, show)(op)
- @dotty.annotation.inline
+ @inline
def conditionalTraceIndented[TC](cond: Boolean, question: => String, printer: Printers.Printer = Printers.default, show: Boolean = false)(op: => TC): TC =
if (cond) traceIndented[TC](question, printer, show)(op)
else op
- @dotty.annotation.inline
+ @inline
def traceIndented[T](question: => String, printer: Printers.Printer = Printers.default, show: Boolean = false)(op: => T): T =
if (printer eq config.Printers.noPrinter) op
else doTraceIndented[T](question, printer, show)(op)
diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala
index 4af9ecaec..b59c33008 100644
--- a/src/dotty/tools/dotc/typer/Inliner.scala
+++ b/src/dotty/tools/dotc/typer/Inliner.scala
@@ -17,6 +17,7 @@ import Names.Name
import SymDenotations.SymDenotation
import Annotations.Annotation
import transform.ExplicitOuter
+import Inferencing.fullyDefinedType
import config.Printers.inlining
import ErrorReporting.errorTree
import util.{Property, SourceFile, NoSource}
@@ -36,13 +37,13 @@ object Inliner {
def attachBody(inlineAnnot: Annotation, tree: => Tree)(implicit ctx: Context): Unit =
inlineAnnot.tree.putAttachment(InlinedBody, new InlinedBody(tree))
- def inlinedBody(sym: SymDenotation)(implicit ctx: Context): Tree =
+ def inlinedBody(sym: SymDenotation)(implicit ctx: Context): Option[Tree] =
sym.getAnnotation(defn.InlineAnnot).get.tree
- .attachment(InlinedBody).body
+ .getAttachment(InlinedBody).map(_.body)
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
if (enclosingInlineds.length < ctx.settings.xmaxInlines.value)
- new Inliner(tree, inlinedBody(tree.symbol)).inlined(pt)
+ new Inliner(tree, inlinedBody(tree.symbol).get).inlined(pt)
else errorTree(tree,
i"""Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded,
| Maybe this is caused by a recursive inline method?
@@ -86,6 +87,8 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
private val (methPart, targs, argss) = decomposeCall(call)
private val meth = methPart.symbol
+ for (targ <- targs) fullyDefinedType(targ.tpe, "inlined type argument", targ.pos)
+
private val prefix = methPart match {
case Select(qual, _) => qual
case _ => tpd.This(ctx.owner.enclosingClass.asClass)
@@ -156,19 +159,9 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
private object InlineTyper extends ReTyper {
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
- val acc = tree.symbol
- super.typedSelect(tree, pt) match {
- case res @ Select(qual, name) =>
- if (name.endsWith(nme.OUTER)) {
- val outerAcc = tree.symbol
- res.withType(qual.tpe.widen.normalizedPrefix)
- }
- else {
- ensureAccessible(res.tpe, qual.isInstanceOf[Super], tree.pos)
- res
- }
- case res => res
- }
+ val res = super.typedSelect(tree, pt)
+ ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.pos)
+ res
}
override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = {
val cond1 = typed(tree.cond, defn.BooleanType)
@@ -207,26 +200,27 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
val typeMap = new TypeMap {
def apply(t: Type) = t match {
case t: ThisType => thisProxy.getOrElse(t, t)
- case t: TypeRef => paramProxy.getOrElse(t, t)
- case t: SingletonType => paramProxy.getOrElse(t, t)
+ case t: TypeRef => paramProxy.getOrElse(t, mapOver(t))
+ case t: SingletonType => paramProxy.getOrElse(t, mapOver(t))
case t => mapOver(t)
}
}
- def treeMap(tree: Tree) = tree match {
+ def treeMap(tree: Tree) = {
+ tree match {
case _: This =>
thisProxy.get(tree.tpe) match {
- case Some(t) => ref(t)
+ case Some(t) => ref(t).withPos(tree.pos)
case None => tree
}
case _: Ident =>
paramProxy.get(tree.tpe) match {
- case Some(t: SingletonType) if tree.isTerm => singleton(t)
- case Some(t) if tree.isType => TypeTree(t)
+ case Some(t: SingletonType) if tree.isTerm => singleton(t).withPos(tree.pos)
+ case Some(t) if tree.isType => TypeTree(t).withPos(tree.pos)
case None => tree
}
case _ => tree
- }
+ }}
val inliner = new TreeTypeMap(typeMap, treeMap, meth :: Nil, ctx.owner :: Nil)
val bindings = bindingsBuf.toList.map(_.withPos(call.pos))
@@ -235,7 +229,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
val expansion1 = InlineTyper.typed(expansion, pt)(inlineContext(call))
val result = tpd.Inlined(call, bindings, expansion1)
- inlining.println(i"inlining $call\n --> \n$result")
+ inlining.println(i"inlined $call\n --> \n$result")
result
}
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 22a5095ec..29c36805f 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1794,7 +1794,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
else if (tree.tpe <:< pt)
if (tree.symbol.isInlineMethod &&
+ Inliner.inlinedBody(tree.symbol).isDefined &&
!ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
+ !ctx.settings.YnoInline.value &&
!ctx.isAfterTyper)
adapt(Inliner.inlineCall(tree, pt), pt)
else if (ctx.typeComparer.GADTused && pt.isValueType)
diff --git a/src/dotty/tools/dotc/util/Stats.scala b/src/dotty/tools/dotc/util/Stats.scala
index f5e711348..e06695dfb 100644
--- a/src/dotty/tools/dotc/util/Stats.scala
+++ b/src/dotty/tools/dotc/util/Stats.scala
@@ -20,7 +20,7 @@ import collection.mutable
override def default(key: String): Int = 0
}
- @dotty.annotation.inline
+ @inline
def record(fn: String, n: Int = 1) =
if (enabled) doRecord(fn, n)
@@ -30,7 +30,7 @@ import collection.mutable
hits(name) += n
}
- @dotty.annotation.inline
+ @inline
def track[T](fn: String)(op: => T) =
if (enabled) doTrack(fn)(op) else op
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 9f95a30c1..a12e77918 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -156,7 +156,7 @@ class tests extends CompilerTest {
.filter(_.nonEmpty)
.toList
- @Test def compileStdLib = compileList("compileStdLib", stdlibFiles, "-migration" :: scala2mode)
+ @Test def compileStdLib = compileList("compileStdLib", stdlibFiles, "-migration" :: "-Yno-inline" :: scala2mode)
@Test def compileMixed = compileLine(
"""tests/pos/B.scala
|./scala-scala/src/library/scala/collection/immutable/Seq.scala
@@ -274,7 +274,7 @@ class tests extends CompilerTest {
"ClassOf.scala", "CollectEntryPoints.scala", "Constructors.scala", "CrossCastAnd.scala",
"CtxLazy.scala", "ElimByName.scala", "ElimErasedValueType.scala", "ElimRepeated.scala",
"ElimStaticThis.scala", "Erasure.scala", "ExpandPrivate.scala", "ExpandSAMs.scala",
- "ExplicitOuter.scala", "ExplicitSelf.scala", "ExtensionMethods.scala", "FirstTransform.scala",
+ "ExplicitOuter.scala", "ExtensionMethods.scala", "FirstTransform.scala",
"Flatten.scala", "FullParameterization.scala", "FunctionalInterfaces.scala", "GetClass.scala",
"Getters.scala", "InterceptedMethods.scala", "LambdaLift.scala", "LiftTry.scala", "LinkScala2ImplClasses.scala",
"MacroTransform.scala", "Memoize.scala", "Mixin.scala", "MixinOps.scala", "NonLocalReturns.scala",
diff --git a/tests/neg/inlineAccess.scala b/tests/neg/inlineAccess.scala
deleted file mode 100644
index cfb1cc06f..000000000
--- a/tests/neg/inlineAccess.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-package p {
-class C {
- protected def f(): Unit = ()
-
- @dotty.annotation.inline
- def inl() = f() // error (when inlined): not accessible
-}
-}
-
-object Test {
- def main(args: Array[String]) = {
- val c = new p.C()
- c.inl()
- }
-}
diff --git a/tests/neg/inlineAccess/C_1.scala b/tests/neg/inlineAccess/C_1.scala
index fc24f7666..6db1ea787 100644
--- a/tests/neg/inlineAccess/C_1.scala
+++ b/tests/neg/inlineAccess/C_1.scala
@@ -2,7 +2,7 @@ package p {
class C {
protected def f(): Unit = ()
- @dotty.annotation.inline
+ @inline
def inl() = f() // error (when inlined): not accessible
}
}
diff --git a/tests/neg/power.scala b/tests/neg/power.scala
index 7439d8699..6230b4e51 100644
--- a/tests/neg/power.scala
+++ b/tests/neg/power.scala
@@ -1,6 +1,6 @@
object Test {
- @dotty.annotation.inline
+ @inline
def power(x: Double, n: Int): Double =
if (n == 0) 1.0
else if (n == 1) x
diff --git a/tests/run/inline/inlines_1.scala b/tests/run/inline/inlines_1.scala
index 36f5ac402..8189e6805 100644
--- a/tests/run/inline/inlines_1.scala
+++ b/tests/run/inline/inlines_1.scala
@@ -5,7 +5,7 @@ object inlines {
final val monitored = false
- @dotty.annotation.inline
+ @inline
def f(x: Int): Int = x * x
val hits = new mutable.HashMap[String, Int] {
@@ -21,7 +21,7 @@ object inlines {
@volatile private var stack: List[String] = Nil
- @dotty.annotation.inline
+ @inline
def track[T](fn: String)(op: => T) =
if (monitored) {
stack = fn :: stack
@@ -34,9 +34,9 @@ object inlines {
def f = "Outer.f"
class Inner {
val msg = " Inner"
- @dotty.annotation.inline def m = msg
- @dotty.annotation.inline def g = f
- @dotty.annotation.inline def h = f ++ m
+ @inline def m = msg
+ @inline def g = f
+ @inline def h = f ++ m
}
val inner = new Inner
}
diff --git a/tests/run/inlinePower/power_1.scala b/tests/run/inlinePower/power_1.scala
index 1faa10516..23da6009a 100644
--- a/tests/run/inlinePower/power_1.scala
+++ b/tests/run/inlinePower/power_1.scala
@@ -2,7 +2,7 @@ package p
object pow {
- @dotty.annotation.inline
+ @inline
def power(x: Double, n: Int): Double =
if (n == 0) 1.0
else if (n == 1) x
diff --git a/tests/run/inlinedAssign.scala b/tests/run/inlinedAssign.scala
index 735158209..b9a5d287d 100644
--- a/tests/run/inlinedAssign.scala
+++ b/tests/run/inlinedAssign.scala
@@ -1,6 +1,6 @@
object Test {
- @dotty.annotation.inline
+ @inline
def swap[T](x: T, x_= : T => Unit, y: T, y_= : T => Unit) = {
val t = x
x_=(y)
@@ -10,8 +10,8 @@ object Test {
def main(args: Array[String]) = {
var x = 1
var y = 2
- @dotty.annotation.inline def setX(z: Int) = x = z
- @dotty.annotation.inline def setY(z: Int) = y = z
+ @inline def setX(z: Int) = x = z
+ @inline def setY(z: Int) = y = z
swap[Int](x, setX, y, setY)
assert(x == 2 && y == 1)
}