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) --- src/reflect/scala/reflect/internal/Printers.scala | 41 ++++++++---- .../scala/reflect/internal/PrintersTest.scala | 77 ++++++++++++++-------- 2 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index fcc377ba32..2ce861898f 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -596,18 +596,26 @@ trait Printers extends api.Printers { self: SymbolTable => } } - protected def emptyTree(tree: Tree) = tree match { - case EmptyTree | build.SyntacticEmptyTypeTree() => true - case _ => false + object EmptyTypeTree { + def unapply(tt: TypeTree): Boolean = tt match { + case build.SyntacticEmptyTypeTree() if tt.wasEmpty || tt.isEmpty => true + case _ => false + } } + protected def isEmptyTree(tree: Tree) = + tree match { + case EmptyTree | EmptyTypeTree() => true + case _ => false + } + protected def originalTypeTrees(trees: List[Tree]) = - trees.filter(!emptyTree(_)) map { - case tt: TypeTree => tt.original - case tree => tree + trees.filter(!isEmptyTree(_)) map { + case tt: TypeTree if tt.original != null => tt.original + case tree => tree } - val defaultClasses = List(tpnme.AnyRef) + val defaultClasses = List(tpnme.AnyRef, tpnme.Object) val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable) protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = { def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] = @@ -623,9 +631,10 @@ trait Printers extends api.Printers { self: SymbolTable => removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove) } - protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) = + protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) = originalTypeTrees(trees) filter { case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_) + case tt: TypeTree if tt.tpe != null => !(classesToRemove contains(newTypeName(tt.tpe.toString()))) case _ => true } @@ -637,7 +646,7 @@ trait Printers extends api.Printers { self: SymbolTable => } override def printOpt(prefix: String, tree: Tree) = - if (!emptyTree(tree)) super.printOpt(prefix, tree) + if (!isEmptyTree(tree)) super.printOpt(prefix, tree) override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = { super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end) @@ -952,7 +961,7 @@ trait Printers extends api.Printers { self: SymbolTable => def printTp = print("(", tp, ")") tp match { - case EmptyTree | build.SyntacticEmptyTypeTree() => printTp + case EmptyTree | EmptyTypeTree() => printTp // case for untypechecked trees case Annotated(annot, arg) if (expr ne null) && (arg ne null) && expr.equalsStructure(arg) => printTp // remove double arg - 5: 5: @unchecked case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp @@ -963,7 +972,7 @@ trait Printers extends api.Printers { self: SymbolTable => // print only fun when targs are TypeTrees with empty original case TypeApply(fun, targs) => - if (targs.exists(emptyTree(_))) { + if (targs.exists(isEmptyTree(_))) { print(fun) } else super.printTree(tree) @@ -984,8 +993,8 @@ trait Printers extends api.Printers { self: SymbolTable => case treeInfo.Unapplied(body) => body match { case Select(qual, name) if name == nme.unapply => print(qual) - case TypeApply(Select(qual, name), args) if name == nme.unapply || name == nme.unapplySeq => - print(TypeApply(qual, args)) + case TypeApply(Select(qual, name), _) if name == nme.unapply || name == nme.unapplySeq => + print(qual) case _ => print(body) } case _ => print(fun) @@ -1061,7 +1070,11 @@ trait Printers extends api.Printers { self: SymbolTable => print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector)) case tt: TypeTree => - if (!emptyTree(tt)) print(tt.original) + if (!isEmptyTree(tt)) { + val original = tt.original + if (original != null) print(original) + else super.printTree(tree) + } case AppliedTypeTree(tp, args) => // it's possible to have (=> String) => String type but Function1[=> String, String] is not correct 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(+) 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 733224093d8fee6f624656ecb9ee7c596fdb5ec2 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 23 May 2014 11:34:17 -0700 Subject: SI-8494 Restore filtering javap output Regressed in support for new delayedEndPoint, where it must pick what to filter for. `s/claas/klass/` and similar. --- .../scala/tools/nsc/interpreter/JavapClass.scala | 77 ++++++++++++---------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala index 915fd57bf8..f3ffea5a9b 100644 --- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala +++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala @@ -41,16 +41,16 @@ class JavapClass( * Byte data for filename args is retrieved with findBytes. */ def apply(args: Seq[String]): List[JpResult] = { - val (options, claases) = args partition (s => (s startsWith "-") && s.length > 1) + val (options, classes) = args partition (s => (s startsWith "-") && s.length > 1) val (flags, upgraded) = upgrade(options) import flags.{ app, fun, help, raw } - val targets = if (fun && !help) FunFinder(loader, intp).funs(claases) else claases - if (help || claases.isEmpty) + val targets = if (fun && !help) FunFinder(loader, intp).funs(classes) else classes + if (help || classes.isEmpty) List(JpResult(JavapTool.helper(printWriter))) else if (targets.isEmpty) List(JpResult("No anonfuns found.")) else - tool(raw, upgraded)(targets map (claas => targeted(claas, app))) + tool(raw, upgraded)(targets map (klass => targeted(klass, app))) } /** Cull our tool options. */ @@ -67,17 +67,18 @@ class JavapClass( case f: Failure[_] => (path, Failure(f.exception)) } - /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar"). */ + /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar"). + * @return the path to use for filtering, and the byte array + */ private def bytesFor(path: String, app: Boolean) = Try { def last = intp.get.mostRecentVar // fail if no intp - def req = path match { - case "-" => last - case HashSplit(prefix, member) => - if (prefix != null) prefix - else if (member != null) member - else "#" + val req = path match { + case "-" => last + case HashSplit(prefix, _) if prefix != null => prefix + case HashSplit(_, member) if member != null => member + case s => s } - val targetedBytes = if (app) findAppBody(req) else (req, findBytes(req)) + val targetedBytes = if (app) findAppBody(req) else (path, findBytes(req)) if (targetedBytes._2.isEmpty) throw new FileNotFoundException(s"Could not find class bytes for '$path'") targetedBytes } @@ -217,15 +218,15 @@ class JavapClass( // if apply is added here, it's for other than -fun: javap Foo#, perhaps m#? val filterOn = target.splitHashMember._2 map { s => if (s.isEmpty) "apply" else s } var filtering = false // true if in region matching filter - // true to output - def checkFilter(line: String) = if (filterOn.isEmpty) true else { + // turn filtering on/off given the pattern of interest + def filterStatus(line: String, pattern: String) = { // cheap heuristic, todo maybe parse for the java sig. // method sigs end in paren semi def isAnyMethod = line.endsWith(");") def isOurMethod = { val lparen = line.lastIndexOf('(') val blank = line.lastIndexOf(' ', lparen) - (blank >= 0 && line.substring(blank+1, lparen) == filterOn.get) + (blank >= 0 && line.substring(blank+1, lparen) == pattern) } filtering = if (filtering) { // next blank line terminates section @@ -236,8 +237,12 @@ class JavapClass( } filtering } - for (line <- Source.fromString(preamble + written).getLines(); if checkFilter(line)) - printWriter write line+lineSeparator + // do we output this line? + def checkFilter(line: String) = filterOn map (filterStatus(line, _)) getOrElse true + for { + line <- Source.fromString(preamble + written).getLines() + if checkFilter(line) + } printWriter write f"$line%n" printWriter.flush() } } @@ -275,7 +280,7 @@ class JavapClass( override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] = (inputs map { - case (claas, Success(ba)) => JpResult(showable(raw, claas, newPrinter(new ByteArrayInputStream(ba), newEnv(options)))) + case (klass, Success(ba)) => JpResult(showable(raw, klass, newPrinter(new ByteArrayInputStream(ba), newEnv(options)))) case (_, Failure(e)) => JpResult(e.toString) }).toList orFailed List(noToolError) } @@ -290,10 +295,10 @@ class JavapClass( //object TaskResult extends Enumeration { // val Ok, Error, CmdErr, SysErr, Abnormal = Value //} - val TaskClaas = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull - override protected def failed = TaskClaas eq null + val TaskClass = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull + override protected def failed = TaskClass eq null - val TaskCtor = TaskClaas.getConstructor( + val TaskCtor = TaskClass.getConstructor( classOf[Writer], classOf[JavaFileManager], classOf[DiagnosticListener[_]], @@ -344,8 +349,12 @@ class JavapClass( import Kind._ import StandardLocation._ import JavaFileManager.Location - import java.net.URI - def uri(name: String): URI = new URI(name) // new URI("jfo:" + name) + import java.net.{ URI, URISyntaxException } + + // name#fragment is OK, but otherwise fragile + def uri(name: String): URI = + try new URI(name) // new URI("jfo:" + name) + catch { case _: URISyntaxException => new URI("dummy") } def inputNamed(name: String): Try[ByteAry] = (managed find (_._1 == name)).get._2 def managedFile(name: String, kind: Kind) = kind match { @@ -379,19 +388,19 @@ class JavapClass( def showable(raw: Boolean, target: String): Showable = showWithPreamble(raw, target, reporter.reportable(raw)) // eventually, use the tool interface - def task(options: Seq[String], claases: Seq[String], inputs: Seq[Input]): Task = { + def task(options: Seq[String], classes: Seq[String], inputs: Seq[Input]): Task = { //ServiceLoader.load(classOf[javax.tools.DisassemblerTool]). - //getTask(writer, fileManager, reporter, options.asJava, claases.asJava) + //getTask(writer, fileManager, reporter, options.asJava, classes.asJava) import JavaConverters.asJavaIterableConverter - TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, claases.asJava) + TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, classes.asJava) .orFailed (throw new IllegalStateException) } // a result per input - private def applyOne(raw: Boolean, options: Seq[String], claas: String, inputs: Seq[Input]): Try[JpResult] = + private def applyOne(raw: Boolean, options: Seq[String], klass: String, inputs: Seq[Input]): Try[JpResult] = Try { - task(options, Seq(claas), inputs).call() + task(options, Seq(klass), inputs).call() } map { - case true => JpResult(showable(raw, claas)) + case true => JpResult(showable(raw, klass)) case _ => JpResult(reporter.reportable(raw)) } recoverWith { case e: java.lang.reflect.InvocationTargetException => e.getCause match { @@ -402,7 +411,7 @@ class JavapClass( reporter.clear() } override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] = (inputs map { - case (claas, Success(_)) => applyOne(raw, options, claas, inputs).get + case (klass, Success(_)) => applyOne(raw, options, klass, inputs).get case (_, Failure(e)) => JpResult(e.toString) }).toList orFailed List(noToolError) } @@ -534,6 +543,7 @@ class JavapClass( private def isTaskable(cl: ScalaClassLoader) = hasClass(cl, Tool) + /** Select the tool implementation for this platform. */ def apply() = if (isTaskable(loader)) new JavapTool7 else new JavapTool6 } } @@ -545,7 +555,8 @@ object JavapClass { intp: Option[IMain] = None ) = new JavapClass(loader, printWriter, intp) - val HashSplit = "(.*?)(?:#([^#]*))?".r + val HashSplit = "([^#]+)?(?:#(.+)?)?".r + // We enjoy flexibility in specifying either a fully-qualified class name com.acme.Widget // or a resource path com/acme/Widget.class; but not widget.out implicit class MaybeClassLike(val s: String) extends AnyVal { @@ -580,11 +591,11 @@ object JavapClass { /* only the file location from which the given class is loaded */ def locate(k: String): Option[Path] = { Try { - val claas = try cl loadClass k catch { + val klass = try cl loadClass k catch { case _: NoClassDefFoundError => null // let it snow } // cf ScalaClassLoader.originOfClass - claas.getProtectionDomain.getCodeSource.getLocation + klass.getProtectionDomain.getCodeSource.getLocation } match { case Success(null) => None case Success(loc) if loc.isFile => Some(Path(new JFile(loc.toURI))) -- cgit v1.2.3 From fadb21dc107b54e9d1a15abb626a36370bcd3501 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 23 May 2014 12:29:09 -0700 Subject: SI-8494 Javap filter includes specialized When filtering javap output, include specialized versions of methods. For anonfuns, in particular, the apply$sp is the method of interest. --- .../scala/tools/nsc/interpreter/JavapClass.scala | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala index f3ffea5a9b..3cb6ba11c1 100644 --- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala +++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala @@ -226,15 +226,20 @@ class JavapClass( def isOurMethod = { val lparen = line.lastIndexOf('(') val blank = line.lastIndexOf(' ', lparen) - (blank >= 0 && line.substring(blank+1, lparen) == pattern) - } - filtering = if (filtering) { - // next blank line terminates section - // for -public, next line is next method, more or less - line.trim.nonEmpty && !isAnyMethod - } else { - isAnyMethod && isOurMethod + if (blank < 0) false + else { + val method = line.substring(blank+1, lparen) + (method == pattern || ((method startsWith pattern+"$") && (method endsWith "$sp"))) + } } + filtering = + if (filtering) { + // next blank line terminates section + // for -public, next line is next method, more or less + line.trim.nonEmpty && !isAnyMethod + } else { + isAnyMethod && isOurMethod + } filtering } // do we output this line? -- 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 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 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 1f53a0d180a1fa561502f3d7884d71daf998a837 Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Thu, 26 Jun 2014 18:07:57 -0700 Subject: SI-7577 Incorrect documentation: current default isn't Vector Fixed documentation to specify List in four cases where it was wrong or missing. --- src/library/scala/collection/Iterable.scala | 2 +- src/library/scala/collection/Traversable.scala | 2 +- src/library/scala/collection/immutable/Iterable.scala | 1 + src/library/scala/collection/immutable/Traversable.scala | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/library/scala/collection/Iterable.scala b/src/library/scala/collection/Iterable.scala index a5ab8efd5c..afbffd36c6 100644 --- a/src/library/scala/collection/Iterable.scala +++ b/src/library/scala/collection/Iterable.scala @@ -38,7 +38,7 @@ trait Iterable[+A] extends Traversable[A] } /** $factoryInfo - * The current default implementation of a $Coll is a `Vector`. + * The current default implementation of a $Coll is a `List`. * @define coll iterable collection * @define Coll `Iterable` */ diff --git a/src/library/scala/collection/Traversable.scala b/src/library/scala/collection/Traversable.scala index b53724c568..a35750a35f 100644 --- a/src/library/scala/collection/Traversable.scala +++ b/src/library/scala/collection/Traversable.scala @@ -87,7 +87,7 @@ trait Traversable[+A] extends TraversableLike[A, Traversable[A]] } /** $factoryInfo - * The current default implementation of a $Coll is a `Vector`. + * The current default implementation of a $Coll is a `List`. */ object Traversable extends TraversableFactory[Traversable] { self => diff --git a/src/library/scala/collection/immutable/Iterable.scala b/src/library/scala/collection/immutable/Iterable.scala index 6e4eb1e45f..df322396d0 100644 --- a/src/library/scala/collection/immutable/Iterable.scala +++ b/src/library/scala/collection/immutable/Iterable.scala @@ -35,6 +35,7 @@ trait Iterable[+A] extends Traversable[A] } /** $factoryInfo + * The current default implementation of a $Coll is a `List`. * @define Coll `immutable.Iterable` * @define coll immutable iterable collection */ diff --git a/src/library/scala/collection/immutable/Traversable.scala b/src/library/scala/collection/immutable/Traversable.scala index 775d635fae..5fc0607a00 100644 --- a/src/library/scala/collection/immutable/Traversable.scala +++ b/src/library/scala/collection/immutable/Traversable.scala @@ -29,7 +29,7 @@ trait Traversable[+A] extends scala.collection.Traversable[A] } /** $factoryInfo - * The current default implementation of a $Coll is a `Vector`. + * The current default implementation of a $Coll is a `List`. * @define coll immutable traversable collection * @define Coll `immutable.Traversable` */ -- cgit v1.2.3 From 36ef5c374a11f881cb77bcb784af7b52483ee646 Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Fri, 27 Jun 2014 19:23:37 -0700 Subject: SI-8638 Empty UnrolledBuffer hangs on prepend. Tracked down bug to incorrect recursion in insertAll. Fixed by adding a missing case (which incidentally will provide better performance when adding to the end of a block). No specific tests, as this is caught by quasi-complete collections tests. --- .../scala/collection/mutable/UnrolledBuffer.scala | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/library/scala/collection/mutable/UnrolledBuffer.scala b/src/library/scala/collection/mutable/UnrolledBuffer.scala index 1f89199bdc..693c47d86e 100644 --- a/src/library/scala/collection/mutable/UnrolledBuffer.scala +++ b/src/library/scala/collection/mutable/UnrolledBuffer.scala @@ -300,27 +300,33 @@ object UnrolledBuffer extends ClassTagTraversableFactory[UnrolledBuffer] { if (next eq null) true else false // checks if last node was thrown out } else false - @tailrec final def insertAll(idx: Int, t: scala.collection.Traversable[T], buffer: UnrolledBuffer[T]): Unit = if (idx < size) { - // divide this node at the appropriate position and insert all into head - // update new next - val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff) - Array.copy(array, idx, newnextnode.array, 0, size - idx) - newnextnode.size = size - idx - newnextnode.next = next - - // update this - nullout(idx, size) - size = idx - next = null - - // insert everything from iterable to this - var curr = this - for (elem <- t) curr = curr append elem - curr.next = newnextnode - - // try to merge the last node of this with the newnextnode - if (curr.tryMergeWithNext()) buffer.lastPtr = curr - } else insertAll(idx - size, t, buffer) + @tailrec final def insertAll(idx: Int, t: scala.collection.Traversable[T], buffer: UnrolledBuffer[T]): Unit = { + if (idx < size) { + // divide this node at the appropriate position and insert all into head + // update new next + val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff) + Array.copy(array, idx, newnextnode.array, 0, size - idx) + newnextnode.size = size - idx + newnextnode.next = next + + // update this + nullout(idx, size) + size = idx + next = null + + // insert everything from iterable to this + var curr = this + for (elem <- t) curr = curr append elem + curr.next = newnextnode + + // try to merge the last node of this with the newnextnode + if (curr.tryMergeWithNext()) buffer.lastPtr = curr + } + else if (idx == size) { + var curr = this + for (elem <- t) curr = curr append elem + } else insertAll(idx - size, t, buffer) + } private def nullout(from: Int, until: Int) { var idx = from while (idx < until) { -- cgit v1.2.3 From 23ae5c48b3c647361a63373c4f967022351d99dc Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Fri, 27 Jun 2014 19:56:17 -0700 Subject: SI-5200 Incorrect advice for implementing mutable.Set in scaladoc Fixed advice; it was already there in mutable.SetLike but a case sensitivity error kept it from appearing. --- src/library/scala/collection/SetLike.scala | 7 +++---- src/library/scala/collection/mutable/SetLike.scala | 17 +++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala index 0c5c7e0b29..3e549f72cd 100644 --- a/src/library/scala/collection/SetLike.scala +++ b/src/library/scala/collection/SetLike.scala @@ -17,6 +17,9 @@ import parallel.ParSet /** A template trait for sets. * * $setNote + * '''Implementation note:''' + * This trait provides most of the operations of a `Set` independently of its representation. + * It is typically inherited by concrete implementations of sets. * $setTags * @since 2.8 * @@ -24,10 +27,6 @@ import parallel.ParSet * * A set is a collection that contains no duplicate elements. * - * '''Implementation note:''' - * This trait provides most of the operations of a `Set` independently of its representation. - * It is typically inherited by concrete implementations of sets. - * * To implement a concrete set, you need to provide implementations of the * following methods: * {{{ diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala index d749167870..a377b03124 100644 --- a/src/library/scala/collection/mutable/SetLike.scala +++ b/src/library/scala/collection/mutable/SetLike.scala @@ -16,19 +16,20 @@ import scala.annotation.migration import parallel.mutable.ParSet /** A template trait for mutable sets of type `mutable.Set[A]`. + * + * This trait provides most of the operations of a `mutable.Set` independently of its representation. + * It is typically inherited by concrete implementations of sets. + * + * $setNote + * * @tparam A the type of the elements of the set * @tparam This the type of the set itself. * - * $setnote - * * @author Martin Odersky * @version 2.8 * @since 2.8 * - * @define setnote - * @note - * This trait provides most of the operations of a `mutable.Set` independently of its representation. - * It is typically inherited by concrete implementations of sets. + * @define setNote * * To implement a concrete mutable set, you need to provide implementations * of the following methods: @@ -36,13 +37,13 @@ import parallel.mutable.ParSet * def contains(elem: A): Boolean * def iterator: Iterator[A] * def += (elem: A): this.type - * def -= (elem: A): this.type + * def -= (elem: A): this.type * }}} * If you wish that methods like `take`, * `drop`, `filter` return the same kind of set, * you should also override: * {{{ - * def empty: This + * def empty: This * }}} * It is also good idea to override methods `foreach` and * `size` for efficiency. -- cgit v1.2.3 From ff43de9f8f9e0e9fef55a825dfb067bdc61b90fc Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Fri, 27 Jun 2014 20:30:33 -0700 Subject: SI-8335 List.++ avoidably burns memory Changed to check the identity of the CanBuildFrom instead of the identity of the generated builder to shortcut building. Should reduce memory churn on ++ a little. --- src/library/scala/collection/immutable/List.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 930e13a9d3..aa9dec2761 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -190,11 +190,9 @@ sealed abstract class List[+A] extends AbstractSeq[A] // Overridden methods from IterableLike and SeqLike or overloaded variants of such methods - override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { - val b = bf(this) - if (b.isInstanceOf[ListBuffer[_]]) (this ::: that.seq.toList).asInstanceOf[That] + override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = + if (bf eq List.ReusableCBF) (this ::: that.seq.toList).asInstanceOf[That] else super.++(that) - } override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That = bf match { case _: List.GenericCanBuildFrom[_] => (elem :: this).asInstanceOf[That] -- cgit v1.2.3 From 9ceab680a315cb79d4d187f977e9dac3b58e48c0 Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Fri, 27 Jun 2014 17:12:39 -0700 Subject: SI-7115 JMapWrapper.get can incorrectly return Some(null) This isn't incorrect. Trying to use a single-threaded interface in a concurrent context is supposed to break in various unpleasant ways. Documentation has been added to encourage one to avoid wrapping a concurrent map in the generic wrapper (which assumes a single thread), and pointing out that synchronized maps do not maintain synchronization for non-atomic operations (including get). More docs. --- src/library/scala/collection/convert/DecorateAsScala.scala | 6 ++++++ src/library/scala/collection/convert/WrapAsScala.scala | 8 +++++++- src/library/scala/collection/convert/Wrappers.scala | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index c724831c54..5448f5f91c 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -135,6 +135,12 @@ trait DecorateAsScala { * If the Java `Map` was previously obtained from an implicit or explicit * call of `asMap(scala.collection.mutable.Map)` then the original * Scala `Map` will be returned. + * + * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), + * it is your responsibility to wrap all + * non-atomic operations with `underlying.synchronized`. + * This includes `get`, as `java.util.Map`'s API does not allow for an + * atomic `get` when `null` values may be present. * * @param m The `Map` to be converted. * @return An object with an `asScala` method that returns a Scala mutable diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index d4ab451b0d..ab151a6778 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -133,7 +133,13 @@ trait WrapAsScala { * If the Java `Map` was previously obtained from an implicit or * explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then * the original Scala Map will be returned. - * + * + * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), + * it is your responsibility to wrap all + * non-atomic operations with `underlying.synchronized`. + * This includes `get`, as `java.util.Map`'s API does not allow for an + * atomic `get` when `null` values may be present. + * * @param m The Map to be converted. * @return A Scala mutable Map view of the argument. */ diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 7d1d6b3781..9f9732c62f 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -288,6 +288,13 @@ private[collection] trait Wrappers { override def empty: Repr = null.asInstanceOf[Repr] } + /** Wraps a Java map as a Scala one. If the map is to support concurrent access, + * use [[JConcurrentMapWrapper]] instead. If the wrapped map is synchronized + * (e.g. from `java.util.Collections.synchronizedMap`), it is your responsibility + * to wrap all non-atomic operations with `underlying.synchronized`. + * This includes `get`, as `java.util.Map`'s API does not allow for an + * atomic `get` when `null` values may be present. + */ case class JMapWrapper[A, B](underlying : ju.Map[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JMapWrapper[A, B]] { override def empty = JMapWrapper(new ju.HashMap[A, B]) } @@ -314,6 +321,10 @@ private[collection] trait Wrappers { def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) } + /** Wraps a concurrent Java map as a Scala one. Single-element concurrent + * access is supported; multi-element operations such as maps and filters + * are not guaranteed to be atomic. + */ case class JConcurrentMapWrapper[A, B](underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[A, B] { override def get(k: A) = { val v = underlying get k -- 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 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 5d63ef31c16511df5ce9cbda5d07fd7672844ae2 Mon Sep 17 00:00:00 2001 From: Antoine Gourlay Date: Sun, 16 Feb 2014 14:54:10 +0100 Subject: SI-8292 report error when scaladoc fails to find doclet. --- src/scaladoc/scala/tools/nsc/doc/DocFactory.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala index dce52af56a..47ddfb8aa9 100644 --- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala +++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala @@ -95,11 +95,11 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor val documentError: PartialFunction[Throwable, Unit] = { case NoCompilerRunException => reporter.info(null, "No documentation generated with unsuccessful compiler run", force = false) - case _: ClassNotFoundException => - () + case e @ (_:ClassNotFoundException | _:IllegalAccessException | _:InstantiationException | _:SecurityException | _:ClassCastException) => + reporter.error(null, s"Cannot load the doclet class ${settings.docgenerator.value} (specified with ${settings.docgenerator.name}): $e. Leaving the default settings will generate the html version of scaladoc.") } - /** Generate document(s) for all `files` containing scaladoc documenataion. + /** Generate document(s) for all `files` containing scaladoc documentation. * @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */ def document(files: List[String]) { def generate() = { -- cgit v1.2.3 From b3c4e3ace9e68050f8e07af931a8f1b55cf90f7c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 1 Jul 2014 13:45:41 +0200 Subject: Document SuperAccessors Added comment giving an up-to-date overview of SuperAccessors and how we might want to change it. --- .../tools/nsc/typechecker/SuperAccessors.scala | 46 +++++++++++++++++----- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 9b9e641cad..b6d37ab9a7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -12,21 +12,47 @@ import scala.collection.{ mutable, immutable } import mutable.ListBuffer import symtab.Flags._ -/** This phase adds super accessors for all super calls that either +/** This phase performs the following functions, each of which could be split out in a + * mini-phase: + * + * (1) Adds super accessors for all super calls that either * appear in a trait or have as a target a member of some outer class. - * It also replaces references to parameter accessors with aliases - * by super references to these aliases. The phase also checks that - * symbols accessed from super are not abstract, or are overridden by - * an abstract override. Finally, the phase also mangles the names - * of class-members which are private up to an enclosing non-package - * class, in order to avoid overriding conflicts. * - * This phase also sets SPECIALIZED flag on type parameters with + * (2) Converts references to parameter fields that have the same name as a corresponding + * public parameter field in a superclass to a reference to the superclass + * field (corresponding = super class field is initialized with subclass field). + * This info is pre-computed by the `alias` field in Typer. `dotc` follows a different + * route; it computes everything in SuperAccessors and changes the subclass field + * to a forwarder instead of manipulating references. This is more modular. + * + * (3) Adds protected accessors if the access to the protected member happens + * in a class which is not a subclass of the member's owner. + * + * (4) Mangles the names of class-members which are + * private up to an enclosing non-package class, in order to avoid overriding conflicts. + * This is a dubious, and it would be better to deprecate class-qualified privates. + * + * (5) This phase also sets SPECIALIZED flag on type parameters with * `@specialized` annotation. We put this logic here because the * flag must be set before pickling. * - * @author Martin Odersky - * @version 1.0 + * It also checks that: + * + * (1) Symbols accessed from super are not abstract, or are overridden by + * an abstract override. + * + * (2) If a symbol accessed accessed from super is defined in a real class (not a trait), + * there are no abstract members which override this member in Java's rules + * (see SI-4989; such an access would lead to illegal bytecode) + * + * (3) Super calls do not go to some synthetic members of Any (see isDisallowed) + * + * (4) Super calls do not go to synthetic field accessors + * + * (5) A class and its companion object do not both define a class or module with the + * same name. + * + * TODO: Rename phase to "Accessors" because it handles more than just super accessors */ abstract class SuperAccessors extends transform.Transform with transform.TypingTransformers { import global._ -- 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(-) 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(-) 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 f2b76e80094219db1f72a7a56d02f21bab1fc9eb Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 10 Jun 2014 09:44:24 +0200 Subject: Pure refactor: reorder definitions --- .../scala/tools/nsc/reporters/Reporter.scala | 55 +++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index 766a35960b..1a8794d217 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -16,6 +16,29 @@ import scala.reflect.internal.util._ abstract class Reporter { protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit + /** 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 = { } + + // 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 @@ -40,35 +63,21 @@ abstract class Reporter { } // 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 + var cancelled: Boolean = false - /** 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) + // overridden by sbt + def hasErrors: Boolean = ERROR.count > 0 || cancelled - /** Informational messages. If `!force`, they may be suppressed. */ - final def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) + // overridden by sbt + def hasWarnings: Boolean = WARNING.count > 0 - /** 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) + // TODO def incompleteInputError(pos: Position, msg: String): Unit = { if (incompleteHandled) incompleteHandler(pos, msg) else error(pos, msg) } - // 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 - ERROR.count = 0 - WARNING.count = 0 - 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 = {} } -- 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 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(-) 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 e08735380e8cba8f4b7230f5615e528782a0111a Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 10 Jun 2014 12:32:06 +0200 Subject: Track symbol that caused a deprecation warning. So that we can filter deprecations based on defining package. Configurable error reporting will support a rule like: "In compilation unit X, escalate deprecation warnings that result from accessing members in package P that have been deprecated since version V. Report an error instead of a warning for those." TODO: remove deprecationWarning overload that doesn't take a `Symbol`? (Replace by a default value of `NoSymbol` for the deprecated symbol arg?) --- src/compiler/scala/tools/nsc/CompilationUnits.scala | 2 ++ src/compiler/scala/tools/nsc/Reporting.scala | 4 ++++ .../nsc/transform/patmat/ScalacPatternExpanders.scala | 6 ++++-- .../scala/tools/nsc/typechecker/Adaptations.scala | 2 +- .../scala/tools/nsc/typechecker/NamesDefaults.scala | 4 ++-- .../scala/tools/nsc/typechecker/RefChecks.scala | 14 ++++++-------- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 17 ++++++++--------- src/reflect/scala/reflect/internal/Reporting.scala | 3 +++ 8 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index ae1b94dfa1..b9e745f176 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -132,8 +132,10 @@ trait CompilationUnits { global: Global => def warning(pos: Position, msg: String): Unit = reporter.warning(pos, msg) def deprecationWarning(pos: Position, msg: String): Unit = reporting.deprecationWarning(pos, msg) + def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = reporting.deprecationWarning(pos, sym, 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) diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index a8fd3bec76..1b5a778235 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -61,6 +61,7 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w private val _inlinerWarnings = new ConditionalWarning("inliner", settings.YinlinerWarnings) private val _allConditionalWarnings = List(_deprecationWarnings, _uncheckedWarnings, _featureWarnings, _inlinerWarnings) + // TODO: remove in favor of the overload that takes a Symbol, give that argument a default (NoSymbol) 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) @@ -73,6 +74,9 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w def allConditionalWarnings = _allConditionalWarnings flatMap (_.warnings) + // behold! the symbol that caused the deprecation warning (may not be deprecated itself) + def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = _deprecationWarnings.warn(pos, msg) + 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" diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala index d10eff1d8d..c19786d5e7 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala @@ -139,8 +139,10 @@ trait ScalacPatternExpanders { def acceptMessage = if (extractor.isErroneous) "" else s" to hold ${extractor.offeringString}" val requiresTupling = isUnapply && patterns.totalArity == 1 && productArity > 1 - if (requiresTupling && effectivePatternArity(args) == 1) - currentUnit.deprecationWarning(sel.pos, s"${sel.symbol.owner} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)") + if (requiresTupling && effectivePatternArity(args) == 1) { + val sym = sel.symbol.owner + currentUnit.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)") + } val normalizedExtractor = if (requiresTupling) tupleExtractor(extractor) else extractor validateAligned(fn, Aligned(patterns, normalizedExtractor)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala index 1e544e54f6..6e99b9bd4c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala @@ -77,7 +77,7 @@ trait Adaptations { val msg = "Adaptation of argument list by inserting () has been deprecated: " + ( if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous." else "this is unlikely to be what you want.") - context.unit.deprecationWarning(t.pos, adaptWarningMessage(msg)) + context.unit.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(msg)) } } else if (settings.warnAdaptedArgs) context.warning(t.pos, adaptWarningMessage(s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want.")) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 284ab2f6f9..65f33952d3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -536,8 +536,8 @@ trait NamesDefaults { self: Analyzer => def matchesName(param: Symbol) = !param.isSynthetic && ( (param.name == name) || (param.deprecatedParamName match { case Some(`name`) => - context0.unit.deprecationWarning(arg.pos, - "the parameter name "+ name +" has been deprecated. Use "+ param.name +" instead.") + context0.unit.deprecationWarning(arg.pos, param, + s"the parameter name $name has been deprecated. Use ${param.name} instead.") true case _ => false }) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4540017b62..0d79637c88 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -546,7 +546,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if (other.hasDeprecatedOverridingAnnotation) { val suffix = other.deprecatedOverridingMessage map (": " + _) getOrElse "" val msg = s"overriding ${other.fullLocationString} is deprecated$suffix" - unit.deprecationWarning(member.pos, msg) + unit.deprecationWarning(member.pos, other, msg) } } } @@ -1287,11 +1287,9 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans private def checkUndesiredProperties(sym: Symbol, pos: Position) { // If symbol is deprecated, and the point of reference is not enclosed // in either a deprecated member or a scala bridge method, issue a warning. - if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) { - unit.deprecationWarning(pos, "%s%s is deprecated%s".format( - sym, sym.locationString, sym.deprecationMessage map (": " + _) getOrElse "") - ) - } + if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) + unit.deprecationWarning(pos, sym, s"${sym}${sym.locationString} is deprecated${sym.deprecationMessage map (": " + _) getOrElse ""}") + // Similar to deprecation: check if the symbol is marked with @migration // indicating it has changed semantics between versions. if (sym.hasMigrationAnnotation && settings.Xmigration.value != NoScalaVersion) { @@ -1409,8 +1407,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if(!concrOvers.isEmpty) unit.deprecationWarning( tree.pos, - symbol.toString + " overrides concrete, non-deprecated symbol(s):" + - concrOvers.map(_.name.decode).mkString(" ", ", ", "")) + symbol, + s"${symbol.toString} overrides concrete, non-deprecated symbol(s): ${concrOvers.map(_.name.decode).mkString(", ")}") } } private def isRepeatedParamArg(tree: Tree) = currentApplication match { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 059b58c943..3c215ea10b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -941,10 +941,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } def adaptConstant(value: Constant): Tree = { val sym = tree.symbol - if (sym != null && sym.isDeprecated) { - val msg = sym.toString + sym.locationString + " is deprecated: " + sym.deprecationMessage.getOrElse("") - unit.deprecationWarning(tree.pos, msg) - } + if (sym != null && sym.isDeprecated) + unit.deprecationWarning(tree.pos, sym, s"${sym.toString}${sym.locationString} is deprecated: ${sym.deprecationMessage.getOrElse("")}") + treeCopy.Literal(tree, value) } @@ -1676,7 +1675,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (!isPastTyper && psym.hasDeprecatedInheritanceAnnotation && !sameSourceFile) { val suffix = psym.deprecatedInheritanceMessage map (": " + _) getOrElse "" val msg = s"inheritance from ${psym.fullLocationString} is deprecated$suffix" - unit.deprecationWarning(parent.pos, msg) + unit.deprecationWarning(parent.pos, psym, msg) } if (psym.isSealed && !phase.erasedTypes) @@ -3666,7 +3665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2) - unit.deprecationWarning(ann.pos, "@deprecated now takes two arguments; see the scaladoc.") + unit.deprecationWarning(ann.pos, DeprecatedAttr, "@deprecated now takes two arguments; see the scaladoc.") if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) ErroneousAnnotation else annInfo(typedAnn) @@ -4698,10 +4697,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // temporarily use `filter` as an alternative for `withFilter` def tryWithFilterAndFilter(tree: Select, qual: Tree): Tree = { - def warn() = unit.deprecationWarning(tree.pos, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead") + def warn(sym: Symbol) = unit.deprecationWarning(tree.pos, sym, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead") silent(_ => typedSelect(tree, qual, nme.withFilter)) orElse { _ => silent(_ => typed1(Select(qual, nme.filter) setPos tree.pos, mode, pt)) match { - case SilentResultValue(res) => warn() ; res + case SilentResultValue(res) => warn(res.symbol) ; res case SilentTypeError(err) => WithFilterError(tree, err) } } @@ -5482,7 +5481,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } def reportWarning(inferredType: Type) = { val explanation = s"inference of $inferredType from macro impl's c.Expr[$inferredType] is deprecated and is going to stop working in 2.12" - unit.deprecationWarning(ddef.pos, s"$commonMessage ($explanation)") + unit.deprecationWarning(ddef.pos, ddef.symbol, s"$commonMessage ($explanation)") } computeMacroDefTypeFromMacroImplRef(ddef, rhs1) match { case ErrorType => ErrorType diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala index baeed1357d..0670e9bd8e 100644 --- a/src/reflect/scala/reflect/internal/Reporting.scala +++ b/src/reflect/scala/reflect/internal/Reporting.scala @@ -10,6 +10,9 @@ 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. + * + * Eventually, this interface should be reduced to one method: `reporter`, + * and clients should indirect themselves (reduce duplication of forwarders). */ trait Reporting { self : Positions => def reporter: Reporter -- cgit v1.2.3 From 59db57f5ac26609186d6338d2d7cfaf1281b78ab Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 23 Jun 2014 17:49:59 +0200 Subject: Route type checker reporting through context Continue the work started in SI-8450 (no "implicit numeric widening" warning in silent mode), which was caused by going straight to the reporter instead of using the context for type error reporting (which buffers in silent mode). Ideally, this mistake should not be possible: typer should change the current reporter to buffer where appropriate. --- .../scala/tools/nsc/typechecker/Adaptations.scala | 2 +- .../scala/tools/nsc/typechecker/Contexts.scala | 8 ++++ .../tools/nsc/typechecker/NamesDefaults.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 52 +++++++++++----------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala index 6e99b9bd4c..37c39c07be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala @@ -77,7 +77,7 @@ trait Adaptations { val msg = "Adaptation of argument list by inserting () has been deprecated: " + ( if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous." else "this is unlikely to be what you want.") - context.unit.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(msg)) + context.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(msg)) } } else if (settings.warnAdaptedArgs) context.warning(t.pos, adaptWarningMessage(s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want.")) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 8e1ceffecd..03890f30f6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -593,6 +593,14 @@ trait Contexts { self: Analyzer => else if (bufferErrors) reportBuffer += (pos -> msg) } + def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = + currentRun.reporting.deprecationWarning(pos, sym, msg) + + def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit = + currentRun.reporting.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required) + + def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg) + // nextOuter determines which context is searched next for implicits // (after `this`, which contributes `newImplicits` below.) In // most cases, it is simply the outer context: if we're owned by diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 65f33952d3..43902d1c65 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -536,7 +536,7 @@ trait NamesDefaults { self: Analyzer => def matchesName(param: Symbol) = !param.isSynthetic && ( (param.name == name) || (param.deprecatedParamName match { case Some(`name`) => - context0.unit.deprecationWarning(arg.pos, param, + context0.deprecationWarning(arg.pos, param, s"the parameter name $name has been deprecated. Use ${param.name} instead.") true case _ => false diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 3c215ea10b..349bad555a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -746,7 +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 - unit.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required) + context.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required) } OK } @@ -942,7 +942,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def adaptConstant(value: Constant): Tree = { val sym = tree.symbol if (sym != null && sym.isDeprecated) - unit.deprecationWarning(tree.pos, sym, s"${sym.toString}${sym.locationString} is deprecated: ${sym.deprecationMessage.getOrElse("")}") + context.deprecationWarning(tree.pos, sym, s"${sym.toString}${sym.locationString} is deprecated: ${sym.deprecationMessage.getOrElse("")}") treeCopy.Literal(tree, value) } @@ -1051,7 +1051,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case coercion => def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe if (settings.logImplicitConv) - unit.echo(tree.pos, msg) + context.echo(tree.pos, msg) debuglog(msg) val silentContext = context.makeImplicit(context.ambiguousErrors) @@ -1211,7 +1211,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case EmptyTree => qual case coercion => if (settings.logImplicitConv) - unit.echo(qual.pos, + context.echo(qual.pos, "applied implicit conversion from %s to %s = %s".format( qual.tpe, searchTemplate, coercion.symbol.defString)) @@ -1276,7 +1276,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper private def validateNoCaseAncestor(clazz: Symbol) = { if (!phase.erasedTypes) { for (ancestor <- clazz.ancestors find (_.isCase)) { - unit.error(clazz.pos, ( + context.error(clazz.pos, ( "case %s has case ancestor %s, but case-to-case inheritance is prohibited."+ " To overcome this limitation, use extractors to pattern match on non-leaf nodes." ).format(clazz, ancestor.fullName)) @@ -1293,7 +1293,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val isValueClass = !clazz.isTrait def where = if (isValueClass) "value class" else "universal trait extending from class Any" def implRestriction(tree: Tree, what: String) = - unit.error(tree.pos, s"implementation restriction: $what is not allowed in $where" + + context.error(tree.pos, s"implementation restriction: $what is not allowed in $where" + "\nThis restriction is planned to be removed in subsequent releases.") /** * Deeply traverses the tree in search of constructs that are not allowed @@ -1322,7 +1322,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } for (stat <- body) { - def notAllowed(what: String) = unit.error(stat.pos, s"$what is not allowed in $where") + def notAllowed(what: String) = context.error(stat.pos, s"$what is not allowed in $where") stat match { // see https://issues.scala-lang.org/browse/SI-6444 // see https://issues.scala-lang.org/browse/SI-6463 @@ -1350,9 +1350,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper private def validateDerivedValueClass(clazz: Symbol, body: List[Tree]) = { if (clazz.isTrait) - unit.error(clazz.pos, "only classes (not traits) are allowed to extend AnyVal") + context.error(clazz.pos, "only classes (not traits) are allowed to extend AnyVal") if (!clazz.isStatic) - unit.error(clazz.pos, "value class may not be a "+ + context.error(clazz.pos, "value class may not be a "+ (if (clazz.owner.isTerm) "local class" else "member of another class")) if (!clazz.isPrimitiveValueClass) { clazz.primaryConstructor.paramss match { @@ -1360,26 +1360,26 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val decls = clazz.info.decls val paramAccessor = clazz.constrParamAccessors.head if (paramAccessor.isMutable) - unit.error(paramAccessor.pos, "value class parameter must not be a var") + context.error(paramAccessor.pos, "value class parameter must not be a var") val accessor = decls.toList.find(x => x.isMethod && x.accessedOrSelf == paramAccessor) accessor match { case None => - unit.error(paramAccessor.pos, "value class parameter must be a val and not be private[this]") + context.error(paramAccessor.pos, "value class parameter must be a val and not be private[this]") case Some(acc) if acc.isProtectedLocal => - unit.error(paramAccessor.pos, "value class parameter must not be protected[this]") + context.error(paramAccessor.pos, "value class parameter must not be protected[this]") case Some(acc) => if (acc.tpe.typeSymbol.isDerivedValueClass) - unit.error(acc.pos, "value class may not wrap another user-defined value class") + context.error(acc.pos, "value class may not wrap another user-defined value class") checkEphemeral(clazz, body filterNot (stat => stat.symbol != null && stat.symbol.accessedOrSelf == paramAccessor)) } case _ => - unit.error(clazz.pos, "value class needs to have exactly one val parameter") + context.error(clazz.pos, "value class needs to have exactly one val parameter") } } for (tparam <- clazz.typeParams) if (tparam hasAnnotation definitions.SpecializedClass) - unit.error(tparam.pos, "type parameter of value class may not be specialized") + context.error(tparam.pos, "type parameter of value class may not be specialized") } /** Typechecks a parent type reference. @@ -1675,7 +1675,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (!isPastTyper && psym.hasDeprecatedInheritanceAnnotation && !sameSourceFile) { val suffix = psym.deprecatedInheritanceMessage map (": " + _) getOrElse "" val msg = s"inheritance from ${psym.fullLocationString} is deprecated$suffix" - unit.deprecationWarning(parent.pos, psym, msg) + context.deprecationWarning(parent.pos, psym, msg) } if (psym.isSealed && !phase.erasedTypes) @@ -1742,7 +1742,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if ((clazz isNonBottomSubClass ClassfileAnnotationClass) && (clazz != ClassfileAnnotationClass)) { if (!clazz.owner.isPackageClass) - unit.error(clazz.pos, "inner classes cannot be classfile annotations") + context.error(clazz.pos, "inner classes cannot be classfile annotations") else restrictionWarning(cdef.pos, unit, """|subclassing Classfile does not |make your annotation visible at runtime. If that is what @@ -1797,7 +1797,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper private def ensurePredefParentsAreInSameSourceFile(template: Template) = { val parentSyms = template.parents map (_.symbol) filterNot (_ == AnyRefClass) if (parentSyms exists (_.associatedFile != PredefModule.associatedFile)) - unit.error(template.pos, s"All parents of Predef must be defined in ${PredefModule.associatedFile}.") + context.error(template.pos, s"All parents of Predef must be defined in ${PredefModule.associatedFile}.") } /** In order to override this in the TreeCheckers Typer so synthetics aren't re-added * all the time, it is exposed here the module/class typing methods go through it. @@ -1868,7 +1868,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ConstrArgsInParentOfTraitError(parents1.head, clazz) if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.isTopLevel) - unit.error(clazz.pos, "inner classes cannot be classfile annotations") + context.error(clazz.pos, "inner classes cannot be classfile annotations") if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) @@ -1896,7 +1896,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (clazz.isTrait) { for (decl <- clazz.info.decls if decl.isTerm && decl.isEarlyInitialized) { - unit.warning(decl.pos, "Implementation restriction: early definitions in traits are not initialized before the super class is initialized.") + context.warning(decl.pos, "Implementation restriction: early definitions in traits are not initialized before the super class is initialized.") } } @@ -2084,7 +2084,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case xs => xs.map(_.nameString).mkString(" (of ", " with ", ")") } def fail(pos: Position, msg: String): Boolean = { - unit.error(pos, msg) + context.error(pos, msg) false } /* Have to examine all parameters in all lists. @@ -3665,7 +3665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } if (annType.typeSymbol == DeprecatedAttr && argss.flatten.size < 2) - unit.deprecationWarning(ann.pos, DeprecatedAttr, "@deprecated now takes two arguments; see the scaladoc.") + context.deprecationWarning(ann.pos, DeprecatedAttr, "@deprecated now takes two arguments; see the scaladoc.") if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) ErroneousAnnotation else annInfo(typedAnn) @@ -4239,7 +4239,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // it is non-Unit) so we have to retype it. Fortunately it won't come up much // unless the warning is legitimate. if (typed(expr).tpe.typeSymbol != UnitClass) - unit.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded") + context.warning(tree.pos, "enclosing method " + name + " has result type Unit: return value discarded") } val res = treeCopy.Return(tree, checkDead(expr1)).setSymbol(enclMethod.owner) val tp = pluginsTypedReturn(NothingTpe, this, res, restpt.tpe) @@ -4697,7 +4697,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // temporarily use `filter` as an alternative for `withFilter` def tryWithFilterAndFilter(tree: Select, qual: Tree): Tree = { - def warn(sym: Symbol) = unit.deprecationWarning(tree.pos, sym, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead") + def warn(sym: Symbol) = context.deprecationWarning(tree.pos, sym, s"`withFilter' method does not yet exist on ${qual.tpe.widen}, using `filter' method instead") silent(_ => typedSelect(tree, qual, nme.withFilter)) orElse { _ => silent(_ => typed1(Select(qual, nme.filter) setPos tree.pos, mode, pt)) match { case SilentResultValue(res) => warn(res.symbol) ; res @@ -5477,11 +5477,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val commonMessage = "macro defs must have explicitly specified return types" def reportFailure() = { ddef.symbol.setFlag(IS_ERROR) - unit.error(ddef.pos, commonMessage) + context.error(ddef.pos, commonMessage) } def reportWarning(inferredType: Type) = { val explanation = s"inference of $inferredType from macro impl's c.Expr[$inferredType] is deprecated and is going to stop working in 2.12" - unit.deprecationWarning(ddef.pos, ddef.symbol, s"$commonMessage ($explanation)") + context.deprecationWarning(ddef.pos, ddef.symbol, s"$commonMessage ($explanation)") } computeMacroDefTypeFromMacroImplRef(ddef, rhs1) match { case ErrorType => ErrorType -- cgit v1.2.3 From b7242013830510776fbb93bbf0e883532133030c Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 23 Jun 2014 17:50:19 +0200 Subject: Rip out reporting indirection from CompilationUnit Inline the forwarders from CompilationUnit, which should not affect behavior. Since all forwarders lead to global.reporter, don't first navigate to a compilation unit, only to then forward back to global.reporter. The cleanup in the previous commits revealed a ton of confusion regarding how to report an error. This was a mechanical search/replace, which has low potential for messing things up, since the list of available methods are disjoint between `reporter` and `currentRun.reporting`. The changes involving `typer.context` were done previously. Essentially, there are three ways to report: - via typer.context, so that reporting can be silenced (buffered) - via global.currentRun.reporting, which summarizes (e.g., deprecation) - via global.reporter, which is (mostly) stateless and straightforward. Ideally, these should all just go through `global.currentRun.reporting`, with the typing context changing that reporter to buffer where necessary. After the refactor, these are the ways in which we report (outside of typer): - reporter.comment - reporter.echo - reporter.error - reporter.warning - currentRun.reporting.deprecationWarning - currentRun.reporting.incompleteHandled - currentRun.reporting.incompleteInputError - currentRun.reporting.inlinerWarning - currentRun.reporting.uncheckedWarning Before: - c.cunit.error - c.enclosingUnit.deprecationWarning - context.unit.error - context.unit.warning - csymCompUnit.warning - cunit.error - cunit.warning - currentClass.cunit.warning - currentIClazz.cunit.inlinerWarning - currentRun.currentUnit.error - currentRun.reporting - currentUnit.deprecationWarning - currentUnit.error - currentUnit.warning - getContext.unit.warning - getCurrentCUnit.error - global.currentUnit.uncheckedWarning - global.currentUnit.warning - global.reporter - icls.cunit.warning - item.cunit.warning - reporter.comment - reporter.echo - reporter.error - reporter.warning - reporting.deprecationWarning - reporting.incompleteHandled - reporting.incompleteInputError - reporting.inlinerWarning - reporting.uncheckedWarning - typer.context.unit.warning - unit.deprecationWarning - unit.echo - unit.error - unit.incompleteHandled - unit.incompleteInputError - unit.uncheckedWarning - unit.warning - v1.cunit.warning All these methods ended up calling a method on `global.reporter` or on `global.currentRun.reporting` (their interfaces are disjoint). Also clean up `TypeDiagnostics`: inline nearly-single-use private methods. --- .../scala/reflect/macros/contexts/Parsers.scala | 20 +++--- .../scala/tools/nsc/CompilationUnits.scala | 25 +------- src/compiler/scala/tools/nsc/Global.scala | 4 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 10 +-- .../scala/tools/nsc/ast/parser/Scanners.scala | 6 +- .../tools/nsc/ast/parser/SyntaxAnalyzer.scala | 2 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 2 +- .../tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 4 +- .../scala/tools/nsc/backend/jvm/BCodeHelpers.scala | 4 +- .../tools/nsc/backend/jvm/BCodeSkelBuilder.scala | 2 +- .../scala/tools/nsc/backend/jvm/GenASM.scala | 10 +-- .../scala/tools/nsc/backend/jvm/GenBCode.scala | 2 +- .../scala/tools/nsc/backend/jvm/GenJVMASM.scala | 2 +- .../nsc/backend/opt/InlineExceptionHandlers.scala | 4 +- .../scala/tools/nsc/backend/opt/Inliners.scala | 2 +- .../scala/tools/nsc/javac/JavaParsers.scala | 6 +- .../scala/tools/nsc/javac/JavaScanners.scala | 6 +- .../scala/tools/nsc/symtab/classfile/Pickler.scala | 2 +- .../scala/tools/nsc/transform/CleanUp.scala | 8 +-- .../scala/tools/nsc/transform/Constructors.scala | 4 +- .../scala/tools/nsc/transform/Erasure.scala | 10 +-- .../scala/tools/nsc/transform/ExplicitOuter.scala | 2 +- .../tools/nsc/transform/ExtensionMethods.scala | 2 +- .../scala/tools/nsc/transform/LambdaLift.scala | 2 +- src/compiler/scala/tools/nsc/transform/Mixin.scala | 2 +- .../scala/tools/nsc/transform/TailCalls.scala | 6 +- .../scala/tools/nsc/transform/UnCurry.scala | 10 +-- .../tools/nsc/transform/patmat/MatchAnalysis.scala | 4 +- .../nsc/transform/patmat/MatchOptimization.scala | 2 +- .../nsc/transform/patmat/MatchTranslation.scala | 2 +- .../nsc/transform/patmat/MatchTreeMaking.scala | 2 +- .../tools/nsc/transform/patmat/MatchWarnings.scala | 4 +- .../nsc/transform/patmat/PatternMatching.scala | 6 +- .../transform/patmat/ScalacPatternExpanders.scala | 6 +- .../scala/tools/nsc/typechecker/Checkable.scala | 6 +- .../scala/tools/nsc/typechecker/Contexts.scala | 10 +-- .../scala/tools/nsc/typechecker/Infer.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 6 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 74 +++++++++++----------- .../tools/nsc/typechecker/SuperAccessors.scala | 12 ++-- .../scala/tools/nsc/typechecker/TreeCheckers.scala | 4 +- .../tools/nsc/typechecker/TypeDiagnostics.scala | 20 +++--- .../scala/tools/reflect/FormatInterpolator.scala | 2 +- .../scala/tools/nsc/doc/ScaladocAnalyzer.scala | 6 +- 44 files changed, 152 insertions(+), 175 deletions(-) diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala index 9975bd22a0..f4584f3627 100644 --- a/src/compiler/scala/reflect/macros/contexts/Parsers.scala +++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala @@ -9,15 +9,15 @@ trait Parsers { def parse(code: String) = { val sreporter = new StoreReporter() - 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 { - case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg) - } - tree + val oldReporter = global.reporter + try { + global.reporter = sreporter + val parser = newUnitParser(new CompilationUnit(newSourceFile(code, ""))) + val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages()) + sreporter.infos.foreach { + case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg) + } + tree + } finally global.reporter = oldReporter } } \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index b9e745f176..1ad206f519 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -123,28 +123,9 @@ trait CompilationUnits { global: Global => */ val icode: LinkedHashSet[icodes.IClass] = new LinkedHashSet - // reporter and its forwarded methods - def reporter = global.reporter - def reporting = currentRun.reporting - - 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 deprecationWarning(pos: Position, msg: String): Unit = reporting.deprecationWarning(pos, msg) - def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = reporting.deprecationWarning(pos, sym, 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) - - // 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) + // called by ScalaDocAnalyzer, overridden by the IDE (in Reporter) + // TODO: don't use reporter to communicate comments from parser to IDE! + final 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 daf69ffc3f..a6fa3bf1dc 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1434,10 +1434,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) private def checkDeprecatedSettings(unit: CompilationUnit) { // issue warnings for any usage of deprecated settings settings.userSetSettings filter (_.isDeprecated) foreach { s => - unit.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get) + currentRun.reporting.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get) } if (settings.target.value.contains("jvm-1.5")) - unit.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.") + currentRun.reporting.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated: use target for Java 1.6 or above.") } /* An iterator returning all the units being compiled in this run */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index ffc45b21ea..883fd31dbc 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -205,11 +205,11 @@ self => override def newScanner() = new UnitScanner(unit, patches) override def warning(offset: Offset, msg: String) { - unit.warning(o2p(offset), msg) + reporter.warning(o2p(offset), msg) } override def deprecationWarning(offset: Offset, msg: String) { - unit.deprecationWarning(o2p(offset), msg) + currentRun.reporting.deprecationWarning(o2p(offset), msg) } private var smartParsing = false @@ -224,17 +224,17 @@ self => val syntaxErrors = new ListBuffer[(Int, String)] def showSyntaxErrors() = for ((offset, msg) <- syntaxErrors) - unit.error(o2p(offset), msg) + reporter.error(o2p(offset), msg) override def syntaxError(offset: Offset, msg: String) { if (smartParsing) syntaxErrors += ((offset, msg)) - else unit.error(o2p(offset), msg) + else reporter.error(o2p(offset), msg) } override def incompleteInputError(msg: String) { val offset = source.content.length - 1 if (smartParsing) syntaxErrors += ((offset, msg)) - else unit.incompleteInputError(o2p(offset), msg) + else currentRun.reporting.incompleteInputError(o2p(offset), msg) } /** parse unit. If there are inbalanced braces, diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index e8d46704c3..572497ac90 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -1259,9 +1259,9 @@ trait Scanners extends ScannersCommon { class UnitScanner(val unit: CompilationUnit, patches: List[BracePatch]) extends SourceFileScanner(unit.source) { def this(unit: CompilationUnit) = this(unit, List()) - override def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg) - override def error (off: Offset, msg: String) = unit.error(unit.position(off), msg) - override def incompleteInputError(off: Offset, msg: String) = unit.incompleteInputError(unit.position(off), msg) + override def deprecationWarning(off: Offset, msg: String) = currentRun.reporting.deprecationWarning(unit.position(off), msg) + override def error (off: Offset, msg: String) = reporter.error(unit.position(off), msg) + override def incompleteInputError(off: Offset, msg: String) = currentRun.reporting.incompleteInputError(unit.position(off), msg) private var bracePatches: List[BracePatch] = patches diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index 3d8a7d2e55..64b762696e 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 (unit.incompleteHandled) newUnitParser(unit).parse() + else if (currentRun.reporting.incompleteHandled) newUnitParser(unit).parse() else newUnitParser(unit).smartParse() } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 0ad3c2c76b..d9f56b47fa 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -680,7 +680,7 @@ abstract class GenICode extends SubComponent { val dims = arr.dimensions var elemKind = arr.elementKind if (args.length > dims) - unit.error(tree.pos, "too many arguments for array constructor: found " + args.length + + reporter.error(tree.pos, "too many arguments for array constructor: found " + args.length + " but array has only " + dims + " dimension(s)") if (args.length != dims) for (i <- args.length until dims) elemKind = ARRAY(elemKind) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index bffa4bc51d..4583462b71 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -504,7 +504,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { case nextCleanup :: rest => if (saveReturnValue) { if (insideCleanupBlock) { - cunit.warning(r.pos, "Return statement found in finally-clause, discarding its return-value in favor of that of a more deeply nested return.") + reporter.warning(r.pos, "Return statement found in finally-clause, discarding its return-value in favor of that of a more deeply nested return.") bc drop returnType } else { // regarding return value, the protocol is: in place of a `return-stmt`, a sequence of `adapt, store, jump` are inserted. @@ -602,7 +602,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { var elemKind = arr.elementType val argsSize = args.length if (argsSize > dims) { - cunit.error(app.pos, s"too many arguments for array constructor: found ${args.length} but array has only $dims dimension(s)") + reporter.error(app.pos, s"too many arguments for array constructor: found ${args.length} but array has only $dims dimension(s)") } if (argsSize < dims) { /* In one step: diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 51bfdf0027..31a392ed55 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -38,7 +38,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { outputDirectory(csym) } catch { case ex: Throwable => - cunit.error(cunit.body.pos, s"Couldn't create file for class $cName\n${ex.getMessage}") + reporter.error(cunit.body.pos, s"Couldn't create file for class $cName\n${ex.getMessage}") null } } @@ -141,7 +141,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters { */ def apply(sym: Symbol, csymCompUnit: CompilationUnit): Boolean = { def fail(msg: String, pos: Position = sym.pos) = { - csymCompUnit.warning(sym.pos, + reporter.warning(sym.pos, sym.name + s" has a main method with parameter type Array[String], but ${sym.fullName('.')} will not be a runnable program.\n Reason: $msg" // TODO: make this next claim true, if possible diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index effc68c5e3..8845ffa0cd 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -570,7 +570,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { if (params.size > MaximumJvmParameters) { // SI-7324 - cunit.error(methSymbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.") + reporter.error(methSymbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.") return } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 988c04f514..b0fb3069c1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -113,7 +113,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { // Warn when classes will overwrite one another on case-insensitive systems. for ((_, v1 :: v2 :: _) <- sortedClasses groupBy (_.symbol.javaClassName.toString.toLowerCase)) { - v1.cunit.warning(v1.symbol.pos, + reporter.warning(v1.symbol.pos, s"Class ${v1.symbol.javaClassName} differs only in case from ${v2.symbol.javaClassName}. " + "Such classes will overwrite one another on case-insensitive filesystems.") } @@ -141,7 +141,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { try emitFor(c) catch { case e: FileConflictException => - c.cunit.error(c.symbol.pos, s"error writing ${c.symbol}: ${e.getMessage}") + reporter.error(c.symbol.pos, s"error writing ${c.symbol}: ${e.getMessage}") } sortedClasses = sortedClasses.tail classes -= c.symbol // GC opportunity @@ -1363,7 +1363,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { if (m.symbol.isStaticConstructor || definitions.isGetClass(m.symbol)) return if (m.params.size > MaximumJvmParameters) { - getCurrentCUnit().error(m.symbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.") + reporter.error(m.symbol.pos, s"Platform restriction: a parameter list's length cannot exceed $MaximumJvmParameters.") return } @@ -3245,7 +3245,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { } if(!isValidSignature) { - unit.warning(sym.pos, + reporter.warning(sym.pos, """|compiler bug: created invalid generic signature for %s in %s |signature: %s |if this is reproducible, please report bug at https://issues.scala-lang.org/ @@ -3258,7 +3258,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe)) val bytecodeTpe = owner.thisType.memberInfo(sym) if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) { - unit.warning(sym.pos, + reporter.warning(sym.pos, """|compiler bug: created generic signature for %s in %s that does not conform to its erasure |signature: %s |original type: %s diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index 9b292fee7f..a401de05e5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -156,7 +156,7 @@ abstract class GenBCode extends BCodeSyncAndTry { case None => caseInsensitively.put(lowercaseJavaClassName, claszSymbol) case Some(dupClassSym) => - item.cunit.warning( + reporter.warning( claszSymbol.pos, s"Class ${claszSymbol.javaClassName} differs only in case from ${dupClassSym.javaClassName}. " + "Such classes will overwrite one another on case-insensitive filesystems." diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala index 01c4ff5a52..2bcde7f7b9 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVMASM.scala @@ -27,7 +27,7 @@ trait GenJVMASM { protected def isJavaEntryPoint(icls: IClass) = { val sym = icls.symbol def fail(msg: String, pos: Position = sym.pos) = { - icls.cunit.warning(sym.pos, + reporter.warning(sym.pos, sym.name + " has a main method with parameter type Array[String], but " + sym.fullName('.') + " will not be a runnable program.\n" + " Reason: " + msg // TODO: make this next claim true, if possible diff --git a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala index 235e954f88..425c10d153 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/InlineExceptionHandlers.scala @@ -182,7 +182,7 @@ abstract class InlineExceptionHandlers extends SubComponent { // in other words: what's on the stack MUST conform to what's in the THROW(..)! if (!canReplaceHandler) { - currentClass.cunit.warning(NoPosition, "Unable to inline the exception handler inside incorrect" + + reporter.warning(NoPosition, "Unable to inline the exception handler inside incorrect" + " block:\n" + bblock.iterator.mkString("\n") + "\nwith stack: " + typeInfo + " just " + "before instruction index " + index) } @@ -383,7 +383,7 @@ abstract class InlineExceptionHandlers extends SubComponent { Some((exceptionLocal, copy)) case _ => - currentClass.cunit.warning(NoPosition, "Unable to inline the exception handler due to incorrect format:\n" + + reporter.warning(NoPosition, "Unable to inline the exception handler due to incorrect format:\n" + handler.iterator.mkString("\n")) None } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index f6de522d09..8df3969c49 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -195,7 +195,7 @@ abstract class Inliners extends SubComponent { /** The current iclass */ private var currentIClazz: IClass = _ - private def warn(pos: Position, msg: String) = currentIClazz.cunit.inlinerWarning(pos, msg) + private def warn(pos: Position, msg: String) = currentRun.reporting.inlinerWarning(pos, msg) private def ownedName(sym: Symbol): String = exitingUncurry { val count = ( diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index a61ad392ee..37b00aa9a3 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -26,10 +26,10 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { def freshName(prefix: String): Name = freshTermName(prefix) def freshTermName(prefix: String): TermName = unit.freshTermName(prefix) def freshTypeName(prefix: String): TypeName = unit.freshTypeName(prefix) - def deprecationWarning(off: Int, msg: String) = unit.deprecationWarning(off, msg) + def deprecationWarning(off: Int, msg: String) = currentRun.reporting.deprecationWarning(off, msg) implicit def i2p(offset : Int) : Position = Position.offset(unit.source, offset) - def warning(pos : Int, msg : String) : Unit = unit.warning(pos, msg) - def syntaxError(pos: Int, msg: String) : Unit = unit.error(pos, msg) + def warning(pos : Int, msg : String) : Unit = reporter.warning(pos, msg) + def syntaxError(pos: Int, msg: String) : Unit = reporter.error(pos, msg) } abstract class JavaParser extends ParserCommon { diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index c5401219dd..bddcf6567c 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -860,9 +860,9 @@ trait JavaScanners extends ast.parser.ScannersCommon { class JavaUnitScanner(unit: CompilationUnit) extends JavaScanner { in = new JavaCharArrayReader(unit.source.content, !settings.nouescape.value, syntaxError) init() - def error (pos: Int, msg: String) = unit. error(pos, msg) - def incompleteInputError(pos: Int, msg: String) = unit.incompleteInputError(pos, msg) - def deprecationWarning(pos: Int, msg: String) = unit.deprecationWarning(pos, msg) + def error (pos: Int, msg: String) = reporter.error(pos, msg) + def incompleteInputError(pos: Int, msg: String) = currentRun.reporting.incompleteInputError(pos, msg) + def deprecationWarning(pos: Int, msg: String) = currentRun.reporting.deprecationWarning(pos, msg) implicit def g2p(pos: Int): Position = Position.offset(unit.source, pos) } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 592c5497b5..2fc00fe068 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -69,7 +69,7 @@ abstract class Pickler extends SubComponent { // OPT: do this only as a recovery after fatal error. Checking in advance was expensive. if (t.isErroneous) { if (settings.debug) e.printStackTrace() - unit.error(t.pos, "erroneous or inaccessible type") + reporter.error(t.pos, "erroneous or inaccessible type") return } } diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index f14fce5de9..1664fe0e0d 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -76,7 +76,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { val qual0 = ad.qual val params = ad.args if (settings.logReflectiveCalls) - unit.echo(ad.pos, "method invocation uses reflection") + reporter.echo(ad.pos, "method invocation uses reflection") val typedPos = typedWithPos(ad.pos) _ @@ -360,13 +360,13 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { assert(params.length == mparams.length, ((params, mparams))) (mparams, resType) case tpe @ OverloadedType(pre, alts) => - unit.warning(ad.pos, s"Overloaded type reached the backend! This is a bug in scalac.\n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe)) + reporter.warning(ad.pos, s"Overloaded type reached the backend! This is a bug in scalac.\n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe)) alts filter (_.paramss.flatten.size == params.length) map (_.tpe) match { case mt @ MethodType(mparams, resType) :: Nil => - unit.warning(NoPosition, "Only one overload has the right arity, proceeding with overload " + mt) + reporter.warning(NoPosition, "Only one overload has the right arity, proceeding with overload " + mt) (mparams, resType) case _ => - unit.error(ad.pos, "Cannot resolve overload.") + reporter.error(ad.pos, "Cannot resolve overload.") (Nil, NoType) } } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 391bce5abb..f471440293 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -54,7 +54,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { def check(tree: Tree) = { for (t <- tree) t match { case t: RefTree if uninitializedVals(t.symbol.accessedOrSelf) && t.qualifier.symbol == clazz => - unit.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}") + reporter.warning(t.pos, s"Reference to uninitialized ${t.symbol.accessedOrSelf}") case _ => } } @@ -685,7 +685,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL { // mangling before we introduce more of it. val conflict = clazz.info.nonPrivateMember(acc.name) filter (s => s.isGetter && !s.isOuterField && s.enclClass.isTrait) if (conflict ne NoSymbol) - unit.error(acc.pos, "parameter '%s' requires field but conflicts with %s".format(acc.name, conflict.fullLocationString)) + reporter.error(acc.pos, "parameter '%s' requires field but conflicts with %s".format(acc.name, conflict.fullLocationString)) copyParam(acc, parameter(acc)) } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 2f2142027f..ec4deb6be0 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -488,7 +488,7 @@ abstract class Erasure extends AddInterfaces || (checkBridgeOverrides(member, other, bridge) match { case Nil => true case es if member.owner.isAnonymousClass => resolveAnonymousBridgeClash(member, bridge); true - case es => for ((pos, msg) <- es) unit.error(pos, msg); false + case es => for ((pos, msg) <- es) reporter.error(pos, msg); false }) ) @@ -724,7 +724,7 @@ abstract class Erasure extends AddInterfaces ) val when = if (exitingRefchecks(lowType matches highType)) "" else " after erasure: " + exitingPostErasure(highType) - unit.error(pos, + reporter.error(pos, s"""|$what: |${exitingRefchecks(highString)} and |${exitingRefchecks(lowString)} @@ -865,7 +865,7 @@ abstract class Erasure extends AddInterfaces fn match { case TypeApply(sel @ Select(qual, name), List(targ)) => if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefTpe) - unit.error(sel.pos, "isInstanceOf cannot test if value types are references.") + reporter.error(sel.pos, "isInstanceOf cannot test if value types are references.") def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree = Apply( @@ -952,7 +952,7 @@ abstract class Erasure extends AddInterfaces case nme.length => nme.array_length case nme.update => nme.array_update case nme.clone_ => nme.array_clone - case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME + case _ => reporter.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME } gen.mkRuntimeCall(arrayMethodName, qual :: args) } @@ -1055,7 +1055,7 @@ abstract class Erasure extends AddInterfaces qual match { case Super(_, _) => // Insert a cast here at your peril -- see SI-5162. - unit.error(tree.pos, s"Unable to access ${tree.symbol.fullLocationString} with a super reference.") + reporter.error(tree.pos, s"Unable to access ${tree.symbol.fullLocationString} with a super reference.") tree case _ => // Todo: Figure out how qual.tpe could be null in the check above (it does appear in build where SwingWorker.this diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 0447e23e9e..c291961447 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -481,7 +481,7 @@ abstract class ExplicitOuter extends InfoTransform // since we can't fix SI-4440 properly (we must drop the outer accessors of final classes when there's no immediate reference to them in sight) // at least don't crash... this duplicates maybeOmittable from constructors (acc.owner.isEffectivelyFinal && !acc.isOverridingSymbol)) { - unit.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.") + currentRun.reporting.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.") transform(TRUE) // urgh... drop condition if there's no accessor (or if it may disappear after constructors) } else { // println("(base, acc)= "+(base, acc)) diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 2235a93ca4..228c9da624 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -127,7 +127,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: Symbol): Unit = if (seen contains clazz) - unit.error(pos, "value class may not unbox to itself") + reporter.error(pos, "value class may not unbox to itself") else { val unboxed = definitions.underlyingOfValueClass(clazz).typeSymbol if (unboxed.isDerivedValueClass) checkNonCyclic(pos, seen + clazz, unboxed) diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index e38c034f4d..f85d8222f0 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -339,7 +339,7 @@ abstract class LambdaLift extends InfoTransform { if (clazz.isStaticOwner) clazz.fullLocationString else s"the unconstructed `this` of ${clazz.fullLocationString}" val msg = s"Implementation restriction: access of ${sym.fullLocationString} from ${currentClass.fullLocationString}, would require illegal premature access to $what" - currentUnit.error(curTree.pos, msg) + reporter.error(curTree.pos, msg) } val qual = if (clazz == currentClass) gen.mkAttributedThis(clazz) diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 313d0a6e61..7927875583 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -336,7 +336,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { rebindSuper(clazz, mixinMember.alias, mixinClass) match { case NoSymbol => - unit.error(clazz.pos, "Member %s of mixin %s is missing a concrete super implementation.".format( + reporter.error(clazz.pos, "Member %s of mixin %s is missing a concrete super implementation.".format( mixinMember.alias, mixinClass)) case alias1 => superAccessor.asInstanceOf[TermSymbol] setAlias alias1 diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index d9d1192772..ef534f70fd 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -96,7 +96,7 @@ abstract class TailCalls extends Transform { val failReason = failReasons(ctx) val failPos = failPositions(ctx) - unit.error(failPos, s"could not optimize @tailrec annotated $method: $failReason") + reporter.error(failPos, s"could not optimize @tailrec annotated $method: $failReason") } /** Has the label been accessed? Then its symbol is in this set. */ @@ -268,14 +268,14 @@ abstract class TailCalls extends Transform { tree match { case ValDef(_, _, _, _) => if (tree.symbol.isLazy && tree.symbol.hasAnnotation(TailrecClass)) - unit.error(tree.pos, "lazy vals are not tailcall transformed") + reporter.error(tree.pos, "lazy vals are not tailcall transformed") super.transform(tree) case dd @ DefDef(_, name, _, vparamss0, _, rhs0) if isEligible(dd) => val newCtx = new DefDefTailContext(dd) if (newCtx.isMandatory && !(newCtx containsRecursiveCall rhs0)) - unit.error(tree.pos, "@tailrec annotated method contains no recursive calls") + reporter.error(tree.pos, "@tailrec annotated method contains no recursive calls") debuglog(s"Considering $name for tailcalls, with labels in tailpos: ${newCtx.tailLabels}") val newRHS = transform(rhs0, newCtx) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index d77c6b54a9..2209aac00f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -93,7 +93,7 @@ abstract class UnCurry extends InfoTransform override def transform(tree: Tree): Tree = ( try postTransform(mainTransform(tree)) catch { case ex: TypeError => - unit.error(ex.pos, ex.msg) + reporter.error(ex.pos, ex.msg) debugStack(ex) EmptyTree } @@ -174,7 +174,7 @@ abstract class UnCurry extends InfoTransform cdef <- catches if catchesThrowable(cdef) && !isSyntheticCase(cdef) } { - unit.warning(body.pos, "catch block may intercept non-local return from " + meth) + reporter.warning(body.pos, "catch block may intercept non-local return from " + meth) } Block(List(keyDef), tryCatch) @@ -706,10 +706,10 @@ abstract class UnCurry extends InfoTransform */ private def saveRepeatedParams(dd: DefDef): Unit = if (dd.symbol.isConstructor) - unit.error(dd.symbol.pos, "A constructor cannot be annotated with a `varargs` annotation.") + reporter.error(dd.symbol.pos, "A constructor cannot be annotated with a `varargs` annotation.") else treeInfo.repeatedParams(dd) match { case Nil => - unit.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.") + reporter.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.") case reps => repeatedParams(dd.symbol) = reps } @@ -782,7 +782,7 @@ abstract class UnCurry extends InfoTransform // check if the method with that name and those arguments already exists in the template currentClass.info.member(forwsym.name).alternatives.find(s => s != forwsym && s.tpe.matches(forwsym.tpe)) match { - case Some(s) => unit.error(dd.symbol.pos, + case Some(s) => reporter.error(dd.symbol.pos, "A method with a varargs annotation produces a forwarder method with the same signature " + s.tpe + " as an existing method.") case None => diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index e1a663ea41..6f81cbe152 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -51,7 +51,7 @@ trait TreeAndTypeAnalysis extends Debugging { // This is a pretty poor approximation. def unsoundAssumptionUsed = binder.name != nme.WILDCARD && !(pt <:< pat.tpe) if (settings.lint && unsoundAssumptionUsed) - global.currentUnit.warning(pat.pos, + reporter.warning(pat.pos, sm"""The value matched by $pat is bound to ${binder.name}, which may be used under the |unsound assumption that it has type ${pat.tpe}, whereas we can only safely |count on it having type $pt, as the pattern is matched using `==` (see SI-1503).""") @@ -398,7 +398,7 @@ trait MatchAnalysis extends MatchApproximation { import global.definitions._ trait MatchAnalyzer extends MatchApproximator { - def uncheckedWarning(pos: Position, msg: String) = global.currentUnit.uncheckedWarning(pos, msg) + def uncheckedWarning(pos: Position, msg: String) = currentRun.reporting.uncheckedWarning(pos, msg) def warn(pos: Position, ex: AnalysisBudget.Exception, kind: String) = uncheckedWarning(pos, s"Cannot check match for $kind.\n${ex.advice}") // TODO: model dependencies between variables: if V1 corresponds to (x: List[_]) and V2 is (x.hd), V2 cannot be assigned when V1 = null or V1 = Nil diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala index 8ff7824159..e9c81f4728 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala @@ -442,7 +442,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis { val distinctAlts = distinctBy(switchableAlts)(extractConst) if (distinctAlts.size < switchableAlts.size) { val duplicated = switchableAlts.groupBy(extractConst).flatMap(_._2.drop(1).take(1)) // report the first duplicated - global.currentUnit.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}") + reporter.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}") } CaseDef(Alternative(distinctAlts), guard, body) } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index 4cf8980689..0eaffe7cee 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -154,7 +154,7 @@ trait MatchTranslation { case SymbolBound(sym, expr) => bindingStep(sym, expr) case Literal(Constant(_)) | Ident(_) | Select(_, _) | This(_) => equalityTestStep() case Alternative(alts) => alternativesStep(alts) - case _ => context.unit.error(pos, unsupportedPatternMsg) ; noStep() + case _ => reporter.error(pos, unsupportedPatternMsg) ; noStep() } def translate(): List[TreeMaker] = nextStep() merge (_.translate()) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index 5d8a9fecef..1974befb45 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -558,7 +558,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { } emitSwitch(scrut, scrutSym, casesNoSubstOnly, pt, matchFailGenOverride, suppression.exhaustive).getOrElse{ - if (requireSwitch) typer.context.unit.warning(scrut.pos, "could not emit switch for @switch annotated match") + if (requireSwitch) reporter.warning(scrut.pos, "could not emit switch for @switch annotated match") if (casesNoSubstOnly nonEmpty) { // before optimizing, check casesNoSubstOnly for presence of a default case, diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala index a7d7680db1..9e9372f709 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchWarnings.scala @@ -67,7 +67,7 @@ trait MatchWarnings { val cdef = it.next() // If a default case has been seen, then every succeeding case is unreachable. if (vpat != null) - context.unit./*error*/warning(cdef.body.pos, "unreachable code due to " + vpat + addendum(cdef.pat)) + reporter.warning(cdef.body.pos, "unreachable code due to " + vpat + addendum(cdef.pat)) // TODO: make configurable whether this is an error // If this is a default case and more cases follow, warn about this one so // we have a reason to mention its pattern variable name and any corresponding // symbol in scope. Errors will follow from the remaining cases, at least @@ -78,7 +78,7 @@ trait MatchWarnings { case _ => "" } vpat = s"variable pattern$vpatName on line ${cdef.pat.pos.line}" - context.unit.warning(cdef.pos, s"patterns after a variable pattern cannot match (SLS 8.1.1)" + addendum(cdef.pat)) + reporter.warning(cdef.pos, s"patterns after a variable pattern cannot match (SLS 8.1.1)" + addendum(cdef.pat)) } } } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala index f6c960d089..ef50e083a1 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/PatternMatching.scala @@ -65,7 +65,7 @@ trait PatternMatching extends Transform } catch { case x: (Types#TypeError) => // TODO: this should never happen; error should've been reported during type checking - unit.error(tree.pos, "error during expansion of this match (this is a scalac bug).\nThe underlying error was: "+ x.msg) + reporter.error(tree.pos, "error during expansion of this match (this is a scalac bug).\nThe underlying error was: "+ x.msg) translated } case Try(block, catches, finalizer) => @@ -175,13 +175,13 @@ trait Interface extends ast.TreeDSL { val matchOwner = typer.context.owner def pureType(tp: Type): Type = tp - def reportUnreachable(pos: Position) = typer.context.unit.warning(pos, "unreachable code") + def reportUnreachable(pos: Position) = reporter.warning(pos, "unreachable code") def reportMissingCases(pos: Position, counterExamples: List[String]) = { val ceString = if (counterExamples.tail.isEmpty) "input: " + counterExamples.head else "inputs: " + counterExamples.mkString(", ") - typer.context.unit.warning(pos, "match may not be exhaustive.\nIt would fail on the following "+ ceString) + reporter.warning(pos, "match may not be exhaustive.\nIt would fail on the following "+ ceString) } } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala index c19786d5e7..8f21f4ecfc 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/ScalacPatternExpanders.scala @@ -103,8 +103,8 @@ trait ScalacPatternExpanders { def offerString = if (extractor.isErroneous) "" else s" offering $offering" def arityExpected = ( if (extractor.hasSeq) "at least " else "" ) + productArity - def err(msg: String) = currentUnit.error(tree.pos, msg) - def warn(msg: String) = currentUnit.warning(tree.pos, msg) + def err(msg: String) = reporter.error(tree.pos, msg) + def warn(msg: String) = reporter.warning(tree.pos, msg) def arityError(what: String) = err(s"$what patterns for $owner$offerString: expected $arityExpected, found $totalArity") if (isStar && !isSeq) @@ -141,7 +141,7 @@ trait ScalacPatternExpanders { if (requiresTupling && effectivePatternArity(args) == 1) { val sym = sel.symbol.owner - currentUnit.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)") + currentRun.reporting.deprecationWarning(sel.pos, sym, s"${sym} expects $productArity patterns$acceptMessage but crushing into $productArity-tuple to fit single pattern (SI-6675)") } val normalizedExtractor = if (requiresTupling) tupleExtractor(extractor) else extractor diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala index 13884404b3..3a77cab919 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala @@ -275,7 +275,7 @@ trait Checkable { ; // Matching on types like case _: AnyRef { def bippy: Int } => doesn't work -- yet. case RefinedType(_, decls) if !decls.isEmpty => - getContext.unit.warning(tree.pos, s"a pattern match on a refinement type is unchecked") + reporter.warning(tree.pos, s"a pattern match on a refinement type is unchecked") case RefinedType(parents, _) => parents foreach (p => checkCheckable(tree, p, X, inPattern, canRemedy)) case _ => @@ -285,14 +285,14 @@ trait Checkable { if (checker.neverMatches) { val addendum = if (checker.neverSubClass) "" else " (but still might match its erasure)" - getContext.unit.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $PString$addendum") + reporter.warning(tree.pos, s"fruitless type test: a value of type $X cannot also be a $PString$addendum") } else if (checker.isUncheckable) { val msg = ( if (checker.uncheckableType =:= P) s"abstract type $where$PString" else s"${checker.uncheckableMessage} in type $where$PString" ) - getContext.unit.warning(tree.pos, s"$msg is unchecked since it is eliminated by erasure") + reporter.warning(tree.pos, s"$msg is unchecked since it is eliminated by erasure") } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 03890f30f6..20f0405d1b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -66,7 +66,7 @@ trait Contexts { self: Analyzer => def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel => - unit.warning(imp posOf sel, "Unused import") + reporter.warning(imp posOf sel, "Unused import") } } allUsedSelectors --= imps @@ -103,7 +103,7 @@ trait Contexts { self: Analyzer => // there must be a scala.xml package when xml literals were parsed in this unit if (unit.hasXml && ScalaXmlPackage == NoSymbol) - unit.error(unit.firstXmlPos, "To compile XML syntax, the scala.xml package must be on the classpath.\nPlease see http://docs.scala-lang.org/overviews/core/scala-2.11.html#scala-xml.") + reporter.error(unit.firstXmlPos, "To compile XML syntax, the scala.xml package must be on the classpath.\nPlease see http://docs.scala-lang.org/overviews/core/scala-2.11.html#scala-xml.") // scala-xml needs `scala.xml.TopScope` to be in scope globally as `$scope` // We detect `scala-xml` by looking for `scala.xml.TopScope` and @@ -359,7 +359,7 @@ trait Contexts { self: Analyzer => /** Issue and clear all warnings from the report buffer */ def flushAndIssueWarnings() { reportBuffer.warnings foreach { - case (pos, msg) => unit.warning(pos, msg) + case (pos, msg) => reporter.warning(pos, msg) } reportBuffer.clearAllWarnings() } @@ -541,7 +541,7 @@ trait Contexts { self: Analyzer => } private def unitError(pos: Position, msg: String): Unit = - if (checking) onTreeCheckerError(pos, msg) else unit.error(pos, msg) + if (checking) onTreeCheckerError(pos, msg) else reporter.error(pos, msg) @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) { // TODO: are errors allowed to have pos == NoPosition?? @@ -589,7 +589,7 @@ trait Contexts { self: Analyzer => /** Issue/throw the given error message according to the current mode for error reporting. */ def warning(pos: Position, msg: String, force: Boolean = false) { - if (reportErrors || force) unit.warning(pos, msg) + if (reportErrors || force) reporter.warning(pos, msg) else if (bufferErrors) reportBuffer += (pos -> msg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index fc0e2c7c80..a3f1da60ce 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -558,7 +558,7 @@ trait Infer extends Checkable { foreachWithIndex(targs) ((targ, idx) => targ.typeSymbol match { case sym @ (AnyClass | AnyValClass) => - context.unit.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") + reporter.warning(argumentPosition(idx), s"a type was inferred to be `${sym.name}`; this may indicate a programming error.") case _ => } ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 099031d536..1328119aac 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -443,7 +443,7 @@ trait Namers extends MethodSynthesis { && clazz.exists ) if (fails) { - context.unit.error(tree.pos, ( + reporter.error(tree.pos, ( s"Companions '$clazz' and '$module' must be defined in same file:\n" + s" Found in ${clazz.sourceFile.canonicalPath} and ${module.sourceFile.canonicalPath}") ) @@ -718,7 +718,7 @@ trait Namers extends MethodSynthesis { } val owner = tree.symbol.owner if (settings.lint && owner.isPackageObjectClass && !mods.isImplicit) { - context.unit.warning(tree.pos, + reporter.warning(tree.pos, "it is not recommended to define classes/objects inside of package objects.\n" + "If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead." ) @@ -730,7 +730,7 @@ trait Namers extends MethodSynthesis { log("enter implicit wrapper "+tree+", owner = "+owner) enterImplicitWrapper(tree) } - else context.unit.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter") + else reporter.error(tree.pos, "implicit classes must accept exactly one primary constructor parameter") } validateCompanionDefs(tree) } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 0d79637c88..1c84f8d759 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -147,7 +147,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans val owners = haveDefaults map (_.owner) // constructors of different classes are allowed to have defaults if (haveDefaults.exists(x => !x.isConstructor) || owners.distinct.size < haveDefaults.size) { - unit.error(clazz.pos, + reporter.error(clazz.pos, "in "+ clazz + ", multiple overloaded alternatives of "+ haveDefaults.head + " define default arguments" + ( @@ -162,7 +162,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // Check for doomed attempt to overload applyDynamic if (clazz isSubClass DynamicClass) { for ((_, m1 :: m2 :: _) <- (clazz.info member nme.applyDynamic).alternatives groupBy (_.typeParams.length)) { - unit.error(m1.pos, "implementation restriction: applyDynamic cannot be overloaded except by methods with different numbers of type parameters, e.g. applyDynamic[T1](method: String)(arg: T1) and applyDynamic[T1, T2](method: String)(arg1: T1, arg2: T2)") + reporter.error(m1.pos, "implementation restriction: applyDynamic cannot be overloaded except by methods with different numbers of type parameters, e.g. applyDynamic[T1](method: String)(arg: T1) and applyDynamic[T1, T2](method: String)(arg1: T1, arg2: T2)") } } @@ -172,7 +172,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // implicit classes leave both a module symbol and a method symbol as residue val alts = clazz.info.decl(sym.name).alternatives filterNot (_.isModule) if (alts.size > 1) - alts foreach (x => unit.warning(x.pos, "parameterized overloaded implicit methods are not visible as view bounds")) + alts foreach (x => reporter.warning(x.pos, "parameterized overloaded implicit methods are not visible as view bounds")) } } } @@ -281,10 +281,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans mixinOverrideErrors.toList match { case List() => case List(MixinOverrideError(_, msg)) => - unit.error(clazz.pos, msg) + reporter.error(clazz.pos, msg) case MixinOverrideError(member, msg) :: others => val others1 = others.map(_.member.name.decode).filter(member.name.decode != _).distinct - unit.error( + reporter.error( clazz.pos, msg+(if (others1.isEmpty) "" else ";\n other members with override errors are: "+(others1 mkString ", "))) @@ -347,7 +347,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans ) } def emitOverrideError(fullmsg: String) { - if (member.owner == clazz) unit.error(member.pos, fullmsg) + if (member.owner == clazz) reporter.error(member.pos, fullmsg) else mixinOverrideErrors += new MixinOverrideError(member, fullmsg) } @@ -464,7 +464,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkOverrideDeprecated() if (settings.warnNullaryOverride) { if (other.paramss.isEmpty && !member.paramss.isEmpty) { - unit.warning(member.pos, "non-nullary method overrides nullary method") + reporter.warning(member.pos, "non-nullary method overrides nullary method") } } } @@ -496,7 +496,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans typer.infer.checkKindBounds(high :: Nil, lowType :: Nil, rootType, low.owner) match { // (1.7.2) case Nil => case kindErrors => - unit.error(member.pos, + reporter.error(member.pos, "The kind of "+member.keyString+" "+member.varianceString + member.nameString+ " does not conform to the expected kind of " + other.defString + other.locationString + "." + kindErrors.toList.mkString("\n", ", ", "")) @@ -507,7 +507,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans typer.infer.checkKindBounds(low :: Nil, lowType.normalize :: Nil, rootType, low.owner) match { case Nil => case kindErrors => - unit.error(member.pos, + reporter.error(member.pos, "The kind of the right-hand side "+lowType.normalize+" of "+low.keyString+" "+ low.varianceString + low.nameString+ " does not conform to its expected kind."+ kindErrors.toList.mkString("\n", ", ", "")) @@ -546,7 +546,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if (other.hasDeprecatedOverridingAnnotation) { val suffix = other.deprecatedOverridingMessage map (": " + _) getOrElse "" val msg = s"overriding ${other.fullLocationString} is deprecated$suffix" - unit.deprecationWarning(member.pos, other, msg) + currentRun.reporting.deprecationWarning(member.pos, other, msg) } } } @@ -754,7 +754,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkNoAbstractDecls(clazz) if (abstractErrors.nonEmpty) - unit.error(clazz.pos, abstractErrorMessage) + reporter.error(clazz.pos, abstractErrorMessage) } else if (clazz.isTrait && !(clazz isSubClass AnyValClass)) { // For non-AnyVal classes, prevent abstract methods in interfaces that override @@ -765,7 +765,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // override a concrete method in Object. The jvm, however, does not. val overridden = decl.matchingSymbol(ObjectClass, ObjectTpe) if (overridden.isFinal) - unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") + reporter.error(decl.pos, "trait cannot redefine final method from class AnyRef") } } @@ -818,7 +818,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // for (bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG val nonMatching: List[Symbol] = clazz.info.member(member.name).alternatives.filterNot(_.owner == clazz).filterNot(_.isFinal) - def issueError(suffix: String) = unit.error(member.pos, member.toString() + " overrides nothing" + suffix) + def issueError(suffix: String) = reporter.error(member.pos, member.toString() + " overrides nothing" + suffix) nonMatching match { case Nil => issueError("") @@ -871,7 +871,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case _ :: Nil => ;// OK case tp1 :: tp2 :: _ => - unit.error(clazz.pos, "illegal inheritance;\n " + clazz + + reporter.error(clazz.pos, "illegal inheritance;\n " + clazz + " inherits different type instances of " + baseClass + ":\n" + tp1 + " and " + tp2) explainTypes(tp1, tp2) @@ -888,7 +888,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case _ => "type "+tp } override def issueVarianceError(base: Symbol, sym: Symbol, required: Variance) { - currentRun.currentUnit.error(base.pos, + reporter.error(base.pos, s"${sym.variance} $sym occurs in $required position in ${tpString(base.info)} of $base") } } @@ -956,7 +956,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.lint) (fn, args) match { case (tap@TypeApply(fun, targs), List(view: ApplyImplicitView)) if fun.symbol == currentRun.runDefinitions.Option_apply => - unit.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567 + reporter.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567 case _ => } @@ -1031,7 +1031,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def nonSensibleWarning(what: String, alwaysEqual: Boolean) = { val msg = alwaysEqual == (name == nme.EQ || name == nme.eq) - unit.warning(pos, s"comparing $what using `${name.decode}' will always yield $msg") + reporter.warning(pos, s"comparing $what using `${name.decode}' will always yield $msg") isNonSensible = true } def nonSensible(pre: String, alwaysEqual: Boolean) = @@ -1046,7 +1046,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } def unrelatedTypes() = if (!isNonSensible) { val weaselWord = if (isEitherValueClass) "" else " most likely" - unit.warning(pos, s"$typesString are unrelated: they will$weaselWord $unrelatedMsg") + reporter.warning(pos, s"$typesString are unrelated: they will$weaselWord $unrelatedMsg") } if (nullCount == 2) // null == null @@ -1141,7 +1141,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans && callsSelf ) if (trivialInifiniteLoop) - unit.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively") + reporter.warning(valOrDef.rhs.pos, s"${valOrDef.symbol.fullLocationString} does nothing other than call itself recursively") } // Transformation ------------------------------------------------------------ @@ -1231,7 +1231,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans finally if (currentLevel.maxindex > 0) { // An implementation restriction to avoid VerifyErrors and lazyvals mishaps; see SI-4717 debuglog("refsym = " + currentLevel.refsym) - unit.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation") + reporter.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation") } case ModuleDef(_, _, _) => eliminateModuleDefs(tree) case ValDef(_, _, _, _) => @@ -1241,7 +1241,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans val lazySym = tree.symbol.lazyAccessorOrSelf if (lazySym.isLocalToBlock && index <= currentLevel.maxindex) { debuglog("refsym = " + currentLevel.refsym) - unit.error(currentLevel.refpos, "forward reference extends over definition of " + lazySym) + reporter.error(currentLevel.refpos, "forward reference extends over definition of " + lazySym) } tree1 :: Nil } @@ -1255,7 +1255,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans try typer.infer.checkBounds(tree0, pre, owner, tparams, argtps, "") catch { case ex: TypeError => - unit.error(tree0.pos, ex.getMessage()) + reporter.error(tree0.pos, ex.getMessage()) if (settings.explaintypes) { val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, argtps).bounds) (argtps, bounds).zipped map ((targ, bound) => explainTypes(bound.lo, targ)) @@ -1288,7 +1288,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // If symbol is deprecated, and the point of reference is not enclosed // in either a deprecated member or a scala bridge method, issue a warning. if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) - unit.deprecationWarning(pos, sym, s"${sym}${sym.locationString} is deprecated${sym.deprecationMessage map (": " + _) getOrElse ""}") + currentRun.reporting.deprecationWarning(pos, sym, s"${sym}${sym.locationString} is deprecated${sym.deprecationMessage map (": " + _) getOrElse ""}") // Similar to deprecation: check if the symbol is marked with @migration // indicating it has changed semantics between versions. @@ -1297,12 +1297,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans settings.Xmigration.value < ScalaVersion(sym.migrationVersion.get) catch { case e : NumberFormatException => - unit.warning(pos, s"${sym.fullLocationString} has an unparsable version number: ${e.getMessage()}") + reporter.warning(pos, s"${sym.fullLocationString} has an unparsable version number: ${e.getMessage()}") // if we can't parse the format on the migration annotation just conservatively assume it changed true } if (changed) - unit.warning(pos, s"${sym.fullLocationString} has changed semantics in version ${sym.migrationVersion.get}:\n${sym.migrationMessage.get}") + reporter.warning(pos, s"${sym.fullLocationString} has changed semantics in version ${sym.migrationVersion.get}:\n${sym.migrationMessage.get}") } // See an explanation of compileTimeOnly in its scaladoc at scala.annotation.compileTimeOnly. if (sym.isCompileTimeOnly) { @@ -1310,7 +1310,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans sm"""Reference to ${sym.fullLocationString} should not have survived past type checking, |it should have been processed and eliminated during expansion of an enclosing macro.""" // The getOrElse part should never happen, it's just here as a backstop. - unit.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg) + reporter.error(pos, sym.compileTimeOnlyMessage getOrElse defaultMsg) } } @@ -1321,7 +1321,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans && sym.accessedOrSelf.isVal ) if (settings.lint.value && isLikelyUninitialized) - unit.warning(pos, s"Selecting ${sym} from ${sym.owner}, which extends scala.DelayedInit, is likely to yield an uninitialized value") + reporter.warning(pos, s"Selecting ${sym} from ${sym.owner}, which extends scala.DelayedInit, is likely to yield an uninitialized value") } private def lessAccessible(otherSym: Symbol, memberSym: Symbol): Boolean = ( @@ -1353,7 +1353,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans if (memberSym.isDeferred) "may be unable to provide a concrete implementation of" else "may be unable to override" - unit.warning(memberSym.pos, + reporter.warning(memberSym.pos, "%s%s references %s %s.".format( memberSym.fullLocationString, comparison, accessFlagsToString(otherSym), otherSym @@ -1388,7 +1388,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans tree match { case DefDef(_, name, _, params :: _, _, _) => if (settings.lint && !treeInfo.isLeftAssoc(name.decodedName) && params.exists(p => isByName(p.symbol))) - unit.warning(tree.pos, + reporter.warning(tree.pos, "by-name parameters will be evaluated eagerly when called as a right-associative infix operator. For more details, see SI-1980.") case _ => } @@ -1405,7 +1405,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans symbol.allOverriddenSymbols.filter(sym => !sym.isDeprecated && !sym.isDeferred) if(!concrOvers.isEmpty) - unit.deprecationWarning( + currentRun.reporting.deprecationWarning( tree.pos, symbol, s"${symbol.toString} overrides concrete, non-deprecated symbol(s): ${concrOvers.map(_.name.decode).mkString(", ")}") @@ -1469,7 +1469,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans applyChecks(sym.annotations) // validate implicitNotFoundMessage analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn => - unit.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn") + reporter.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn") } case tpt@TypeTree() => @@ -1594,7 +1594,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans || sym.allOverriddenSymbols.exists(over => !(over.tpe.resultType =:= sym.tpe.resultType)) ) if (!isOk) - unit.warning(sym.pos, s"side-effecting nullary methods are discouraged: suggest defining as `def ${sym.name.decode}()` instead") + reporter.warning(sym.pos, s"side-effecting nullary methods are discouraged: suggest defining as `def ${sym.name.decode}()` instead") case _ => () } @@ -1602,15 +1602,15 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans private def checkAnyValSubclass(clazz: Symbol) = { if (clazz.isDerivedValueClass) { if (clazz.isTrait) - unit.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal") + reporter.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal") else if (clazz.hasAbstractFlag) - unit.error(clazz.pos, "`abstract' modifier cannot be used with value classes") + reporter.error(clazz.pos, "`abstract' modifier cannot be used with value classes") } } private def checkUnexpandedMacro(t: Tree) = if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) - unit.error(t.pos, "macro has not been expanded") + reporter.error(t.pos, "macro has not been expanded") override def transform(tree: Tree): Tree = { val savedLocalTyper = localTyper @@ -1705,7 +1705,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans tree case treeInfo.WildcardStarArg(_) if !isRepeatedParamArg(tree) => - unit.error(tree.pos, "no `: _*' annotation allowed here\n"+ + reporter.error(tree.pos, "no `: _*' annotation allowed here\n"+ "(such annotations are only allowed in arguments to *-parameters)") tree @@ -1778,7 +1778,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } catch { case ex: TypeError => if (settings.debug) ex.printStackTrace() - unit.error(tree.pos, ex.getMessage()) + reporter.error(tree.pos, ex.getMessage()) tree } finally { localTyper = savedLocalTyper diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index b6d37ab9a7..d3a41b9570 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -124,7 +124,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT if (other == NoSymbol) other = linked.info.decl(sym.name.toTermName).filter(_.isModule) if (other != NoSymbol) - unit.error(sym.pos, "name clash: "+sym.owner+" defines "+sym+ + reporter.error(sym.pos, "name clash: "+sym.owner+" defines "+sym+ "\nand its companion "+sym.owner.companionModule+" also defines "+ other) } @@ -139,14 +139,14 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val member = sym.overridingSymbol(clazz) if (mix != tpnme.EMPTY || member == NoSymbol || !(member.isAbstractOverride && member.isIncompleteIn(clazz))) - unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+ + reporter.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+ "unless it is overridden by a member declared `abstract' and `override'") } else if (mix == tpnme.EMPTY && !sym.owner.isTrait){ // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract. val intermediateClasses = clazz.info.baseClasses.tail.takeWhile(_ != sym.owner) intermediateClasses.map(sym.overridingSymbol).find(s => s.isDeferred && !s.isAbstractOverride && !s.owner.isTrait).foreach { absSym => - unit.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract") + reporter.error(sel.pos, s"${sym.fullLocationString} cannot be directly accessed from ${clazz} because ${absSym.owner} redeclares it as abstract") } } @@ -252,7 +252,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT qual.symbol.ancestors foreach { parent => parent.info.decls filterNot (x => x.isPrivate || x.isLocalToThis) foreach { m2 => if (sym.name == m2.name && m2.isGetter && m2.accessed.isMutable) { - unit.warning(sel.pos, + reporter.warning(sel.pos, sym.accessString + " " + sym.fullLocationString + " shadows mutable " + m2.name + " inherited from " + m2.owner + ". Changes to " + m2.name + " will not be visible within " + sym.owner + " - you may want to give them distinct names.") @@ -310,9 +310,9 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case Super(_, mix) => if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) { if (!settings.overrideVars) - unit.error(tree.pos, "super may be not be used on " + sym.accessedOrSelf) + reporter.error(tree.pos, "super may be not be used on " + sym.accessedOrSelf) } else if (isDisallowed(sym)) { - unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead") + reporter.error(tree.pos, "super not allowed here: use this." + name.decode + " instead") } transformSuperSelect(sel) diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index a2f52e1905..399a4ca8d5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -17,7 +17,7 @@ abstract class TreeCheckers extends Analyzer { override protected def onTreeCheckerError(pos: Position, msg: String) { if (settings.fatalWarnings) - currentUnit.warning(pos, "\n** Error during internal checking:\n" + msg) + reporter.warning(pos, "\n** Error during internal checking:\n" + msg) } case class DiffResult[T](lost: List[T], gained: List[T]) { @@ -170,7 +170,7 @@ abstract class TreeCheckers extends Analyzer { ) - def errorFn(pos: Position, msg: Any): Unit = currentUnit.warning(pos, "[check: %s] %s".format(phase.prev, msg)) + def errorFn(pos: Position, msg: Any): Unit = reporter.warning(pos, "[check: %s] %s".format(phase.prev, msg)) def errorFn(msg: Any): Unit = errorFn(NoPosition, msg) def informFn(msg: Any) { diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 60346e7be1..7440f69e93 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -41,9 +41,9 @@ trait TypeDiagnostics { * indicate that the restriction may be lifted in the future. */ def restrictionWarning(pos: Position, unit: CompilationUnit, msg: String): Unit = - unit.warning(pos, "Implementation restriction: " + msg) + reporter.warning(pos, "Implementation restriction: " + msg) def restrictionError(pos: Position, unit: CompilationUnit, msg: String): Unit = - unit.error(pos, "Implementation restriction: " + msg) + reporter.error(pos, "Implementation restriction: " + msg) /** A map of Positions to addendums - if an error involves a position in * the map, the addendum should also be printed. @@ -435,12 +435,8 @@ trait TypeDiagnostics { trait TyperDiagnostics { self: Typer => - private def contextError(context0: Analyzer#Context, pos: Position, msg: String) = context0.error(pos, msg) - private def contextError(context0: Analyzer#Context, pos: Position, err: Throwable) = context0.error(pos, err) - private def contextWarning(pos: Position, msg: String) = context.unit.warning(pos, msg) - def permanentlyHiddenWarning(pos: Position, hidden: Name, defn: Symbol) = - contextWarning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString)) + context.warning(pos, "imported `%s' is permanently hidden by definition of %s".format(hidden, defn.fullLocationString)) object checkUnused { val ignoreNames = Set[TermName]("readResolve", "readObject", "writeObject", "writeReplace") @@ -542,15 +538,15 @@ trait TypeDiagnostics { else if (sym.isModule) "object" else "term" ) - unit.warning(pos, s"$why $what in ${sym.owner} is never used") + reporter.warning(pos, s"$why $what in ${sym.owner} is never used") } p.unsetVars foreach { v => - unit.warning(v.pos, s"local var ${v.name} in ${v.owner} is never set - it could be a val") + reporter.warning(v.pos, s"local var ${v.name} in ${v.owner} is never set - it could be a val") } p.unusedTypes foreach { t => val sym = t.symbol val why = if (sym.isPrivate) "private" else "local" - unit.warning(t.pos, s"$why ${sym.fullLocationString} is never used") + reporter.warning(t.pos, s"$why ${sym.fullLocationString} is never used") } } } @@ -627,13 +623,13 @@ trait TypeDiagnostics { case Import(expr, _) => expr.pos case _ => ex.pos } - contextError(context0, pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) + context0.error(pos, cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) if (sym == ObjectClass) throw new FatalError("cannot redefine root "+sym) } case _ => - contextError(context0, ex.pos, ex) + context0.error(ex.pos, ex) } } } diff --git a/src/compiler/scala/tools/reflect/FormatInterpolator.scala b/src/compiler/scala/tools/reflect/FormatInterpolator.scala index e0f9bb6044..57be1afdfe 100644 --- a/src/compiler/scala/tools/reflect/FormatInterpolator.scala +++ b/src/compiler/scala/tools/reflect/FormatInterpolator.scala @@ -117,7 +117,7 @@ abstract class FormatInterpolator { c.error(errPoint, msg("unsupported")) s0 } else { - c.enclosingUnit.deprecationWarning(errPoint, msg("deprecated")) + currentRun.reporting.deprecationWarning(errPoint, msg("deprecated")) try StringContext.treatEscapes(s0) catch escapeHatch } } diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala index e5c64c6f45..10c382e169 100644 --- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala +++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala @@ -39,12 +39,12 @@ trait ScaladocAnalyzer extends Analyzer { for (useCase <- comment.useCases) { typer1.silent(_.asInstanceOf[ScaladocTyper].defineUseCases(useCase)) match { case SilentTypeError(err) => - unit.warning(useCase.pos, err.errMsg) + reporter.warning(useCase.pos, err.errMsg) case _ => } for (useCaseSym <- useCase.defined) { if (sym.name != useCaseSym.name) - unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode) + reporter.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode) } } } @@ -191,7 +191,7 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax } def isDirty = unclean(unmooredParser parseComment doc) if ((doc ne null) && (settings.lint || isDirty)) - unit.warning(doc.pos, "discarding unmoored doc comment") + reporter.warning(doc.pos, "discarding unmoored doc comment") } override def flushDoc(): DocComment = (try lastDoc finally lastDoc = null) -- 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(-) 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 3066bd4c7b2f574748208b7399c68c6c6493206b Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 24 Jun 2014 14:34:05 +0200 Subject: Encapsulate deprecation warning message synthesis. Both refchecks and typer constructed the same message. But different. Now with more DRYness. Note that no check files had to be updated (disconcerting)... --- src/compiler/scala/tools/nsc/Reporting.scala | 6 +++++- src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 2 ++ src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 2 +- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index 9a20807145..bc27afb0c5 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -15,7 +15,7 @@ import scala.collection.{ mutable, immutable } * * TODO: make reporting configurable */ -trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.api.Symbols => +trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.internal.Symbols => def settings: Settings // not deprecated yet, but a method called "error" imported into @@ -65,6 +65,10 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w // behold! the symbol that caused the deprecation warning (may not be deprecated itself) def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = _deprecationWarnings.warn(pos, msg) + def deprecationWarning(pos: Position, sym: Symbol): Unit = { + val suffix = sym.deprecationMessage match { case Some(msg) => ": "+ msg case _ => "" } + deprecationWarning(pos, sym, s"$sym${sym.locationString} is deprecated$suffix") + } private[this] var reportedFeature = Set[Symbol]() def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 20f0405d1b..72ca9b879a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -595,6 +595,8 @@ trait Contexts { self: Analyzer => def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit = currentRun.reporting.deprecationWarning(pos, sym, msg) + def deprecationWarning(pos: Position, sym: Symbol): Unit = + currentRun.reporting.deprecationWarning(pos, sym) // TODO: allow this to escalate to an error, and implicit search will ignore deprecated implicits def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit = currentRun.reporting.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 1c84f8d759..1b3da26bf2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1288,7 +1288,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // If symbol is deprecated, and the point of reference is not enclosed // in either a deprecated member or a scala bridge method, issue a warning. if (sym.isDeprecated && !currentOwner.ownerChain.exists(x => x.isDeprecated || x.hasBridgeAnnotation)) - currentRun.reporting.deprecationWarning(pos, sym, s"${sym}${sym.locationString} is deprecated${sym.deprecationMessage map (": " + _) getOrElse ""}") + currentRun.reporting.deprecationWarning(pos, sym) // Similar to deprecation: check if the symbol is marked with @migration // indicating it has changed semantics between versions. diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 349bad555a..2c31ef2e8e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -942,7 +942,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def adaptConstant(value: Constant): Tree = { val sym = tree.symbol if (sym != null && sym.isDeprecated) - context.deprecationWarning(tree.pos, sym, s"${sym.toString}${sym.locationString} is deprecated: ${sym.deprecationMessage.getOrElse("")}") + context.deprecationWarning(tree.pos, sym) treeCopy.Literal(tree, value) } -- 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(-) 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 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 From 532ef331eb050454d33a3063b48b581db874d57a Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 7 Jul 2014 10:14:57 +0200 Subject: Restore reporter forwarders in CompilationUnit Deprecate them so that we can remove them in a couple of 2.11.x releases. Plenty of plugins were probably using `unit.error` et al. The continuations plugin was, for one (remedying this with pending PR). --- src/compiler/scala/tools/nsc/CompilationUnits.scala | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 1ad206f519..f23bca77cd 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -123,8 +123,21 @@ trait CompilationUnits { global: Global => */ val icode: LinkedHashSet[icodes.IClass] = new LinkedHashSet + @deprecated("Call global.reporter.echo directly instead.", "2.11.2") + final def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg) + @deprecated("Call global.reporter.error (or typer.context.error) directly instead.", "2.11.2") + final def error(pos: Position, msg: String): Unit = reporter.error(pos, msg) + @deprecated("Call global.reporter.warning (or typer.context.warning) directly instead.", "2.11.2") + final def warning(pos: Position, msg: String): Unit = reporter.warning(pos, msg) + + @deprecated("Call global.currentRun.reporting.deprecationWarning directly instead.", "2.11.2") + final def deprecationWarning(pos: Position, msg: String): Unit = currentRun.reporting.deprecationWarning(pos, msg) + @deprecated("Call global.currentRun.reporting.uncheckedWarning directly instead.", "2.11.2") + final def uncheckedWarning(pos: Position, msg: String): Unit = currentRun.reporting.uncheckedWarning(pos, msg) + // called by ScalaDocAnalyzer, overridden by the IDE (in Reporter) // TODO: don't use reporter to communicate comments from parser to IDE! + @deprecated("This method will be removed.", "2.11.2") final def comment(pos: Position, msg: String): Unit = reporter.comment(pos, msg) -- cgit v1.2.3