From e2fb217483d72b7c35d67377b165742a9209bb06 Mon Sep 17 00:00:00 2001 From: VladimirNik Date: Fri, 9 May 2014 20:50:39 +0400 Subject: TypeTree printing modified (SI-8447) --- .../scala/reflect/internal/PrintersTest.scala | 77 ++++++++++++++-------- 1 file changed, 51 insertions(+), 26 deletions(-) (limited to 'test') diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala index 4587417a99..1458b942dc 100644 --- a/test/junit/scala/reflect/internal/PrintersTest.scala +++ b/test/junit/scala/reflect/internal/PrintersTest.scala @@ -33,10 +33,10 @@ object PrinterHelper { def wrapCode(source: String) = { val context = sm""" |trait PrintersContext { - | class baz extends scala.annotation.StaticAnnotation; - | class foo1[A, B] extends scala.annotation.StaticAnnotation; - | class foo2[A, B](a: scala.Int)(b: scala.Int) extends scala.annotation.StaticAnnotation; - | class foo3[Af, Bf](a: scala.Int)(b: scala.Float, c: PrintersContext.this.foo1[Af, Bf]) extends scala.annotation.StaticAnnotation; + | class baz extends scala.annotation.Annotation with scala.annotation.StaticAnnotation; + | class foo1[A, B] extends scala.annotation.Annotation with scala.annotation.StaticAnnotation; + | class foo2[A, B](a: scala.Int)(b: scala.Int) extends scala.annotation.Annotation with scala.annotation.StaticAnnotation; + | class foo3[Af, Bf](a: scala.Int)(b: scala.Float, c: PrintersContext.this.foo1[Af, Bf]) extends scala.annotation.Annotation with scala.annotation.StaticAnnotation; | trait A1; | trait B1; |${source.trim.lines map {" " + _} mkString s"$LF"} @@ -54,8 +54,12 @@ object PrinterHelper { } } - def assertTreeCode(tree: Tree)(code: String) = { - assertEquals("using quasiquote or given tree"+LF, code.trim, normalizeEOL(showCode(tree))) + def assertTreeCode(tree: Tree, typecheck: Boolean = false)(code: String) = { + if (typecheck) { + assertEquals("using quasiquote or given tree (typechecked)"+LF, code.trim, normalizeEOL(showCode(toolbox.typecheck(tree)))) + } else { + assertEquals("using quasiquote or given tree"+LF, code.trim, normalizeEOL(showCode(tree))) + } } def assertPrintedCode(source: String, checkTypedTree: Boolean = true, wrapCode: Boolean = false) = { @@ -312,17 +316,17 @@ trait BasePrintTests { @Test def testFunc1 = assertResultCode( code = "List(1, 2, 3).map((i: Int) => i - 1)")( parsedCode = "List(1, 2, 3).map(((i: Int) => i.-(1)))", - typedCode = sm"scala.collection.immutable.List.apply(1, 2, 3).map(((i: scala.Int) => i.-(1)))(scala.collection.immutable.List.canBuildFrom)") + typedCode = sm"scala.collection.immutable.List.apply[Int](1, 2, 3).map[Int, List[Int]](((i: scala.Int) => i.-(1)))(scala.collection.immutable.List.canBuildFrom[Int])") @Test def testFunc2 = assertResultCode( code = "val sum: Seq[Int] => Int = _ reduceLeft (_+_)")( parsedCode = "val sum: _root_.scala.Function1[Seq[Int], Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))", - typedCode = "val sum: _root_.scala.Function1[scala.`package`.Seq[scala.Int], scala.Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))") + typedCode = "val sum: _root_.scala.Function1[scala.`package`.Seq[scala.Int], scala.Int] = ((x$1: Seq[Int]) => x$1.reduceLeft[Int](((x$2: Int, x$3: Int) => x$2.+(x$3))))") @Test def testFunc3 = assertResultCode( code = "List(1, 2, 3) map (_ - 1)")( parsedCode = "List(1, 2, 3).map(((x$1) => x$1.-(1))) ", - typedCode = "scala.collection.immutable.List.apply(1, 2, 3).map(((x$1) => x$1.-(1)))(scala.collection.immutable.List.canBuildFrom)") + typedCode = "scala.collection.immutable.List.apply[Int](1, 2, 3).map[Int, List[Int]](((x$1: Int) => x$1.-(1)))(scala.collection.immutable.List.canBuildFrom[Int])") @Test def testFunc4 = assertResultCode( code = "val x: String => Int = ((str: String) => 1)")( @@ -401,7 +405,8 @@ trait ClassPrintTests { @Test def testClassWithImplicitParams = assertPrintedCode("class X(var i: scala.Int)(implicit val d: scala.Double, var f: scala.Float)") - @Test def testClassWithEarly = assertPrintedCode(sm""" + @Test def testClassWithEarly = + assertPrintedCode(sm""" |class X(var i: scala.Int) extends { | val a = i; | type B @@ -419,15 +424,22 @@ trait ClassPrintTests { | throw Throw2.this.e |}""") - /* - class Test { - val (a, b) = (1, 2) - } - */ - @Test def testClassWithAssignmentWithTuple1 = assertPrintedCode(sm""" + @Test def testClassWithAssignmentWithTuple1 = assertResultCode(sm""" |class Test { - | private[this] val x$$1 = (scala.Tuple2.apply(1, 2): @scala.unchecked) match { - | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply(a, b) + | val (a, b) = (1, 2) + |}""")( + parsedCode = sm""" + |class Test { + | private[this] val x$$1 = (scala.Tuple2(1, 2): @scala.unchecked) match { + | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b) + | }; + | val a = x$$1._1; + | val b = x$$1._2 + |}""", + typedCode = sm""" + |class Test { + | private[this] val x$$1 = (scala.Tuple2.apply[Int, Int](1, 2): @scala.unchecked) match { + | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply[Int, Int](a, b) | }; | val a = Test.this.x$$1._1; | val b = Test.this.x$$1._2 @@ -448,8 +460,8 @@ trait ClassPrintTests { |}""", typedCode = sm""" |class Test { - | private[this] val x$$1 = (scala.Predef.ArrowAssoc(1).->(2): @scala.unchecked) match { - | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply(a, b) + | private[this] val x$$1 = (scala.Predef.ArrowAssoc[Int](1).->[Int](2): @scala.unchecked) match { + | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply[Int, Int](a, b) | }; | val a = Test.this.x$$1._1; | val b = Test.this.x$$1._2 @@ -462,8 +474,8 @@ trait ClassPrintTests { */ @Test def testClassWithPatternMatchInAssignment = assertPrintedCode(sm""" |class Test { - | private[this] val x$$1 = (scala.collection.immutable.List.apply(1, 3, 5): @scala.unchecked) match { - | case scala.collection.immutable.List((one @ _), (three @ _), (five @ _)) => scala.Tuple3.apply(one, three, five) + | private[this] val x$$1 = (scala.collection.immutable.List.apply[scala.Int](1, 3, 5): @scala.unchecked) match { + | case scala.collection.immutable.List((one @ _), (three @ _), (five @ _)) => scala.Tuple3.apply[scala.Int, scala.Int, scala.Int](one, three, five) | }; | val one = Test.this.x$$1._1; | val three = Test.this.x$$1._2; @@ -626,7 +638,7 @@ trait ClassPrintTests { @Test def testObjectWithPatternMatch1 = assertPrintedCode(sm""" |object PM1 { - | scala.collection.immutable.List.apply(1, 2) match { + | scala.collection.immutable.List.apply[scala.Int](1, 2) match { | case (i @ _) => i | } |}""") @@ -715,7 +727,7 @@ trait ClassPrintTests { |}""", typedCode = sm""" |object PM5 { - | scala.collection.immutable.List.apply(1, 2) match { + | scala.collection.immutable.List.apply[Int](1, 2) match { | case scala.`package`.::((x @ _), (xs @ _)) => x | } |}""") @@ -756,7 +768,7 @@ trait ClassPrintTests { @Test def testObjectWithPatternMatch8 = assertPrintedCode(sm""" |{ | object Extractor { - | def unapply(i: scala.Int) = scala.Some.apply(i) + | def unapply(i: scala.Int) = scala.Some.apply[scala.Int](i) | }; | object PM9 { | 42 match { @@ -991,7 +1003,7 @@ trait ValAndDefPrintTests { @Test def testDefWithLazyVal2 = assertPrintedCode(sm""" |def a = { - | lazy val test = { + | lazy val test: Unit = { | scala.Predef.println(); | scala.Predef.println() | }; @@ -1161,4 +1173,17 @@ trait QuasiTreesPrintTests { |case class X(x: Int, s: String) { | def y = "test" |}""") + + @Test def testQuasiCaseClassWithTypes1 = assertTreeCode(q"""case class X(x: ${typeOf[Int]}, s: ${typeOf[String]}){ def y = "test" }""")(sm""" + |case class X(x: Int, s: String) { + | def y = "test" + |}""") + + @Test def testQuasiCaseClassWithTypes2 = assertTreeCode(q"""case class X(x: ${typeOf[Int]}, s: ${typeOf[String]}){ def y = "test" }""", typecheck = true)(sm""" + |{ + | case class X(x: Int, s: String) { + | def y = "test" + | }; + | () + |}""") } \ No newline at end of file -- cgit v1.2.3 From 56ed4fc79580d4a0b7a264a436db3010543a9211 Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Wed, 21 May 2014 16:33:58 +0200 Subject: SI-8609 Fix flattening of definitions and imports in quasiquotes Quasiquotes allow to unquote trees with ..$ with block flattening semantics to simplify composition: val onetwo = q"1; 2" val onetwothree = q"..$onetwo; 3" // same as q"1; 2; 3" If there is no block it will be equivalent to $ unquoting: val one = q"1" val onetwo = q"..$one; 2" // same as q"1; 2" But the inconsistency here is that currently only terms support this single-element semantics. This commit extends this functionality to also support definitions and imports. So that following code works: val q1 = q"val x = 1" val q2 = q"..$q1; val y = 2" // same as q"val x = 1; val y = 2" --- src/reflect/scala/reflect/internal/ReificationSupport.scala | 2 ++ .../files/scalacheck/quasiquotes/TermConstructionProps.scala | 12 ++++++++++++ 2 files changed, 14 insertions(+) (limited to 'test') diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala index ad8a2594dd..2caa30d27e 100644 --- a/src/reflect/scala/reflect/internal/ReificationSupport.scala +++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala @@ -97,6 +97,8 @@ trait ReificationSupport { self: SymbolTable => def toStats(tree: Tree): List[Tree] = tree match { case EmptyTree => Nil case SyntacticBlock(stats) => stats + case defn if defn.isDef => defn :: Nil + case imp: Import => imp :: Nil case _ => throw new IllegalArgumentException(s"can't flatten $tree") } diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index 45392de582..409f07037e 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -310,4 +310,16 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { val cases = List(cq"a => b", cq"c => d") assertEqAst(q"{ case ..$cases }", "{ case a => b case c => d }") } + + property("SI-8609 a") = test { + val q1 = q"val x = 1" + val q2 = q"..$q1; val y = 2" + assert(q2 ≈ q"{ val x = 1; val y = 2 }") + } + + property("SI-8609 b") = test { + val q1 = q"import foo.bar" + val q2 = q"..$q1; val y = 2" + assert(q2 ≈ q"{ import foo.bar; val y = 2 }") + } } -- cgit v1.2.3 From 7a16f76673530f71bf1b8fa79b489b502ef504a8 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 23 Jun 2014 11:27:31 +0200 Subject: SI-8675 Avoid unreported error after second try using implicit view This is specific to situations in which we first typecheck an application `qual.m(arg)` against the method `m` directly provided by `qual`, and then fall back to `implicitView(qual).m(arg)`. Regressed in SI-3971 / 7fa77af, in which error reports were moved to the innermost `Apply`, and the check for `errorInResult` was accordingly changed to recurse through `Apply` trees. Before that change, we did not fall back to using a view. After the change, we do try a view. We retypecheck the arguments under the `retyping` mode (see `tryTypedArgs`), but this doesn't seem to be enough to avoid leaking the error typed nested trees from the first try. Here's an example from the enclosed test case: a.update(0, x[A]({new isString(true)})) `-- error typed refArrayOps(a).update(0, x[A]({new isString(true)})) ` `-- error type persists `-- this tree is retypecked by tryTypedArgs This commit changes `onError` to only proceed with the second try if the retyped argument trees are error free. --- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- test/files/neg/t8675.check | 11 ++++++++++ test/files/neg/t8675.scala | 24 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/files/neg/t8675.check create mode 100644 test/files/neg/t8675.scala (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 66b1c2d87a..9a4d5e3c06 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4399,7 +4399,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (retry) { val Select(qual, name) = fun tryTypedArgs(args, forArgMode(fun, mode)) match { - case Some(args1) => + case Some(args1) if !args1.exists(arg => arg.exists(_.isErroneous)) => val qual1 = if (!pt.isError) adaptToArguments(qual, name, args1, pt, reportAmbiguous = true, saveErrors = true) else qual diff --git a/test/files/neg/t8675.check b/test/files/neg/t8675.check new file mode 100644 index 0000000000..4e44fba918 --- /dev/null +++ b/test/files/neg/t8675.check @@ -0,0 +1,11 @@ +t8675.scala:13: error: type mismatch; + found : Boolean(true) + required: String + a.update(0, x[A]({new isString(true)})) // !!! allowed + ^ +t8675.scala:22: error: type mismatch; + found : Boolean(true) + required: String + new X().m(x[A]({new isString(true)})) // !!! allowed + ^ +two errors found diff --git a/test/files/neg/t8675.scala b/test/files/neg/t8675.scala new file mode 100644 index 0000000000..ca9bb57ffa --- /dev/null +++ b/test/files/neg/t8675.scala @@ -0,0 +1,24 @@ +class A(s: String) { + def foo(x: A) = x +} + +class isString(s: String) + +class Test { + + def x[A](a: Any): A = ??? + + def test { + val a = Array[A]() + a.update(0, x[A]({new isString(true)})) // !!! allowed + + // boils down to + class X { + def m(p: Any) {} + } + implicit class XOps(x: X) { + def m(p: Any) {} + } + new X().m(x[A]({new isString(true)})) // !!! allowed + } +} -- cgit v1.2.3 From 5ba129070f46da9b981d36afe2f9f0aac50c3800 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Thu, 26 Jun 2014 11:32:01 +0200 Subject: SI-8675 Add another test case for swallowed type errors As reported on scala-internals. After tightening up the treatment of undetermined type parameters in SI-7944, the enclosed test case no longer typechecks. And since the regression fixed in the previous commit, the error was swallowed by the typechecker only to be burped up by a crash in the backend. --- test/files/neg/t8675b.check | 6 ++++++ test/files/neg/t8675b.scala | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/files/neg/t8675b.check create mode 100644 test/files/neg/t8675b.scala (limited to 'test') diff --git a/test/files/neg/t8675b.check b/test/files/neg/t8675b.check new file mode 100644 index 0000000000..cb7ac8af59 --- /dev/null +++ b/test/files/neg/t8675b.check @@ -0,0 +1,6 @@ +t8675b.scala:19: error: missing parameter type for expanded function +The argument types of an anonymous function must be fully known. (SLS 8.5) +Expected type was: List[Test.Reportable1[?,?]] => Boolean + for (path: List[Any] <- (null : Engine1).asRequirement.pathsIncludingSelf.toList) { + ^ +one error found diff --git a/test/files/neg/t8675b.scala b/test/files/neg/t8675b.scala new file mode 100644 index 0000000000..2c5015b1d0 --- /dev/null +++ b/test/files/neg/t8675b.scala @@ -0,0 +1,22 @@ +object Test { + trait Engine1 + + implicit class EngineTools1[Params, R](e: Engine1) { + def asRequirement: Requirement1[Params, R] = ??? + } + trait Requirement1[Params, R] { + def pathsIncludingSelf: Traversable[List[Reportable1[Params, R]]] + } + trait Reportable1[Params, R] + + // "missing paramater type" error was swallowed in 2.11.0 leading to a crash + // in the backend. + // + // This error is itself a regression (or at least a change) in 2.11.0-M7, + // specifically in SI-7944. The type paramaters to the implicit view + // `EngineTools1` are undetermined, and are now treated as type variables + // in the expected type of the closure argument to `withFilter`. + for (path: List[Any] <- (null : Engine1).asRequirement.pathsIncludingSelf.toList) { + ??? + } +} -- cgit v1.2.3 From 4e29e9a229c5a13e8517fe034668aa97ae102eec Mon Sep 17 00:00:00 2001 From: Antoine Gourlay Date: Sun, 29 Jun 2014 16:42:14 +0200 Subject: SI-8690 BufferedSource.mkString mistakenly skipped the first char. mkString is overriden in BufferedSource for performance, but the implementation always used the wrong reader. This seems to be a typo (`allReader` is declared 5 lines earlier but never used, `charReader` is used in its place). --- src/library/scala/io/BufferedSource.scala | 2 +- test/files/run/t8690.check | 2 ++ test/files/run/t8690.scala | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/files/run/t8690.check create mode 100644 test/files/run/t8690.scala (limited to 'test') diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala index 1c87a1f421..52fa525b24 100644 --- a/src/library/scala/io/BufferedSource.scala +++ b/src/library/scala/io/BufferedSource.scala @@ -93,7 +93,7 @@ class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val cod val buf = new Array[Char](bufferSize) var n = 0 while (n != -1) { - n = charReader.read(buf) + n = allReader.read(buf) if (n>0) sb.appendAll(buf, 0, n) } sb.result diff --git a/test/files/run/t8690.check b/test/files/run/t8690.check new file mode 100644 index 0000000000..72f076c4d8 --- /dev/null +++ b/test/files/run/t8690.check @@ -0,0 +1,2 @@ +non-empty iterator +abcdef diff --git a/test/files/run/t8690.scala b/test/files/run/t8690.scala new file mode 100644 index 0000000000..ab8b45b2a7 --- /dev/null +++ b/test/files/run/t8690.scala @@ -0,0 +1,12 @@ +import scala.io.Source +import java.io.ByteArrayInputStream + +object Test extends App { + val txt = "abcdef" + + val in = new ByteArrayInputStream(txt.getBytes()); + val source = Source.fromInputStream(in); + println(source.toString) // forces the BufferedSource to look at the head of the input + + println(source.mkString) // used to return "bcdef" ... +} -- cgit v1.2.3 From acab0fa000e89d91ef6a809cd1cb70d519d29d5a Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Tue, 24 Jun 2014 05:18:20 +0200 Subject: [backport] SI-8677 Duration: Zero - Inf should be MinusInf Fixes #8677. Add basic tests. This is a backport from 2.12.x of dead39dc5f21c6eac41788e93426c50ddd398c24. --- src/library/scala/concurrent/duration/Duration.scala | 2 +- test/files/jvm/duration-tck.scala | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala index 1b50b7fa56..2eded9f060 100644 --- a/src/library/scala/concurrent/duration/Duration.scala +++ b/src/library/scala/concurrent/duration/Duration.scala @@ -621,7 +621,7 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio } def -(other: Duration) = other match { case x: FiniteDuration => add(-x.length, x.unit) - case _ => other + case _ => -other } def *(factor: Double) = diff --git a/test/files/jvm/duration-tck.scala b/test/files/jvm/duration-tck.scala index 3bc8a2c100..7db6c49964 100644 --- a/test/files/jvm/duration-tck.scala +++ b/test/files/jvm/duration-tck.scala @@ -61,6 +61,11 @@ object Test extends App { minf - inf mustBe minf minf + minf mustBe minf + for (i <- Seq(zero, one, two, three)) { + i - inf mustBe minf + i - minf mustBe inf + } + inf.compareTo(inf) mustBe 0 inf.compareTo(one) mustBe 1 inf.compareTo(minf) mustBe 1 -- cgit v1.2.3 From ffb0e25fc8ec9d6ecb0cd806bc534e9430e37bd4 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 10 Jun 2014 15:59:23 +0200 Subject: Unclutter Reporter. Move truncation to ReplReporter. Refactor to reduce the Reporter interface. Working towards minimal interfaces in scala.reflect.internal that can be consumed by sbt/IDE/.... The scala.tools.nsc package is entirely private to the compiler (in principle). A `Reporter` should only be used to inform (info/warning/error). No state. Ideally, we'd move to having only one reporter, whose lifetime is adjusted appropriately (from per-run in general to per-context for type checking, so errors can be buffered -- "silenced" -- during nested type checking calls). Start the clean up by moving truncation to the REPL, since it's not relevant for regular reporting. Perversely, we were checking truncation all the time, even though it's only on during a repl run. (Truncation is now always turned off in the repl under -verbose.) Untangle error resetting on symbols from error reporting (reportAdditionalErrors). This fixes a nice&subtle bug that caused feature warnings to be suppressed under `-Xfatal-warnings`: ``` def reportCompileErrors() { if (!reporter.hasErrors && reporter.hasWarnings && settings.fatalWarnings) globalError("No warnings can be incurred under -Xfatal-warnings.") if (reporter.hasErrors) { ... } else { // will erroneously not get here if // `reporter.hasWarnings && settings.fatalWarnings` // since the `globalError` call above means `reporter.hasErrors`... allConditionalWarnings foreach (_.summarize()) ... } } ``` The second `if`'s condition depends on the `globalError` call in the first `if`... --- .../scala/tools/nsc/CompilationUnits.scala | 3 +- src/compiler/scala/tools/nsc/Global.scala | 58 +++++++++++----------- .../tools/nsc/reporters/ConsoleReporter.scala | 3 +- .../scala/tools/nsc/reporters/Reporter.scala | 37 ++++++-------- .../scala/tools/nsc/reporters/StoreReporter.scala | 3 +- src/repl/scala/tools/nsc/interpreter/IMain.scala | 4 +- .../scala/tools/nsc/interpreter/ReplReporter.scala | 19 +++++++ test/files/neg/checksensible.check | 3 +- test/files/neg/overloaded-implicit.check | 3 +- test/files/neg/t6567.check | 3 +- test/files/neg/unchecked-refinement.check | 3 +- 11 files changed, 77 insertions(+), 62 deletions(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index c2caed70a0..924bb54ddb 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -146,7 +146,8 @@ trait CompilationUnits { global: Global => def incompleteInputError(pos: Position, msg:String) = reporter.incompleteInputError(pos, msg) - def comment(pos: Position, msg: String) = + // used by the IDE -- TODO: don't use reporter to communicate comments from parser to IDE! + def comment(pos: Position, msg: String): Unit = reporter.comment(pos, msg) /** Is this about a .java source file? */ diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index cb785de4b3..836203e80d 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -291,8 +291,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) log(s"!!!$pos_s $msg") // such warnings always at least logged } - def informComplete(msg: String): Unit = reporter.withoutTruncating(inform(msg)) - def logError(msg: String, t: Throwable): Unit = () override def shouldLogAtThisPhase = settings.log.isSetByUser && ( @@ -351,9 +349,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } if (settings.verbose || settings.Ylogcp) { - // Uses the "do not truncate" inform - informComplete("[search path for source files: " + classPath.sourcepaths.mkString(",") + "]") - informComplete("[search path for class files: " + classPath.asClasspathString + "]") + reporter.echo( + s"[search path for source files: ${classPath.sourcepaths.mkString(",")}]\n"+ + s"[search path for class files: ${classPath.asClasspathString}") } // The current division between scala.reflect.* and scala.tools.nsc.* is pretty @@ -1212,6 +1210,20 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def uncheckedWarnings: List[(Position, String)] = uncheckedWarnings0.warnings.toList // used in sbt def deprecationWarnings: List[(Position, String)] = deprecationWarnings0.warnings.toList // used in sbt + def reportAdditionalErrors(): Unit = { + if (!reporter.hasErrors) { + if (reporter.hasWarnings && settings.fatalWarnings) + globalError("No warnings can be incurred under -Xfatal-warnings.") + + allConditionalWarnings foreach (_.summarize()) + + if (seenMacroExpansionsFallingBack) + warning("some macros could not be expanded and code fell back to overridden methods;"+ + "\nrecompiling with generated classfiles on the classpath might help.") + // todo: migrationWarnings + } + } + var reportedFeature = Set[Symbol]() /** Has any macro expansion used a fallback during this run? */ @@ -1416,6 +1428,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) refreshProgress() } + // for sbt def cancel() { reporter.cancelled = true } private def currentProgress = (phasec * size) + unitc @@ -1565,26 +1578,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } } - def reportCompileErrors() { - if (!reporter.hasErrors && reporter.hasWarnings && settings.fatalWarnings) - globalError("No warnings can be incurred under -Xfatal-warnings.") - - if (reporter.hasErrors) { - for ((sym, file) <- symSource.iterator) { - sym.reset(new loaders.SourcefileLoader(file)) - if (sym.isTerm) - sym.moduleClass reset loaders.moduleClassLoader - } - } - else { - allConditionalWarnings foreach (_.summarize()) - - if (seenMacroExpansionsFallingBack) - warning("some macros could not be expanded and code fell back to overridden methods;"+ - "\nrecompiling with generated classfiles on the classpath might help.") - // todo: migrationWarnings - } - } /** Caching member symbols that are def-s in Defintions because they might change from Run to Run. */ val runDefinitions: definitions.RunDefinitions = new definitions.RunDefinitions @@ -1597,7 +1590,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def checkDeprecations() = { checkDeprecatedSettings(newCompilationUnit("")) - reportCompileErrors() + reportAdditionalErrors() } val units = sources map scripted map (new CompilationUnit(_)) @@ -1621,7 +1614,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) checkDeprecatedSettings(unitbuf.head) globalPhase = fromPhase - while (globalPhase.hasNext && !reporter.hasErrors) { + while (globalPhase.hasNext && !reporter.hasErrors) { val startTime = currentTime phase = globalPhase globalPhase.run() @@ -1667,6 +1660,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) advancePhase() } + reportAdditionalErrors() + if (traceSymbolActivity) units map (_.body) foreach (traceSymbols recordSymbolsInTree _) @@ -1674,8 +1669,15 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (settings.Yshow.isDefault) showMembers() - reportCompileErrors() + if (reporter.hasErrors) { + for ((sym, file) <- symSource.iterator) { + sym.reset(new loaders.SourcefileLoader(file)) + if (sym.isTerm) + sym.moduleClass reset loaders.moduleClassLoader + } + } symSource.keys foreach (x => resetPackageClass(x.owner)) + informTime("total", startTime) // Clear any sets or maps created via perRunCaches. diff --git a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala index 3f210a543c..0b218b711c 100644 --- a/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala @@ -12,8 +12,7 @@ import scala.reflect.internal.util._ import StringOps._ /** - * This class implements a Reporter that displays messages on a text - * console. + * This class implements a Reporter that displays messages on a text console. */ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: PrintWriter) extends AbstractReporter { def this(settings: Settings) = this(settings, Console.in, new PrintWriter(Console.err, true)) diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index 68362c066d..766a35960b 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -8,9 +8,10 @@ package reporters import scala.reflect.internal.util._ -/** - * This interface provides methods to issue information, warning and - * error messages. +/** Report information, warnings and errors. + * + * This describes the stable interface for issuing information, warnings and errors. + * The only abstract method in this class must be info0. */ abstract class Reporter { protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit @@ -29,19 +30,6 @@ abstract class Reporter { override def toString: String = "ERROR" } - /** Whether very long lines can be truncated. This exists so important - * debugging information (like printing the classpath) is not rendered - * invisible due to the max message length. - */ - private var _truncationOK: Boolean = true - def truncationOK = _truncationOK - def withoutTruncating[T](body: => T): T = { - val saved = _truncationOK - _truncationOK = false - try body - finally _truncationOK = saved - } - private var incompleteHandler: (Position, String) => Unit = null def incompleteHandled = incompleteHandler != null def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = { @@ -51,6 +39,7 @@ abstract class Reporter { finally incompleteHandler = saved } + // used by sbt (via unit.cancel) to cancel a compile (see hasErrors) var cancelled = false def hasErrors = ERROR.count > 0 || cancelled def hasWarnings = WARNING.count > 0 @@ -58,21 +47,23 @@ abstract class Reporter { /** For sending a message which should not be labeled as a warning/error, * but also shouldn't require -verbose to be visible. */ - def echo(msg: String): Unit = info(NoPosition, msg, force = true) - def echo(pos: Position, msg: String): Unit = info(pos, msg, force = true) + def echo(msg: String): Unit = info(NoPosition, msg, force = true) + def echo(pos: Position, msg: String): Unit = info(pos, msg, force = true) - /** Informational messages, suppressed unless -verbose or force=true. */ - def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) + /** Informational messages. If `!force`, they may be suppressed. */ + final def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) /** Warnings and errors. */ - def warning(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, WARNING, force = false)) - def error(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, ERROR, force = false)) + def warning(pos: Position, msg: String): Unit = info0(pos, msg, WARNING, force = false) + def error(pos: Position, msg: String): Unit = info0(pos, msg, ERROR, force = false) def incompleteInputError(pos: Position, msg: String): Unit = { if (incompleteHandled) incompleteHandler(pos, msg) else error(pos, msg) } - def comment(pos: Position, msg: String) { } + // overridden by sbt, IDE: + // `comment` is unrelated to reporting and should move out (IDE receives comments from ScaladocAnalyzer) + def comment(pos: Position, msg: String) {} def flush() { } def reset() { INFO.count = 0 diff --git a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala index 04c5bdf824..24a61cb171 100644 --- a/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/StoreReporter.scala @@ -10,8 +10,7 @@ import scala.collection.mutable import scala.reflect.internal.util.Position /** - * This class implements a Reporter that displays messages on a text - * console. + * This class implements a Reporter that stores its reports in the set `infos`. */ class StoreReporter extends Reporter { case class Info(pos: Position, msg: String, severity: Severity) { diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 47d97dd4dd..2deeed2be3 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -110,7 +110,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set lazy val reporter: ReplReporter = new ReplReporter(this) import formatting._ - import reporter.{ printMessage, withoutTruncating } + import reporter.{ printMessage, printUntruncatedMessage } // This exists mostly because using the reporter too early leads to deadlock. private def echo(msg: String) { Console println msg } @@ -609,7 +609,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } else { // don't truncate stack traces - withoutTruncating(printMessage(result)) + printUntruncatedMessage(result) IR.Error } } diff --git a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala index b20166d070..88372334d6 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplReporter.scala @@ -9,11 +9,29 @@ package interpreter import reporters._ import IMain._ +import scala.reflect.internal.util.Position + /** Like ReplGlobal, a layer for ensuring extra functionality. */ class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.in, new ReplStrippingWriter(intp)) { def printUntruncatedMessage(msg: String) = withoutTruncating(printMessage(msg)) + /** Whether very long lines can be truncated. This exists so important + * debugging information (like printing the classpath) is not rendered + * invisible due to the max message length. + */ + private var _truncationOK: Boolean = !intp.settings.verbose + def truncationOK = _truncationOK + def withoutTruncating[T](body: => T): T = { + val saved = _truncationOK + _truncationOK = false + try body + finally _truncationOK = saved + } + + override def warning(pos: Position, msg: String): Unit = withoutTruncating(super.warning(pos, msg)) + override def error(pos: Position, msg: String): Unit = withoutTruncating(super.error(pos, msg)) + override def printMessage(msg: String) { // Avoiding deadlock if the compiler starts logging before // the lazy val is complete. @@ -31,4 +49,5 @@ class ReplReporter(intp: IMain) extends ConsoleReporter(intp.settings, Console.i if (intp.totalSilence) () else super.displayPrompt() } + } diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index e5f1a38d96..38cc5ec447 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -98,5 +98,6 @@ checksensible.scala:95: warning: comparing values of types Unit and Int using `! while ((c = in.read) != -1) ^ error: No warnings can be incurred under -Xfatal-warnings. +error: there were 3 deprecation warnings; re-run with -deprecation for details 33 warnings found -one error found +two errors found diff --git a/test/files/neg/overloaded-implicit.check b/test/files/neg/overloaded-implicit.check index ca0870705d..d9594d126a 100644 --- a/test/files/neg/overloaded-implicit.check +++ b/test/files/neg/overloaded-implicit.check @@ -5,5 +5,6 @@ overloaded-implicit.scala:3: warning: parameterized overloaded implicit methods implicit def imp1[T](x: Set[T]): Map[T, T] = Map() ^ error: No warnings can be incurred under -Xfatal-warnings. +error: there were 4 feature warnings; re-run with -feature for details two warnings found -one error found +two errors found diff --git a/test/files/neg/t6567.check b/test/files/neg/t6567.check index a733d75354..3243fde0cd 100644 --- a/test/files/neg/t6567.check +++ b/test/files/neg/t6567.check @@ -5,5 +5,6 @@ t6567.scala:10: warning: Suspicious application of an implicit view (Test.this.a val b: Option[B] = Option(a) ^ error: No warnings can be incurred under -Xfatal-warnings. +error: there was one feature warning; re-run with -feature for details two warnings found -one error found +two errors found diff --git a/test/files/neg/unchecked-refinement.check b/test/files/neg/unchecked-refinement.check index e85a51f44d..b49e47fcbb 100644 --- a/test/files/neg/unchecked-refinement.check +++ b/test/files/neg/unchecked-refinement.check @@ -11,5 +11,6 @@ unchecked-refinement.scala:24: warning: a pattern match on a refinement type is /* nowarn - todo */ case x: AnyRef { def size: Int } if b => x.size // this could/should do a static conformance test and not warn ^ error: No warnings can be incurred under -Xfatal-warnings. +error: there was one feature warning; re-run with -feature for details four warnings found -one error found +two errors found -- cgit v1.2.3 From 98216be3f3e546fc320ab5182ac5c129707db1ce Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 10 Jun 2014 16:24:37 +0200 Subject: Move reporting logic into Reporting trait Move code from Global/SymbolTable to separate Reporting traits to start carving out an interface in scala.reflect.internal.Reporting, with internals in scala.tools.nsc. Reporting is mixed into the cake. It contains a nested class PerRunReporting. Should do the same for debugging/logging. The idea is that CompilationUnit and Global forward all reporting to Reporter. The Reporting trait contains these forwarders, and PerRunReporting, which accumulates warning state during a run. In the process, I slightly changed the behavior of `globalError` in reflect.internal.SymbolTable: it used to abort, weirdly. I assume that was dummy behavior to avoid introducing an abstract method. It's immediately overridden in Global, and I couldn't find any other subclasses, so I don't think the behavior in SymbolTable was ever observed. Provide necessary hooks for scala.reflect.macros.Parsers#parse. See scala/reflect/macros/contexts/Parsers.scala's parse method, which overrides the reporter to detect when parsing goes wrong. This should be refactored, but that goes beyond the scope of this PR. Don't pop empty macro context stack. (Ran into this while reworking -Xfatal-warnings logic.) Fix -Xfatal-warnings behavior (and check files): it wasn't meant to influence warning reporting, except for emitting one final error; if necessary to fail the compile (when warnings but no errors were reported). Warnings should stay warnings. This was refactored in fbbbb22946, but we soon seem to have relapsed. An hour of gitfu did not lead to where it went wrong. Must've been a merge. --- bincompat-forward.whitelist.conf | 8 ++ .../scala/reflect/macros/contexts/Parsers.scala | 5 +- .../scala/tools/nsc/CompilationUnits.scala | 37 +++-- src/compiler/scala/tools/nsc/CompileServer.scala | 4 +- src/compiler/scala/tools/nsc/Global.scala | 150 +++++++-------------- src/compiler/scala/tools/nsc/Reporting.scala | 132 ++++++++++++++++++ .../tools/nsc/ast/parser/SyntaxAnalyzer.scala | 2 +- .../scala/tools/nsc/reporters/Reporter.scala | 15 --- .../scala/tools/nsc/typechecker/Macros.scala | 4 +- .../scala/tools/nsc/typechecker/Typers.scala | 16 +-- src/reflect/scala/reflect/internal/Positions.scala | 11 +- src/reflect/scala/reflect/internal/Reporting.scala | 32 +++++ .../scala/reflect/internal/SymbolTable.scala | 9 +- src/repl/scala/tools/nsc/interpreter/IMain.scala | 4 +- test/files/neg/checksensible.check | 6 +- test/files/neg/overloaded-implicit.check | 6 +- test/files/neg/t1909-object.check | 4 +- test/files/neg/t5675.check | 4 +- test/files/neg/t6567.check | 6 +- test/files/neg/unchecked-refinement.check | 6 +- 20 files changed, 268 insertions(+), 193 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/Reporting.scala create mode 100644 src/reflect/scala/reflect/internal/Reporting.scala (limited to 'test') diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 3cd985aeae..05d929b177 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -234,6 +234,14 @@ filter { { matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse" + problemName=MissingTypesProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse.inform" + problemName=MissingMethodProblem } ] } diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala index 88cfea8157..9975bd22a0 100644 --- a/src/compiler/scala/reflect/macros/contexts/Parsers.scala +++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala @@ -9,7 +9,10 @@ trait Parsers { def parse(code: String) = { val sreporter = new StoreReporter() - val unit = new CompilationUnit(newSourceFile(code, "")) { override def reporter = sreporter } + val unit = new CompilationUnit(newSourceFile(code, "")) { + override def reporter = sreporter + override def reporting = new PerRunReporting { override def reporter = sreporter } + } val parser = newUnitParser(unit) val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages()) sreporter.infos.foreach { diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 924bb54ddb..ae1b94dfa1 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -123,32 +123,27 @@ trait CompilationUnits { global: Global => */ val icode: LinkedHashSet[icodes.IClass] = new LinkedHashSet - def reporter = global.reporter + // reporter and its forwarded methods + def reporter = global.reporter + def reporting = currentRun.reporting - def echo(pos: Position, msg: String) = - reporter.echo(pos, msg) + def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg) + def error(pos: Position, msg: String): Unit = reporter.error(pos, msg) + def warning(pos: Position, msg: String): Unit = reporter.warning(pos, msg) - def error(pos: Position, msg: String) = - reporter.error(pos, msg) + def deprecationWarning(pos: Position, msg: String): Unit = reporting.deprecationWarning(pos, msg) + def uncheckedWarning(pos: Position, msg: String): Unit = reporting.uncheckedWarning(pos, msg) + def inlinerWarning(pos: Position, msg: String): Unit = reporting.inlinerWarning(pos, msg) + def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", + required: Boolean): Unit = reporting.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required) - def warning(pos: Position, msg: String) = - reporter.warning(pos, msg) - - def deprecationWarning(pos: Position, msg: String) = - currentRun.deprecationWarnings0.warn(pos, msg) - - def uncheckedWarning(pos: Position, msg: String) = - currentRun.uncheckedWarnings0.warn(pos, msg) - - def inlinerWarning(pos: Position, msg: String) = - currentRun.inlinerWarnings.warn(pos, msg) - - def incompleteInputError(pos: Position, msg:String) = - reporter.incompleteInputError(pos, msg) + // repl + def incompleteHandled: Boolean = reporting.incompleteHandled + def incompleteInputError(pos: Position, msg:String): Unit = reporting.incompleteInputError(pos, msg) // used by the IDE -- TODO: don't use reporter to communicate comments from parser to IDE! - def comment(pos: Position, msg: String): Unit = - reporter.comment(pos, msg) + def comment(pos: Position, msg: String): Unit = reporter.comment(pos, msg) + /** Is this about a .java source file? */ lazy val isJava = source.file.name.endsWith(".java") diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala index 6f068e179c..1f3a4237eb 100644 --- a/src/compiler/scala/tools/nsc/CompileServer.scala +++ b/src/compiler/scala/tools/nsc/CompileServer.scala @@ -7,7 +7,7 @@ package scala.tools.nsc import java.io.PrintStream import scala.tools.nsc.reporters.{Reporter, ConsoleReporter} -import scala.reflect.internal.util.FakePos //Position +import scala.reflect.internal.util.{FakePos, Position} import scala.tools.util.SocketServer import settings.FscSettings @@ -37,7 +37,7 @@ class StandardCompileServer extends SocketServer { /** Create a new compiler instance */ def newGlobal(settings: Settings, reporter: Reporter) = new Global(settings, reporter) { - override def inform(msg: String) = out.println(msg) + override def inform(pos: Position, msg: String) = out.println(msg) } override def timeout() { diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 836203e80d..daf69ffc3f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -44,7 +44,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) with Trees with Printers with DocComments - with Positions { self => + with Positions + with Reporting { self => // the mirror -------------------------------------------------- @@ -227,20 +228,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) */ def registerTopLevelSym(sym: Symbol) {} -// ------------------ Reporting ------------------------------------- - - // not deprecated yet, but a method called "error" imported into - // nearly every trait really must go. For now using globalError. - def error(msg: String) = globalError(msg) - - override def inform(msg: String) = inform(NoPosition, msg) - override def globalError(msg: String) = globalError(NoPosition, msg) - override def warning(msg: String) = warning(NoPosition, msg) - override def deprecationWarning(pos: Position, msg: String) = currentUnit.deprecationWarning(pos, msg) - - def globalError(pos: Position, msg: String) = reporter.error(pos, msg) - def warning(pos: Position, msg: String) = if (settings.fatalWarnings) globalError(pos, msg) else reporter.warning(pos, msg) - def inform(pos: Position, msg: String) = reporter.echo(pos, msg) +// ------------------ Debugging ------------------------------------- // Getting in front of Predef's asserts to supplement with more info. // This has the happy side effect of masking the one argument forms @@ -263,12 +251,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) require(requirement, "") } - // Needs to call error to make sure the compile fails. - override def abort(msg: String): Nothing = { - error(msg) - super.abort(msg) - } - @inline final def ifDebug(body: => Unit) { if (settings.debug) body @@ -1063,6 +1045,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile def currentFreshNameCreator = currentUnit.fresh + def currentReporting = currentRun.reporting def isGlobalInitialized = ( definitions.isDefinitionsInitialized @@ -1110,45 +1093,41 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. */ - override def supplementErrorMessage(errorMessage: String): String = { - if (currentRun.supplementedError) errorMessage - else try { - currentRun.supplementedError = true - val tree = analyzer.lastTreeToTyper - val sym = tree.symbol - val tpe = tree.tpe - val site = lastSeenContext.enclClassOrMethod.owner - val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "" - val context_s = try { - // Taking 3 before, 3 after the fingered line. - val start = 0 max (tree.pos.line - 3) - val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7 - val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" } - strs.mkString("== Source file context for tree position ==\n\n", "\n", "") - } - catch { case t: Exception => devWarning("" + t) ; "" } - - val info1 = formatExplain( - "while compiling" -> currentSource.path, - "during phase" -> ( if (globalPhase eq phase) phase else "globalPhase=%s, enteringPhase=%s".format(globalPhase, phase) ), - "library version" -> scala.util.Properties.versionString, - "compiler version" -> Properties.versionString, - "reconstructed args" -> settings.recreateArgs.mkString(" ") - ) - val info2 = formatExplain( - "last tree to typer" -> tree.summaryString, - "tree position" -> pos_s, - "tree tpe" -> tpe, - "symbol" -> Option(sym).fold("null")(_.debugLocationString), - "symbol definition" -> Option(sym).fold("null")(s => s.defString + s" (a ${s.shortSymbolClass})"), - "symbol package" -> sym.enclosingPackage.fullName, - "symbol owners" -> ownerChainString(sym), - "call site" -> (site.fullLocationString + " in " + site.enclosingPackage) - ) - ("\n " + errorMessage + "\n" + info1) :: info2 :: context_s :: Nil mkString "\n\n" + def supplementTyperState(errorMessage: String): String = try { + val tree = analyzer.lastTreeToTyper + val sym = tree.symbol + val tpe = tree.tpe + val site = lastSeenContext.enclClassOrMethod.owner + val pos_s = if (tree.pos.isDefined) s"line ${tree.pos.line} of ${tree.pos.source.file}" else "" + val context_s = try { + // Taking 3 before, 3 after the fingered line. + val start = 0 max (tree.pos.line - 3) + val xs = scala.reflect.io.File(tree.pos.source.file.file).lines drop start take 7 + val strs = xs.zipWithIndex map { case (line, idx) => f"${start + idx}%6d $line" } + strs.mkString("== Source file context for tree position ==\n\n", "\n", "") } - catch { case _: Exception | _: TypeError => errorMessage } - } + catch { case t: Exception => devWarning("" + t) ; "" } + + val info1 = formatExplain( + "while compiling" -> currentSource.path, + "during phase" -> ( if (globalPhase eq phase) phase else "globalPhase=%s, enteringPhase=%s".format(globalPhase, phase) ), + "library version" -> scala.util.Properties.versionString, + "compiler version" -> Properties.versionString, + "reconstructed args" -> settings.recreateArgs.mkString(" ") + ) + val info2 = formatExplain( + "last tree to typer" -> tree.summaryString, + "tree position" -> pos_s, + "tree tpe" -> tpe, + "symbol" -> Option(sym).fold("null")(_.debugLocationString), + "symbol definition" -> Option(sym).fold("null")(s => s.defString + s" (a ${s.shortSymbolClass})"), + "symbol package" -> sym.enclosingPackage.fullName, + "symbol owners" -> ownerChainString(sym), + "call site" -> (site.fullLocationString + " in " + site.enclosingPackage) + ) + ("\n " + errorMessage + "\n" + info1) :: info2 :: context_s :: Nil mkString "\n\n" + } catch { case _: Exception | _: TypeError => errorMessage } + /** The id of the currently active run */ @@ -1160,19 +1139,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) inform("[running phase " + ph.name + " on " + currentRun.size + " compilation units]") } - /** Collects for certain classes of warnings during this run. */ - class ConditionalWarning(what: String, option: Settings#BooleanSetting) { - val warnings = mutable.LinkedHashMap[Position, String]() - def warn(pos: Position, msg: String) = - if (option) reporter.warning(pos, msg) - else if (!(warnings contains pos)) warnings += ((pos, msg)) - def summarize() = - if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)){ - val warningEvent = if (warnings.size > 1) s"were ${ warnings.size } $what warnings" else s"was one $what warning" - warning(s"there $warningEvent; re-run with ${ option.name } for details") - } - } - def newSourceFile(code: String, filename: String = "") = new BatchSourceFile(filename, code) @@ -1199,38 +1165,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** The currently compiled unit; set from GlobalPhase */ var currentUnit: CompilationUnit = NoCompilationUnit - // This change broke sbt; I gave it the thrilling name of uncheckedWarnings0 so - // as to recover uncheckedWarnings for its ever-fragile compiler interface. - val deprecationWarnings0 = new ConditionalWarning("deprecation", settings.deprecation) - val uncheckedWarnings0 = new ConditionalWarning("unchecked", settings.unchecked) - val featureWarnings = new ConditionalWarning("feature", settings.feature) - val inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings) - val allConditionalWarnings = List(deprecationWarnings0, uncheckedWarnings0, featureWarnings, inlinerWarnings) - - def uncheckedWarnings: List[(Position, String)] = uncheckedWarnings0.warnings.toList // used in sbt - def deprecationWarnings: List[(Position, String)] = deprecationWarnings0.warnings.toList // used in sbt - - def reportAdditionalErrors(): Unit = { - if (!reporter.hasErrors) { - if (reporter.hasWarnings && settings.fatalWarnings) - globalError("No warnings can be incurred under -Xfatal-warnings.") - - allConditionalWarnings foreach (_.summarize()) - - if (seenMacroExpansionsFallingBack) - warning("some macros could not be expanded and code fell back to overridden methods;"+ - "\nrecompiling with generated classfiles on the classpath might help.") - // todo: migrationWarnings - } - } - - var reportedFeature = Set[Symbol]() - - /** Has any macro expansion used a fallback during this run? */ - var seenMacroExpansionsFallingBack = false + val reporting = new PerRunReporting - /** Have we already supplemented the error message of a compiler crash? */ - private[nsc] final var supplementedError = false + // used in sbt + def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings + // used in sbt + def deprecationWarnings: List[(Position, String)] = reporting.deprecationWarnings private class SyncedCompilationBuffer { self => private val underlying = new mutable.ArrayBuffer[CompilationUnit] @@ -1590,7 +1530,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def checkDeprecations() = { checkDeprecatedSettings(newCompilationUnit("")) - reportAdditionalErrors() + reporting.summarizeErrors() } val units = sources map scripted map (new CompilationUnit(_)) @@ -1660,7 +1600,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) advancePhase() } - reportAdditionalErrors() + reporting.summarizeErrors() if (traceSymbolActivity) units map (_.body) foreach (traceSymbols recordSymbolsInTree _) diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala new file mode 100644 index 0000000000..614eb4f212 --- /dev/null +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -0,0 +1,132 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL, Typesafe Inc. + * @author Adriaan Moors + */ + +package scala +package tools +package nsc + +import reporters.{ Reporter, ConsoleReporter } +import scala.collection.{ mutable, immutable } + +trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.api.Symbols => + def settings: Settings + def reporter: Reporter + def currentReporting: PerRunReporting + + def supplementTyperState(errorMessage: String): String + + // not deprecated yet, but a method called "error" imported into + // nearly every trait really must go. For now using globalError. + def error(msg: String) = globalError(msg) + + override def inform(pos: Position, msg: String) = reporter.echo(pos, msg) + override def warning(pos: Position, msg: String) = reporter.warning(pos, msg) + override def globalError(pos: Position, msg: String) = reporter.error(pos, msg) + + override def deprecationWarning(pos: Position, msg: String) = currentReporting.deprecationWarning(pos, msg) + override def supplementErrorMessage(errorMessage: String) = currentReporting.supplementErrorMessage(errorMessage) + + // a new instance of this class is created for every Run (access the current instance via `currentReporting`) + class PerRunReporting { + // NOTE: scala.reflect.macros.Parsers#parse relies on everything related to reporting going through this def... + // TODO: can we rework this to avoid the indirection/fragility? + def reporter = Reporting.this.reporter + + /** Collects for certain classes of warnings during this run. */ + private class ConditionalWarning(what: String, option: Settings#BooleanSetting) { + val warnings = mutable.LinkedHashMap[Position, String]() + def warn(pos: Position, msg: String) = + if (option) reporter.warning(pos, msg) + else if (!(warnings contains pos)) warnings += ((pos, msg)) + def summarize() = + if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)) { + val numWarnings = warnings.size + val warningEvent = // TODO use scala.reflect.internal.util.StringOps.countElementsAsString(numWarnings, s"$what warning") + if (numWarnings > 1) s"were $numWarnings $what warnings" + else s"was one $what warning" + + reporter.warning(NoPosition, s"there $warningEvent; re-run with ${option.name} for details") + } + } + + // This change broke sbt; I gave it the thrilling name of uncheckedWarnings0 so + // as to recover uncheckedWarnings for its ever-fragile compiler interface. + private val _deprecationWarnings = new ConditionalWarning("deprecation", settings.deprecation) + private val _uncheckedWarnings = new ConditionalWarning("unchecked", settings.unchecked) + private val _featureWarnings = new ConditionalWarning("feature", settings.feature) + private val _inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings) + private val _allConditionalWarnings = List(_deprecationWarnings, _uncheckedWarnings, _featureWarnings, _inlinerWarnings) + + def deprecationWarning(pos: Position, msg: String): Unit = _deprecationWarnings.warn(pos, msg) + def uncheckedWarning(pos: Position, msg: String): Unit = _uncheckedWarnings.warn(pos, msg) + def featureWarning(pos: Position, msg: String): Unit = _featureWarnings.warn(pos, msg) + def inlinerWarning(pos: Position, msg: String): Unit = _inlinerWarnings.warn(pos, msg) + + def deprecationWarnings = _deprecationWarnings.warnings.toList + def uncheckedWarnings = _uncheckedWarnings.warnings.toList + def featureWarnings = _featureWarnings.warnings.toList + def inlinerWarnings = _inlinerWarnings.warnings.toList + + def allConditionalWarnings = _allConditionalWarnings flatMap (_.warnings) + + private[this] var reportedFeature = Set[Symbol]() + def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit = { + val req = if (required) "needs to" else "should" + val fqname = "scala.language." + featureName + val explain = ( + if (reportedFeature contains featureTrait) "" else + s"""| + |This can be achieved by adding the import clause 'import $fqname' + |or by setting the compiler option -language:$featureName. + |See the Scala docs for value $fqname for a discussion + |why the feature $req be explicitly enabled.""".stripMargin + ) + reportedFeature += featureTrait + + val msg = s"$featureDesc $req be enabled\nby making the implicit value $fqname visible.$explain" replace ("#", construct) + if (required) reporter.error(pos, msg) + else featureWarning(pos, msg) + } + + /** Has any macro expansion used a fallback during this run? */ + var seenMacroExpansionsFallingBack = false + + def summarizeErrors(): Unit = if (!reporter.hasErrors) { + _allConditionalWarnings foreach (_.summarize()) + + if (seenMacroExpansionsFallingBack) + reporter.warning(NoPosition, "some macros could not be expanded and code fell back to overridden methods;"+ + "\nrecompiling with generated classfiles on the classpath might help.") + + // todo: migrationWarnings + + if (settings.fatalWarnings && reporter.hasWarnings) + reporter.error(NoPosition, "No warnings can be incurred under -Xfatal-warnings.") + } + + // for repl + private[this] var incompleteHandler: (Position, String) => Unit = null + def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = { + val saved = incompleteHandler + incompleteHandler = handler + try thunk + finally incompleteHandler = saved + } + + def incompleteHandled = incompleteHandler != null + def incompleteInputError(pos: Position, msg: String): Unit = + if (incompleteHandled) incompleteHandler(pos, msg) + else reporter.error(pos, msg) + + /** Have we already supplemented the error message of a compiler crash? */ + private[this] var supplementedError = false + def supplementErrorMessage(errorMessage: String): String = + if (supplementedError) errorMessage + else { + supplementedError = true + supplementTyperState(errorMessage) + } + } +} \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 3a695c6f59..3d8a7d2e55 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -83,7 +83,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse private def initialUnitBody(unit: CompilationUnit): Tree = { if (unit.isJava) new JavaUnitParser(unit).parse() - else if (global.reporter.incompleteHandled) newUnitParser(unit).parse() + else if (unit.incompleteHandled) newUnitParser(unit).parse() else newUnitParser(unit).smartParse() } diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index 1a8794d217..b617e7b530 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -53,15 +53,6 @@ abstract class Reporter { override def toString: String = "ERROR" } - private var incompleteHandler: (Position, String) => Unit = null - def incompleteHandled = incompleteHandler != null - def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = { - val saved = incompleteHandler - incompleteHandler = handler - try thunk - finally incompleteHandler = saved - } - // used by sbt (via unit.cancel) to cancel a compile (see hasErrors) var cancelled: Boolean = false @@ -71,12 +62,6 @@ abstract class Reporter { // overridden by sbt def hasWarnings: Boolean = WARNING.count > 0 - // TODO - def incompleteInputError(pos: Position, msg: String): Unit = { - if (incompleteHandled) incompleteHandler(pos, msg) - else error(pos, msg) - } - // overridden by sbt, IDE -- should move out of this interface // it's unrelated to reporting (IDE receives comments from ScaladocAnalyzer) def comment(pos: Position, msg: String): Unit = {} diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index ef74beec62..9c22688581 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -714,7 +714,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers { sealed abstract class MacroStatus(val result: Tree) case class Success(expanded: Tree) extends MacroStatus(expanded) - case class Fallback(fallback: Tree) extends MacroStatus(fallback) { currentRun.seenMacroExpansionsFallingBack = true } + case class Fallback(fallback: Tree) extends MacroStatus(fallback) { currentRun.reporting.seenMacroExpansionsFallingBack = true } case class Delayed(delayed: Tree) extends MacroStatus(delayed) case class Skipped(skipped: Tree) extends MacroStatus(skipped) case class Failure(failure: Tree) extends MacroStatus(failure) @@ -788,7 +788,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers { } } catch { case ex: Throwable => - popMacroContext() + if (openMacros.nonEmpty) popMacroContext() // weirdly we started popping on an empty stack when refactoring fatalWarnings logic val realex = ReflectionUtils.unwrapThrowable(ex) realex match { case ex: AbortMacroException => MacroGeneratedAbort(expandee, ex) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9a4d5e3c06..059b58c943 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -746,21 +746,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (!OK) { val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) = featureTrait getAnnotation LanguageFeatureAnnot - val req = if (required) "needs to" else "should" - val fqname = "scala.language." + featureName - val explain = ( - if (currentRun.reportedFeature contains featureTrait) "" else - s"""| - |This can be achieved by adding the import clause 'import $fqname' - |or by setting the compiler option -language:$featureName. - |See the Scala docs for value $fqname for a discussion - |why the feature $req be explicitly enabled.""".stripMargin - ) - currentRun.reportedFeature += featureTrait - - val msg = s"$featureDesc $req be enabled\nby making the implicit value $fqname visible.$explain" replace ("#", construct) - if (required) unit.error(pos, msg) - else currentRun.featureWarnings.warn(pos, msg) + unit.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required) } OK } diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index 01fba1efc1..c16d8778d9 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/src/reflect/scala/reflect/internal/Positions.scala @@ -23,13 +23,10 @@ import scala.collection.mutable.ListBuffer * Otherwise, the singleton consisting of the node itself. */ trait Positions extends api.Positions { self: SymbolTable => - type Position = scala.reflect.internal.util.Position val NoPosition = scala.reflect.internal.util.NoPosition implicit val PositionTag = ClassTag[Position](classOf[Position]) - def inform(msg: String): Unit - def useOffsetPositions: Boolean = true /** A position that wraps a set of trees. @@ -100,7 +97,7 @@ trait Positions extends api.Positions { self: SymbolTable => inform("\nWhile validating #" + tree.id) inform(treeStatus(tree)) inform("\nChildren:") - tree.children map (t => " " + treeStatus(t, tree)) foreach inform + tree.children foreach (t => inform(" " + treeStatus(t, tree))) inform("=======") throw new ValidateException(msg) } @@ -109,7 +106,7 @@ trait Positions extends api.Positions { self: SymbolTable => if (!tree.isEmpty && tree.canHaveAttrs) { if (settings.Yposdebug && (settings.verbose || settings.Yrangepos)) - println("[%10s] %s".format("validate", treeStatus(tree, encltree))) + inform("[%10s] %s".format("validate", treeStatus(tree, encltree))) if (!tree.pos.isDefined) positionError("Unpositioned tree #"+tree.id) { @@ -176,7 +173,7 @@ trait Positions extends api.Positions { self: SymbolTable => case r :: rs1 => assert(!t.pos.isTransparent) if (r.isFree && (r.pos includes t.pos)) { -// println("subdividing "+r+"/"+t.pos) +// inform("subdividing "+r+"/"+t.pos) maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1 } else { if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree @@ -225,7 +222,7 @@ trait Positions extends api.Positions { self: SymbolTable => } } catch { case ex: Exception => - println("error while set children pos "+pos+" of "+trees) + inform("error while set children pos "+pos+" of "+trees) throw ex } diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala new file mode 100644 index 0000000000..e88e765750 --- /dev/null +++ b/src/reflect/scala/reflect/internal/Reporting.scala @@ -0,0 +1,32 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL, Typesafe Inc. + * @author Adriaan Moors + */ + +package scala +package reflect +package internal + +trait Reporting { self : Positions => + def inform(msg: String): Unit = inform(NoPosition, msg) + def warning(msg: String): Unit = warning(NoPosition, msg) + // globalError(msg: String) used to abort -- not sure that was a good idea, so I made it more regular + // (couldn't find any uses that relied on old behavior) + def globalError(msg: String): Unit = globalError(NoPosition, msg) + + def abort(msg: String): Nothing = { + val augmented = supplementErrorMessage(msg) + // Needs to call error to make sure the compile fails. + globalError(augmented) + throw new FatalError(augmented) + } + + def inform(pos: Position, msg: String) = Console.out.println(msg) + def warning(pos: Position, msg: String) = Console.err.println(msg) + def globalError(pos: Position, msg: String) = Console.err.println(msg) + + def deprecationWarning(pos: Position, msg: String): Unit = warning(msg) + + /** Overridden when we know more about what was happening during a failure. */ + def supplementErrorMessage(msg: String): String = msg +} \ No newline at end of file diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index c76dedbff4..ed5c68fe82 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -46,16 +46,12 @@ abstract class SymbolTable extends macros.Universe with pickling.Translations with FreshNames with Internals + with Reporting { val gen = new InternalTreeGen { val global: SymbolTable.this.type = SymbolTable.this } def log(msg: => AnyRef): Unit - def deprecationWarning(pos: Position, msg: String): Unit = warning(msg) - def warning(msg: String): Unit = Console.err.println(msg) - def inform(msg: String): Unit = Console.err.println(msg) - def globalError(msg: String): Unit = abort(msg) - def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg)) protected def elapsedMessage(msg: String, start: Long) = msg + " in " + (TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start) + "ms" @@ -82,9 +78,6 @@ abstract class SymbolTable extends macros.Universe /** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */ def debugStack(t: Throwable): Unit = devWarning(throwableAsString(t)) - /** Overridden when we know more about what was happening during a failure. */ - def supplementErrorMessage(msg: String): String = msg - private[scala] def printCaller[T](msg: String)(result: T) = { Console.err.println("%s: %s\nCalled from: %s".format(msg, result, (new Throwable).getStackTrace.drop(2).take(50).mkString("\n"))) diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 2deeed2be3..8ea8759ee5 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -793,7 +793,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } ((pos, msg)) :: loop(filtered) } - val warnings = loop(run.allConditionalWarnings flatMap (_.warnings)) + val warnings = loop(run.reporting.allConditionalWarnings) if (warnings.nonEmpty) mostRecentWarnings = warnings } @@ -1121,7 +1121,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def apply(line: String): Result = debugging(s"""parse("$line")""") { var isIncomplete = false - reporter.withIncompleteHandler((_, _) => isIncomplete = true) { + currentRun.reporting.withIncompleteHandler((_, _) => isIncomplete = true) { reporter.reset() val trees = newUnitParser(line).parseStats() if (reporter.hasErrors) Error diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index 38cc5ec447..1b53fa5fb9 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -97,7 +97,7 @@ checksensible.scala:84: warning: comparing values of types EqEqRefTest.this.C3 a checksensible.scala:95: warning: comparing values of types Unit and Int using `!=' will always yield true while ((c = in.read) != -1) ^ +warning: there were 3 deprecation warnings; re-run with -deprecation for details error: No warnings can be incurred under -Xfatal-warnings. -error: there were 3 deprecation warnings; re-run with -deprecation for details -33 warnings found -two errors found +34 warnings found +one error found diff --git a/test/files/neg/overloaded-implicit.check b/test/files/neg/overloaded-implicit.check index d9594d126a..5cf6ac528b 100644 --- a/test/files/neg/overloaded-implicit.check +++ b/test/files/neg/overloaded-implicit.check @@ -4,7 +4,7 @@ overloaded-implicit.scala:2: warning: parameterized overloaded implicit methods overloaded-implicit.scala:3: warning: parameterized overloaded implicit methods are not visible as view bounds implicit def imp1[T](x: Set[T]): Map[T, T] = Map() ^ +warning: there were 4 feature warnings; re-run with -feature for details error: No warnings can be incurred under -Xfatal-warnings. -error: there were 4 feature warnings; re-run with -feature for details -two warnings found -two errors found +three warnings found +one error found diff --git a/test/files/neg/t1909-object.check b/test/files/neg/t1909-object.check index 401c1f7ebf..7141c84d4b 100644 --- a/test/files/neg/t1909-object.check +++ b/test/files/neg/t1909-object.check @@ -1,4 +1,6 @@ -t1909-object.scala:4: error: !!! SI-1909 Unable to STATICally lift object InnerTrouble$1, which is defined in the self- or super-constructor call of class Kaboom. A VerifyError is likely. +t1909-object.scala:4: warning: !!! SI-1909 Unable to STATICally lift object InnerTrouble$1, which is defined in the self- or super-constructor call of class Kaboom. A VerifyError is likely. object InnerTrouble ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found one error found diff --git a/test/files/neg/t5675.check b/test/files/neg/t5675.check index 13226935dc..3b3b2fa04c 100644 --- a/test/files/neg/t5675.check +++ b/test/files/neg/t5675.check @@ -1,2 +1,4 @@ -error: there was one feature warning; re-run with -feature for details +warning: there was one feature warning; re-run with -feature for details +error: No warnings can be incurred under -Xfatal-warnings. +one warning found one error found diff --git a/test/files/neg/t6567.check b/test/files/neg/t6567.check index 3243fde0cd..f42f157371 100644 --- a/test/files/neg/t6567.check +++ b/test/files/neg/t6567.check @@ -4,7 +4,7 @@ t6567.scala:8: warning: Suspicious application of an implicit view (Test.this.a2 t6567.scala:10: warning: Suspicious application of an implicit view (Test.this.a2b) in the argument to Option.apply. val b: Option[B] = Option(a) ^ +warning: there was one feature warning; re-run with -feature for details error: No warnings can be incurred under -Xfatal-warnings. -error: there was one feature warning; re-run with -feature for details -two warnings found -two errors found +three warnings found +one error found diff --git a/test/files/neg/unchecked-refinement.check b/test/files/neg/unchecked-refinement.check index b49e47fcbb..0bb944621b 100644 --- a/test/files/neg/unchecked-refinement.check +++ b/test/files/neg/unchecked-refinement.check @@ -10,7 +10,7 @@ unchecked-refinement.scala:23: warning: a pattern match on a refinement type is unchecked-refinement.scala:24: warning: a pattern match on a refinement type is unchecked /* nowarn - todo */ case x: AnyRef { def size: Int } if b => x.size // this could/should do a static conformance test and not warn ^ +warning: there was one feature warning; re-run with -feature for details error: No warnings can be incurred under -Xfatal-warnings. -error: there was one feature warning; re-run with -feature for details -four warnings found -two errors found +5 warnings found +one error found -- cgit v1.2.3 From 62c8f90f3105b8f19a9f29f104ff232438372c73 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Sat, 14 Jun 2014 00:38:30 +0200 Subject: Uniformly route reporting through reporter. Sharpen interfaces, reduce footprint of Reporting trait. Ideally, all reporting should indirect through reporter, and the `Reporting` trait itself should be restricted to a single method that retrieves the current `reporter`. Pull up some more reporting to reflect.internal. Would like to do more, but need to move partest to the reflect.internal interface first. (Its `errorCount` relies on `ERROR.count` in `tools.nsc.Reporter`.) --- bincompat-forward.whitelist.conf | 2 +- src/compiler/scala/tools/nsc/Reporting.scala | 12 ++-- .../tools/nsc/reporters/AbstractReporter.scala | 11 ++-- .../scala/tools/nsc/reporters/Reporter.scala | 69 +++++++++------------- src/reflect/scala/reflect/internal/Reporting.scala | 65 ++++++++++++++++++-- .../scala/reflect/runtime/JavaUniverse.scala | 10 +++- .../nsc/symtab/SymbolTableForUnitTesting.scala | 5 ++ 7 files changed, 116 insertions(+), 58 deletions(-) (limited to 'test') diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index 05d929b177..dbf0807999 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -240,7 +240,7 @@ filter { problemName=MissingTypesProblem }, { - matchName="scala.reflect.runtime.JavaUniverse.inform" + matchName="scala.reflect.runtime.JavaUniverse.reporter" problemName=MissingMethodProblem } ] diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index 614eb4f212..a8fd3bec76 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -10,9 +10,15 @@ package nsc import reporters.{ Reporter, ConsoleReporter } import scala.collection.{ mutable, immutable } +/** Provides delegates to the reporter doing the actual work. + * PerRunReporting implements per-Run stateful info tracking and reporting + * + * TODO: make reporting configurable + */ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.api.Symbols => def settings: Settings - def reporter: Reporter + + // == currentRun.reporting def currentReporting: PerRunReporting def supplementTyperState(errorMessage: String): String @@ -21,10 +27,6 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w // nearly every trait really must go. For now using globalError. def error(msg: String) = globalError(msg) - override def inform(pos: Position, msg: String) = reporter.echo(pos, msg) - override def warning(pos: Position, msg: String) = reporter.warning(pos, msg) - override def globalError(pos: Position, msg: String) = reporter.error(pos, msg) - override def deprecationWarning(pos: Position, msg: String) = currentReporting.deprecationWarning(pos, msg) override def supplementErrorMessage(errorMessage: String) = currentReporting.supplementErrorMessage(errorMessage) diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index 16d432438a..6c592ead0d 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -62,12 +62,13 @@ abstract class AbstractReporter extends Reporter { */ private def testAndLog(pos: Position, severity: Severity, msg: String): Boolean = pos != null && pos.isDefined && { - val fpos = pos.focus + val fpos = pos.focus val suppress = positions(fpos) match { - case ERROR => true // already error at position - case highest if highest > severity => true // already message higher than present severity - case `severity` => messages(fpos) contains msg // already issued this exact message - case _ => false // good to go + case ERROR => true // already error at position + case highest + if highest.id > severity.id => true // already message higher than present severity + case `severity` => messages(fpos) contains msg // already issued this exact message + case _ => false // good to go } suppress || { diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index b617e7b530..5b576a547d 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -10,59 +10,48 @@ import scala.reflect.internal.util._ /** Report information, warnings and errors. * - * This describes the stable interface for issuing information, warnings and errors. + * This describes the internal interface for issuing information, warnings and errors. * The only abstract method in this class must be info0. + * + * TODO: Move external clients (sbt/ide/partest) to reflect.internal.Reporter + * This interface should be considered private to the compiler. */ -abstract class Reporter { - protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit - +abstract class Reporter extends scala.reflect.internal.Reporter { /** Informational messages. If `!force`, they may be suppressed. */ final def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) /** For sending a message which should not be labeled as a warning/error, * but also shouldn't require -verbose to be visible. */ - def echo(msg: String): Unit = info(NoPosition, msg, force = true) - def echo(pos: Position, msg: String): Unit = info(pos, msg, force = true) - - /** Warnings and errors. */ - def warning(pos: Position, msg: String): Unit = info0(pos, msg, WARNING, force = false) - def error(pos: Position, msg: String): Unit = info0(pos, msg, ERROR, force = false) - - def flush(): Unit = { } + def echo(msg: String): Unit = info(NoPosition, msg, force = true) - // overridden by sbt, IDE - def reset(): Unit = { - INFO.count = 0 - WARNING.count = 0 - ERROR.count = 0 - cancelled = false - } - - object severity extends Enumeration - class Severity(val id: Int) extends severity.Value { - var count: Int = 0 - } - val INFO = new Severity(0) { - override def toString: String = "INFO" - } - val WARNING = new Severity(1) { - override def toString: String = "WARNING" - } - val ERROR = new Severity(2) { - override def toString: String = "ERROR" - } + // overridden by sbt, IDE -- should not be in the reporting interface + // (IDE receives comments from ScaladocAnalyzer using this hook method) + // TODO: IDE should override a hook method in the parser instead + def comment(pos: Position, msg: String): Unit = {} // used by sbt (via unit.cancel) to cancel a compile (see hasErrors) + // TODO: figure out how sbt uses this, come up with a separate interface for controlling the build var cancelled: Boolean = false - // overridden by sbt - def hasErrors: Boolean = ERROR.count > 0 || cancelled + override def hasErrors: Boolean = super.hasErrors || cancelled - // overridden by sbt - def hasWarnings: Boolean = WARNING.count > 0 + override def reset(): Unit = { + super.reset() + cancelled = false + } - // overridden by sbt, IDE -- should move out of this interface - // it's unrelated to reporting (IDE receives comments from ScaladocAnalyzer) - def comment(pos: Position, msg: String): Unit = {} + // the below is copy/pasted from ReporterImpl for now + // partest expects this inner class + // TODO: rework partest to use the scala.reflect.internal interface, + // remove duplication here, and consolidate reflect.internal.{ReporterImpl & ReporterImpl} + class Severity(val id: Int)(name: String) { var count: Int = 0 ; override def toString = name} + object INFO extends Severity(0)("INFO") + object WARNING extends Severity(1)("WARNING") + // reason for copy/paste: this is used by partest (must be a val, not an object) + // TODO: use count(ERROR) in scala.tools.partest.nest.DirectCompiler#errorCount, rather than ERROR.count + lazy val ERROR = new Severity(2)("ERROR") + + def count(severity: Severity): Int = severity.count + def resetCount(severity: Severity): Unit = severity.count = 0 } diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala index e88e765750..baeed1357d 100644 --- a/src/reflect/scala/reflect/internal/Reporting.scala +++ b/src/reflect/scala/reflect/internal/Reporting.scala @@ -7,11 +7,20 @@ package scala package reflect package internal +/** Provides delegates to the reporter doing the actual work. + * All forwarding methods should be marked final, + * but some subclasses out of our reach stil override them. + */ trait Reporting { self : Positions => + def reporter: Reporter + + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def inform(msg: String): Unit = inform(NoPosition, msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def warning(msg: String): Unit = warning(NoPosition, msg) // globalError(msg: String) used to abort -- not sure that was a good idea, so I made it more regular // (couldn't find any uses that relied on old behavior) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def globalError(msg: String): Unit = globalError(NoPosition, msg) def abort(msg: String): Nothing = { @@ -21,12 +30,60 @@ trait Reporting { self : Positions => throw new FatalError(augmented) } - def inform(pos: Position, msg: String) = Console.out.println(msg) - def warning(pos: Position, msg: String) = Console.err.println(msg) - def globalError(pos: Position, msg: String) = Console.err.println(msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") + def inform(pos: Position, msg: String) = reporter.echo(pos, msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") + def warning(pos: Position, msg: String) = reporter.warning(pos, msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") + def globalError(pos: Position, msg: String) = reporter.error(pos, msg) def deprecationWarning(pos: Position, msg: String): Unit = warning(msg) /** Overridden when we know more about what was happening during a failure. */ def supplementErrorMessage(msg: String): String = msg -} \ No newline at end of file +} + +import util.Position + +/** Report information, warnings and errors. + * + * This describes the (future) external interface for issuing information, warnings and errors. + * Currently, scala.tools.nsc.Reporter is used by sbt/ide/partest. + */ +abstract class Reporter { + protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit + + def echo(pos: Position, msg: String): Unit = info0(pos, msg, INFO, force = true) + def warning(pos: Position, msg: String): Unit = info0(pos, msg, WARNING, force = false) + def error(pos: Position, msg: String): Unit = info0(pos, msg, ERROR, force = false) + + type Severity + val INFO: Severity + val WARNING: Severity + val ERROR: Severity + + def count(severity: Severity): Int + def resetCount(severity: Severity): Unit + + def hasErrors: Boolean = count(ERROR) > 0 + def hasWarnings: Boolean = count(WARNING) > 0 + + def reset(): Unit = { + resetCount(INFO) + resetCount(WARNING) + resetCount(ERROR) + } + + def flush(): Unit = { } +} + +// TODO: move into superclass once partest cuts tie on Severity +abstract class ReporterImpl extends Reporter { + class Severity(val id: Int)(name: String) { var count: Int = 0 ; override def toString = name} + object INFO extends Severity(0)("INFO") + object WARNING extends Severity(1)("WARNING") + object ERROR extends Severity(2)("ERROR") + + def count(severity: Severity): Int = severity.count + def resetCount(severity: Severity): Unit = severity.count = 0 +} diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index b5446694ed..d846ef2cdd 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -14,15 +14,19 @@ import scala.reflect.api.{TreeCreator, TypeCreator, Universe} * @contentDiagram hideNodes "*Api" "*Extractor" */ class JavaUniverse extends InternalSymbolTable with JavaUniverseForce with ReflectSetup with RuntimeSymbolTable { self => - - override def inform(msg: String): Unit = log(msg) def picklerPhase = SomePhase def erasurePhase = SomePhase lazy val settings = new Settings - private val isLogging = sys.props contains "scala.debug.reflect" + private val isLogging = sys.props contains "scala.debug.reflect" def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) + // TODO: why put output under isLogging? Calls to inform are already conditional on debug/verbose/... + import scala.reflect.internal.{Reporter, ReporterImpl} + override def reporter: Reporter = new ReporterImpl { + protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = log(msg) + } + type TreeCopier = InternalTreeCopierOps implicit val TreeCopierTag: ClassTag[TreeCopier] = ClassTag[TreeCopier](classOf[TreeCopier]) def newStrictTreeCopier: TreeCopier = new StrictTreeCopier diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index 25d8c4667f..6b87a99e6f 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -72,6 +72,11 @@ class SymbolTableForUnitTesting extends SymbolTable { def picklerPhase: scala.reflect.internal.Phase = SomePhase def erasurePhase: scala.reflect.internal.Phase = SomePhase + // Members declared in scala.reflect.internal.Reporting + def reporter = new scala.reflect.internal.ReporterImpl { + protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = println(msg) + } + // Members declared in scala.reflect.internal.SymbolTable def currentRunId: Int = 1 def log(msg: => AnyRef): Unit = println(msg) -- cgit v1.2.3 From 9fc68e19309cef139c4827fbed76952011995e10 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 24 Jun 2014 15:54:10 +0200 Subject: Remove deprecationWarning, currentReporting from Reporting This moves us a bit closer to the goal of having a single entry point to reporting. Must modularize Reporting a bit so it can be used in Variances (need a reference to `currentRun` in `reflect.internal.Reporting`). --- bincompat-forward.whitelist.conf | 12 +++++++++ src/compiler/scala/tools/nsc/Global.scala | 7 ++--- src/compiler/scala/tools/nsc/Reporting.scala | 25 +++-------------- src/reflect/scala/reflect/internal/Reporting.scala | 31 ++++++++++++++++++---- src/reflect/scala/reflect/internal/Variances.scala | 2 +- .../scala/reflect/runtime/JavaUniverse.scala | 8 ++++++ .../nsc/symtab/SymbolTableForUnitTesting.scala | 7 +++++ 7 files changed, 59 insertions(+), 33 deletions(-) (limited to 'test') diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf index dbf0807999..30dac79974 100644 --- a/bincompat-forward.whitelist.conf +++ b/bincompat-forward.whitelist.conf @@ -242,6 +242,18 @@ filter { { matchName="scala.reflect.runtime.JavaUniverse.reporter" problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse$PerRunReporting" + problemName=MissingClassProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse.currentRun" + problemName=MissingMethodProblem + }, + { + matchName="scala.reflect.runtime.JavaUniverse.PerRunReporting" + problemName=MissingMethodProblem } ] } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index a6fa3bf1dc..572e579aca 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1045,7 +1045,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile def currentFreshNameCreator = currentUnit.fresh - def currentReporting = currentRun.reporting def isGlobalInitialized = ( definitions.isDefinitionsInitialized @@ -1093,7 +1092,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. */ - def supplementTyperState(errorMessage: String): String = try { + override def supplementTyperState(errorMessage: String): String = try { val tree = analyzer.lastTreeToTyper val sym = tree.symbol val tpe = tree.tpe @@ -1156,7 +1155,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** A Run is a single execution of the compiler on a set of units. */ - class Run extends RunContextApi { + class Run extends RunContextApi with RunReporting { /** Have been running into too many init order issues with Run * during erroneous conditions. Moved all these vals up to the * top of the file so at least they're not trivially null. @@ -1165,8 +1164,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) /** The currently compiled unit; set from GlobalPhase */ var currentUnit: CompilationUnit = NoCompilationUnit - val reporting = new PerRunReporting - // used in sbt def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings // used in sbt diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index 1b5a778235..9a20807145 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -18,24 +18,13 @@ import scala.collection.{ mutable, immutable } trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.api.Symbols => def settings: Settings - // == currentRun.reporting - def currentReporting: PerRunReporting - - def supplementTyperState(errorMessage: String): String - // not deprecated yet, but a method called "error" imported into // nearly every trait really must go. For now using globalError. def error(msg: String) = globalError(msg) - override def deprecationWarning(pos: Position, msg: String) = currentReporting.deprecationWarning(pos, msg) - override def supplementErrorMessage(errorMessage: String) = currentReporting.supplementErrorMessage(errorMessage) - - // a new instance of this class is created for every Run (access the current instance via `currentReporting`) - class PerRunReporting { - // NOTE: scala.reflect.macros.Parsers#parse relies on everything related to reporting going through this def... - // TODO: can we rework this to avoid the indirection/fragility? - def reporter = Reporting.this.reporter - + // a new instance of this class is created for every Run (access the current instance via `currentRun.reporting`) + protected def PerRunReporting = new PerRunReporting + class PerRunReporting extends PerRunReportingBase { /** Collects for certain classes of warnings during this run. */ private class ConditionalWarning(what: String, option: Settings#BooleanSetting) { val warnings = mutable.LinkedHashMap[Position, String]() @@ -126,13 +115,5 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w if (incompleteHandled) incompleteHandler(pos, msg) else reporter.error(pos, msg) - /** Have we already supplemented the error message of a compiler crash? */ - private[this] var supplementedError = false - def supplementErrorMessage(errorMessage: String): String = - if (supplementedError) errorMessage - else { - supplementedError = true - supplementTyperState(errorMessage) - } } } \ No newline at end of file diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala index 0670e9bd8e..423127803e 100644 --- a/src/reflect/scala/reflect/internal/Reporting.scala +++ b/src/reflect/scala/reflect/internal/Reporting.scala @@ -16,6 +16,32 @@ package internal */ trait Reporting { self : Positions => def reporter: Reporter + def currentRun: RunReporting + + trait RunReporting { + val reporting: PerRunReporting = PerRunReporting + } + + type PerRunReporting <: PerRunReportingBase + protected def PerRunReporting: PerRunReporting + abstract class PerRunReportingBase { + def deprecationWarning(pos: Position, msg: String): Unit + + /** Have we already supplemented the error message of a compiler crash? */ + private[this] var supplementedError = false + def supplementErrorMessage(errorMessage: String): String = + if (supplementedError) errorMessage + else { + supplementedError = true + supplementTyperState(errorMessage) + } + + } + + // overridden in Global + def supplementTyperState(errorMessage: String): String = errorMessage + + def supplementErrorMessage(errorMessage: String) = currentRun.reporting.supplementErrorMessage(errorMessage) @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def inform(msg: String): Unit = inform(NoPosition, msg) @@ -39,11 +65,6 @@ trait Reporting { self : Positions => def warning(pos: Position, msg: String) = reporter.warning(pos, msg) @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def globalError(pos: Position, msg: String) = reporter.error(pos, msg) - - def deprecationWarning(pos: Position, msg: String): Unit = warning(msg) - - /** Overridden when we know more about what was happening during a failure. */ - def supplementErrorMessage(msg: String): String = msg } import util.Position diff --git a/src/reflect/scala/reflect/internal/Variances.scala b/src/reflect/scala/reflect/internal/Variances.scala index cfe2ad8b87..12b765b7a6 100644 --- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -79,7 +79,7 @@ trait Variances { // Unsound pre-2.11 behavior preserved under -Xsource:2.10 if (settings.isScala211 || sym.isOverridingSymbol) Invariant else { - deprecationWarning(sym.pos, s"Construct depends on unsound variance analysis and will not compile in scala 2.11 and beyond") + currentRun.reporting.deprecationWarning(sym.pos, s"Construct depends on unsound variance analysis and will not compile in scala 2.11 and beyond") Bivariant } ) diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index d846ef2cdd..fe39e1f245 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -27,6 +27,14 @@ class JavaUniverse extends InternalSymbolTable with JavaUniverseForce with Refle protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = log(msg) } + // minimal Run to get Reporting wired + def currentRun = new RunReporting {} + class PerRunReporting extends PerRunReportingBase { + def deprecationWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg) + } + protected def PerRunReporting = new PerRunReporting + + type TreeCopier = InternalTreeCopierOps implicit val TreeCopierTag: ClassTag[TreeCopier] = ClassTag[TreeCopier](classOf[TreeCopier]) def newStrictTreeCopier: TreeCopier = new StrictTreeCopier diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index 6b87a99e6f..91868a5683 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -77,6 +77,13 @@ class SymbolTableForUnitTesting extends SymbolTable { protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = println(msg) } + // minimal Run to get Reporting wired + def currentRun = new RunReporting {} + class PerRunReporting extends PerRunReportingBase { + def deprecationWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg) + } + protected def PerRunReporting = new PerRunReporting + // Members declared in scala.reflect.internal.SymbolTable def currentRunId: Int = 1 def log(msg: => AnyRef): Unit = println(msg) -- cgit v1.2.3 From b384d5070f86e9003e8f1b57cc818520033242ab Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 3 Jul 2014 13:40:55 +0200 Subject: Use countElementsAsString for summarized warnings. --- src/compiler/scala/tools/nsc/Reporting.scala | 8 ++++---- test/files/jvm/deprecation.check | 2 +- test/files/jvm/serialization-new.check | 2 +- test/files/jvm/serialization.check | 2 +- test/files/neg/checksensible.check | 2 +- test/files/neg/overloaded-implicit.check | 2 +- test/files/run/colltest.check | 2 +- test/files/run/inferred-type-constructors.check | 2 +- test/files/run/names-defaults.check | 2 +- test/files/run/richs.check | 2 +- test/files/run/t2212.check | 2 +- test/files/run/t3996.check | 2 +- test/files/run/t4080.check | 2 +- test/files/run/t4461.check | 2 +- test/files/run/t4813.check | 2 +- test/files/run/t6111.check | 2 +- test/files/run/t6690.check | 2 +- test/files/run/t6863.check | 2 +- test/files/run/t8196.check | 2 +- test/files/run/t8549.check | 2 +- 20 files changed, 23 insertions(+), 23 deletions(-) (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index bc27afb0c5..0263586418 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -9,6 +9,7 @@ package nsc import reporters.{ Reporter, ConsoleReporter } import scala.collection.{ mutable, immutable } +import scala.reflect.internal.util.StringOps.countElementsAsString /** Provides delegates to the reporter doing the actual work. * PerRunReporting implements per-Run stateful info tracking and reporting @@ -34,11 +35,10 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w def summarize() = if (warnings.nonEmpty && (option.isDefault || settings.fatalWarnings)) { val numWarnings = warnings.size - val warningEvent = // TODO use scala.reflect.internal.util.StringOps.countElementsAsString(numWarnings, s"$what warning") - if (numWarnings > 1) s"were $numWarnings $what warnings" - else s"was one $what warning" + val warningVerb = if (numWarnings == 1) "was" else "were" + val warningCount = countElementsAsString(numWarnings, s"$what warning") - reporter.warning(NoPosition, s"there $warningEvent; re-run with ${option.name} for details") + reporter.warning(NoPosition, s"there $warningVerb $warningCount; re-run with ${option.name} for details") } } diff --git a/test/files/jvm/deprecation.check b/test/files/jvm/deprecation.check index 3c27d4d082..d57b6b55a5 100644 --- a/test/files/jvm/deprecation.check +++ b/test/files/jvm/deprecation.check @@ -1,3 +1,3 @@ -warning: there were 4 deprecation warnings; re-run with -deprecation for details +warning: there were four deprecation warnings; re-run with -deprecation for details Note: deprecation/Use_2.java uses or overrides a deprecated API. Note: Recompile with -Xlint:deprecation for details. diff --git a/test/files/jvm/serialization-new.check b/test/files/jvm/serialization-new.check index 8ec5754ea2..1555135926 100644 --- a/test/files/jvm/serialization-new.check +++ b/test/files/jvm/serialization-new.check @@ -1,4 +1,4 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details a1 = Array[1,2,3] _a1 = Array[1,2,3] arrayEquals(a1, _a1): true diff --git a/test/files/jvm/serialization.check b/test/files/jvm/serialization.check index 8ec5754ea2..1555135926 100644 --- a/test/files/jvm/serialization.check +++ b/test/files/jvm/serialization.check @@ -1,4 +1,4 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details a1 = Array[1,2,3] _a1 = Array[1,2,3] arrayEquals(a1, _a1): true diff --git a/test/files/neg/checksensible.check b/test/files/neg/checksensible.check index 1b53fa5fb9..7de22fef54 100644 --- a/test/files/neg/checksensible.check +++ b/test/files/neg/checksensible.check @@ -97,7 +97,7 @@ checksensible.scala:84: warning: comparing values of types EqEqRefTest.this.C3 a checksensible.scala:95: warning: comparing values of types Unit and Int using `!=' will always yield true while ((c = in.read) != -1) ^ -warning: there were 3 deprecation warnings; re-run with -deprecation for details +warning: there were three deprecation warnings; re-run with -deprecation for details error: No warnings can be incurred under -Xfatal-warnings. 34 warnings found one error found diff --git a/test/files/neg/overloaded-implicit.check b/test/files/neg/overloaded-implicit.check index 5cf6ac528b..0e6617d904 100644 --- a/test/files/neg/overloaded-implicit.check +++ b/test/files/neg/overloaded-implicit.check @@ -4,7 +4,7 @@ overloaded-implicit.scala:2: warning: parameterized overloaded implicit methods overloaded-implicit.scala:3: warning: parameterized overloaded implicit methods are not visible as view bounds implicit def imp1[T](x: Set[T]): Map[T, T] = Map() ^ -warning: there were 4 feature warnings; re-run with -feature for details +warning: there were four feature warnings; re-run with -feature for details error: No warnings can be incurred under -Xfatal-warnings. three warnings found one error found diff --git a/test/files/run/colltest.check b/test/files/run/colltest.check index 46e4017eb6..9579d781aa 100644 --- a/test/files/run/colltest.check +++ b/test/files/run/colltest.check @@ -1,4 +1,4 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details true false true diff --git a/test/files/run/inferred-type-constructors.check b/test/files/run/inferred-type-constructors.check index 67075a59a9..4a63853bd9 100644 --- a/test/files/run/inferred-type-constructors.check +++ b/test/files/run/inferred-type-constructors.check @@ -1,4 +1,4 @@ -warning: there were 2 feature warnings; re-run with -feature for details +warning: there were two feature warnings; re-run with -feature for details p.Iterable[Int] p.Set[Int] p.Seq[Int] diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check index 97cfa4e520..25999c488a 100644 --- a/test/files/run/names-defaults.check +++ b/test/files/run/names-defaults.check @@ -1,7 +1,7 @@ names-defaults.scala:269: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses spawn(b = { val ttt = 1; ttt }, a = 0) ^ -warning: there were 4 deprecation warnings; re-run with -deprecation for details +warning: there were four deprecation warnings; re-run with -deprecation for details 1: @ get: $ get: 2 diff --git a/test/files/run/richs.check b/test/files/run/richs.check index bcaf8bdb8d..cf265ae007 100644 --- a/test/files/run/richs.check +++ b/test/files/run/richs.check @@ -1,4 +1,4 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details RichCharTest1: true diff --git a/test/files/run/t2212.check b/test/files/run/t2212.check index f7e80439c7..1465f1341a 100644 --- a/test/files/run/t2212.check +++ b/test/files/run/t2212.check @@ -1,4 +1,4 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details LinkedList(1) LinkedList(1) true diff --git a/test/files/run/t3996.check b/test/files/run/t3996.check index 2e8e558f88..a9ecc29fea 100644 --- a/test/files/run/t3996.check +++ b/test/files/run/t3996.check @@ -1 +1 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details diff --git a/test/files/run/t4080.check b/test/files/run/t4080.check index c642cc67da..462e925b76 100644 --- a/test/files/run/t4080.check +++ b/test/files/run/t4080.check @@ -1,2 +1,2 @@ -warning: there were 3 deprecation warnings; re-run with -deprecation for details +warning: there were three deprecation warnings; re-run with -deprecation for details LinkedList(1, 0, 2, 3) diff --git a/test/files/run/t4461.check b/test/files/run/t4461.check index c44b0fc077..346993af6f 100644 --- a/test/files/run/t4461.check +++ b/test/files/run/t4461.check @@ -1,4 +1,4 @@ -warning: there were 4 deprecation warnings; re-run with -deprecation for details +warning: there were four deprecation warnings; re-run with -deprecation for details Include(End,1) Include(End,2) Include(End,3) diff --git a/test/files/run/t4813.check b/test/files/run/t4813.check index 2e8e558f88..a9ecc29fea 100644 --- a/test/files/run/t4813.check +++ b/test/files/run/t4813.check @@ -1 +1 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details diff --git a/test/files/run/t6111.check b/test/files/run/t6111.check index 21a5b19ea0..5880658001 100644 --- a/test/files/run/t6111.check +++ b/test/files/run/t6111.check @@ -1,3 +1,3 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details (8,8) (x,x) diff --git a/test/files/run/t6690.check b/test/files/run/t6690.check index 2e8e558f88..a9ecc29fea 100644 --- a/test/files/run/t6690.check +++ b/test/files/run/t6690.check @@ -1 +1 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details diff --git a/test/files/run/t6863.check b/test/files/run/t6863.check index 37de2e6e51..d4df5f7a74 100644 --- a/test/files/run/t6863.check +++ b/test/files/run/t6863.check @@ -10,4 +10,4 @@ t6863.scala:46: warning: comparing values of types Unit and Unit using `==' will t6863.scala:59: warning: comparing values of types Unit and Unit using `==' will always yield true assert({ () => x }.apply == ()) ^ -warning: there were 4 deprecation warnings; re-run with -deprecation for details +warning: there were four deprecation warnings; re-run with -deprecation for details diff --git a/test/files/run/t8196.check b/test/files/run/t8196.check index f021a3619f..d11dc27e68 100644 --- a/test/files/run/t8196.check +++ b/test/files/run/t8196.check @@ -1,7 +1,7 @@ t8196.scala:26: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses form2.g1 // comment this line in order to make the test pass ^ -warning: there were 2 feature warnings; re-run with -feature for details +warning: there were two feature warnings; re-run with -feature for details Scope{ final private val f1: Int } diff --git a/test/files/run/t8549.check b/test/files/run/t8549.check index 2e8e558f88..a9ecc29fea 100644 --- a/test/files/run/t8549.check +++ b/test/files/run/t8549.check @@ -1 +1 @@ -warning: there were 2 deprecation warnings; re-run with -deprecation for details +warning: there were two deprecation warnings; re-run with -deprecation for details -- cgit v1.2.3 From 14fa7bef120cbb996d042daba6095530167c49ed Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 1 Jul 2014 16:19:34 +0200 Subject: SI-8708 Fix pickling of LOCAL_CHILD child of sealed classes When a sealed class or trait has local children, they are not pickled in as part of the children of the symbol (introduced in 12a2b3b to fix Aladdin bug 1055). Instead the compiler adds a single child class named LOCAL_CHILD. The parents of its ClassInfoType were wrong: the first parent should be a class. For sealed traits, we were using the trait itself. Also, the LOCAL_CHILD dummy class was entered as a member of its enclosing class, which is wrong: it represents a local (non-member) class, and it's a synthetic dummy anyway. --- .../scala/tools/nsc/symtab/classfile/Pickler.scala | 11 +++++- .../reflect/internal/pickling/UnPickler.scala | 42 +++++++++++++++++++--- test/files/neg/aladdin1055.check | 7 ++++ test/files/neg/aladdin1055.flags | 1 + test/files/neg/aladdin1055/A.scala | 6 ++++ test/files/neg/aladdin1055/Test_1.scala | 5 +++ test/files/pos/t8708/Either_1.scala | 6 ++++ test/files/pos/t8708/Test_2.scala | 13 +++++++ test/files/run/t8708_b.check | 8 +++++ test/files/run/t8708_b/A_1.scala | 8 +++++ test/files/run/t8708_b/Test_2.scala | 21 +++++++++++ 11 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 test/files/neg/aladdin1055.check create mode 100644 test/files/neg/aladdin1055.flags create mode 100644 test/files/neg/aladdin1055/A.scala create mode 100644 test/files/neg/aladdin1055/Test_1.scala create mode 100644 test/files/pos/t8708/Either_1.scala create mode 100644 test/files/pos/t8708/Test_2.scala create mode 100644 test/files/run/t8708_b.check create mode 100644 test/files/run/t8708_b/A_1.scala create mode 100644 test/files/run/t8708_b/Test_2.scala (limited to 'test') diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 592c5497b5..34c5a899b7 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -186,7 +186,16 @@ abstract class Pickler extends SubComponent { val (locals, globals) = sym.children partition (_.isLocalClass) val children = if (locals.isEmpty) globals - else globals + sym.newClassWithInfo(tpnme.LOCAL_CHILD, List(sym.tpe), EmptyScope, pos = sym.pos) + else { + // The LOCAL_CHILD was introduced in 12a2b3b to fix Aladdin bug 1055. When a sealed + // class/trait has local subclasses, a single class symbol is added + // as pickled child (instead of a reference to the anonymous class; that was done + // initially, but seems not to work, as the bug shows). + // Adding the LOCAL_CHILD is necessary to retain exhaustivity warnings under separate + // compilation. See test neg/aladdin1055. + val parents = (if (sym.isTrait) List(definitions.ObjectTpe) else Nil) ::: List(sym.tpe) + globals + sym.newClassWithInfo(tpnme.LOCAL_CHILD, parents, EmptyScope, pos = sym.pos) + } putChildren(sym, children.toList sortBy (_.sealedSortName)) } diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index 64a1a44722..b808666360 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -290,6 +290,25 @@ abstract class UnPickler { def pflags = flags & PickledFlags def finishSym(sym: Symbol): Symbol = { + /** + * member symbols (symbols owned by a class) are added to the class's scope, with a number + * of exceptions: + * + * (.) ... + * (1) `local child` represents local child classes, see comment in Pickler.putSymbol. + * Since it is not a member, it should not be entered in the owner's scope. + */ + def shouldEnterInOwnerScope = { + sym.owner.isClass && + sym != classRoot && + sym != moduleRoot && + !sym.isModuleClass && + !sym.isRefinementClass && + !sym.isTypeParameter && + !sym.isExistentiallyBound && + sym.rawname != tpnme.LOCAL_CHILD // (1) + } + markFlagsCompleted(sym)(mask = AllFlags) sym.privateWithin = privateWithin sym.info = ( @@ -302,8 +321,7 @@ abstract class UnPickler { newLazyTypeRefAndAlias(inforef, readNat()) } ) - if (sym.owner.isClass && sym != classRoot && sym != moduleRoot && - !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter && !sym.isExistentiallyBound) + if (shouldEnterInOwnerScope) symScope(sym.owner) enter sym sym @@ -681,10 +699,24 @@ abstract class UnPickler { private val p = phase protected def completeInternal(sym: Symbol) : Unit = try { val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` - if (p ne null) - slowButSafeEnteringPhase(p) (sym setInfo tp) + + // This is a temporary fix allowing to read classes generated by an older, buggy pickler. + // See the generation of the LOCAL_CHILD class in Pickler.scala. In an earlier version, the + // pickler did not add the ObjectTpe superclass, it used a trait as the first parent. This + // tripped an assertion in AddInterfaces which checks that the first parent is not a trait. + // This workaround can probably be removed in 2.12, because the 2.12 compiler is supposed + // to only read classfiles generated by 2.12. + val fixLocalChildTp = if (sym.rawname == tpnme.LOCAL_CHILD) tp match { + case ClassInfoType(superClass :: traits, decls, typeSymbol) if superClass.typeSymbol.isTrait => + ClassInfoType(definitions.ObjectTpe :: superClass :: traits, decls, typeSymbol) + case _ => tp + } else tp + + if (p ne null) { + slowButSafeEnteringPhase(p)(sym setInfo fixLocalChildTp) + } if (currentRunId != definedAtRunId) - sym.setInfo(adaptToNewRunMap(tp)) + sym.setInfo(adaptToNewRunMap(fixLocalChildTp)) } catch { case e: MissingRequirementError => throw toTypeError(e) diff --git a/test/files/neg/aladdin1055.check b/test/files/neg/aladdin1055.check new file mode 100644 index 0000000000..41782ae987 --- /dev/null +++ b/test/files/neg/aladdin1055.check @@ -0,0 +1,7 @@ +Test_1.scala:2: warning: match may not be exhaustive. +It would fail on the following input: (_ : this.) + def foo(t: A.T) = t match { + ^ +error: No warnings can be incurred under -Xfatal-warnings. +one warning found +one error found diff --git a/test/files/neg/aladdin1055.flags b/test/files/neg/aladdin1055.flags new file mode 100644 index 0000000000..e8fb65d50c --- /dev/null +++ b/test/files/neg/aladdin1055.flags @@ -0,0 +1 @@ +-Xfatal-warnings \ No newline at end of file diff --git a/test/files/neg/aladdin1055/A.scala b/test/files/neg/aladdin1055/A.scala new file mode 100644 index 0000000000..862336e30c --- /dev/null +++ b/test/files/neg/aladdin1055/A.scala @@ -0,0 +1,6 @@ +object A { + sealed trait T { def f: Int } + class TT extends T { def f = 0 } + + def foo = new T { def f = 1 } // local subclass of sealed trait T +} diff --git a/test/files/neg/aladdin1055/Test_1.scala b/test/files/neg/aladdin1055/Test_1.scala new file mode 100644 index 0000000000..39d9b1dc98 --- /dev/null +++ b/test/files/neg/aladdin1055/Test_1.scala @@ -0,0 +1,5 @@ +object Test { + def foo(t: A.T) = t match { + case a: A.TT => 0 + } +} diff --git a/test/files/pos/t8708/Either_1.scala b/test/files/pos/t8708/Either_1.scala new file mode 100644 index 0000000000..000ed6e7c2 --- /dev/null +++ b/test/files/pos/t8708/Either_1.scala @@ -0,0 +1,6 @@ +sealed trait \/[+A, +B] + +sealed trait EitherT[F[+_], +A, +B] +object EitherT { + def apply[F[+_], A, B](a: F[A \/ B]): EitherT[F, A, B] = new EitherT[F, A, B] { val run = a } +} diff --git a/test/files/pos/t8708/Test_2.scala b/test/files/pos/t8708/Test_2.scala new file mode 100644 index 0000000000..d0e56b9a37 --- /dev/null +++ b/test/files/pos/t8708/Test_2.scala @@ -0,0 +1,13 @@ +import scala.language.higherKinds + +trait ClientTypes[M[+_]] { + final type Context[+A] = EitherT[M, String, A] + object Context { + def apply[A](ca: M[String \/ A]): Context[A] = EitherT[M, String, A](ca) + } + + final type StatefulContext[+A] = EitherT[Context, String, A] + object StatefulContext { + def apply[A](state: Context[String \/ A]): StatefulContext[A] = ??? + } +} diff --git a/test/files/run/t8708_b.check b/test/files/run/t8708_b.check new file mode 100644 index 0000000000..30be62a307 --- /dev/null +++ b/test/files/run/t8708_b.check @@ -0,0 +1,8 @@ +Scope{ + def : ; + sealed abstract trait T extends ; + def foo: +} +Scope{ + def f: +} diff --git a/test/files/run/t8708_b/A_1.scala b/test/files/run/t8708_b/A_1.scala new file mode 100644 index 0000000000..e767420f9e --- /dev/null +++ b/test/files/run/t8708_b/A_1.scala @@ -0,0 +1,8 @@ +package p + +class C { + + sealed trait T { def f: Int } + + def foo: T = new T { def f = 1 } +} diff --git a/test/files/run/t8708_b/Test_2.scala b/test/files/run/t8708_b/Test_2.scala new file mode 100644 index 0000000000..c978490609 --- /dev/null +++ b/test/files/run/t8708_b/Test_2.scala @@ -0,0 +1,21 @@ +import scala.tools.partest._ +import java.io.{Console => _, _} + +object Test extends DirectTest { + + override def extraSettings: String = "-usejavacp -cp " + testOutput.path + + override def code = "" + + override def show(): Unit = { + val g = newCompiler() + withRun(g)(r => { + val c = g.rootMirror.getRequiredClass("p.C") + println(c.info.decls) + val t = c.info.member(g.newTypeName("T")) + // this test ensrues that the dummy class symbol is not entered in the + // scope of trait T during unpickling. + println(t.info.decls) + }) + } +} -- cgit v1.2.3