From 5f9e569926728e7f591a26729efa7700387aeb22 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 21 Feb 2017 09:28:22 +0100 Subject: [PATCH] Don't inline when errors are detected Inlining is only well-defined if the body to inline does not have any errors. We therefore check for errors before we perform any transformation of trees related to inlining. The error check is global, i.e. we stop on any error not just on errors in the code to be inlined. This is a safe approximation, of course. --- .../dotty/tools/dotc/reporting/Reporter.scala | 16 ---------------- .../src/dotty/tools/dotc/typer/Inliner.scala | 11 +++++++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 3 ++- tests/neg/i2006.scala | 10 ++++++++++ 4 files changed, 19 insertions(+), 21 deletions(-) create mode 100644 tests/neg/i2006.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 26c1e5ebc11e..b2c7abec9357 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -171,22 +171,6 @@ trait Reporting { this: Context => throw ex } } - - /** Implements a fold that applies the function `f` to the result of `op` if - * there are no new errors in the reporter - * - * @param op operation checked for errors - * @param f function applied to result of op - * @return either the result of `op` if it had errors or the result of `f` - * applied to it - */ - def withNoError[A, B >: A](op: => A)(f: A => B): B = { - val before = reporter.errorCount - val op0 = op - - if (reporter.errorCount > before) op0 - else f(op0) - } } /** diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index cfc0003c6bc0..3fa39edd5fec 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -27,7 +27,7 @@ import transform.TypeUtils._ object Inliner { import tpd._ - /** Adds accessors accessors for all non-public term members accessed + /** Adds accessors for all non-public term members accessed * from `tree`. Non-public type members are currently left as they are. * This means that references to a private type will lead to typing failures * on the code when it is inlined. Less than ideal, but hard to do better (see below). @@ -190,7 +190,8 @@ object Inliner { val inlineCtx = ctx sym.updateAnnotation(LazyBodyAnnotation { _ => implicit val ctx = inlineCtx - ctx.withNoError(treeExpr(ctx))(makeInlineable) + val body = treeExpr(ctx) + if (ctx.reporter.hasErrors) body else makeInlineable(body) }) } } @@ -233,8 +234,10 @@ object Inliner { * and body that replace it. */ def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = - if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) - new Inliner(tree, bodyToInline(tree.symbol)).inlined(pt) + if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) { + val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors + if (ctx.reporter.hasErrors) tree else new Inliner(tree, body).inlined(pt) + } else errorTree( tree, i"""|Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded, diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 498fd001bdf8..26f7bc65ba34 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1964,7 +1964,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (Inliner.hasBodyToInline(tree.symbol) && !ctx.owner.ownersIterator.exists(_.isInlineMethod) && !ctx.settings.YnoInline.value && - !ctx.isAfterTyper) + !ctx.isAfterTyper && + !ctx.reporter.hasErrors) adapt(Inliner.inlineCall(tree, pt), pt) else if (ctx.typeComparer.GADTused && pt.isValueType) // Insert an explicit cast, so that -Ycheck in later phases succeeds. diff --git a/tests/neg/i2006.scala b/tests/neg/i2006.scala new file mode 100644 index 000000000000..f1b48b011384 --- /dev/null +++ b/tests/neg/i2006.scala @@ -0,0 +1,10 @@ +object Test { + + inline def foo(f: ImplicitFunction1[Int, Int]): AnyRef = f // error + inline def bar(f: ImplicitFunction1[Int, Int]) = f // error + + def main(args: Array[String]) = { + foo(implicit thisTransaction => 43) + bar(implicit thisTransaction => 44) + } +}