From 19ab7ab10fabe7113f45063ffd2b6cc6abcc3329 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 6 Sep 2016 13:20:39 +0200 Subject: 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. --- src/dotty/tools/dotc/config/ScalaSettings.scala | 1 + src/dotty/tools/dotc/core/Decorators.scala | 2 +- src/dotty/tools/dotc/core/Definitions.scala | 2 +- src/dotty/tools/dotc/reporting/Reporter.scala | 6 ++-- src/dotty/tools/dotc/typer/Inliner.scala | 42 +++++++++++-------------- src/dotty/tools/dotc/typer/Typer.scala | 2 ++ src/dotty/tools/dotc/util/Stats.scala | 4 +-- 7 files changed, 28 insertions(+), 31 deletions(-) (limited to 'src/dotty/tools/dotc') 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 -- cgit v1.2.3