为此的编译器选项是-Yissue-debug。它在 2.10 中在发出错误时输出堆栈跟踪。
支持它的代码在 2.11 的报告重构过程中被删除,但该选项仍然有效。 (我在某个时候恢复了它,因为事实上,这是查看发出错误的最快方法;但显然 PR 死在了藤蔓上并消失了。可能是push -f 的受害者。)
在 2.12 中,您可以提供一个自定义报告器,该报告器的功能几乎相同。他们声称他们将通过访问上下文来增强报告 API,因此您也许可以直接查询当前阶段、检查树等等。
这是你描述的情况的一个例子:
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
有三个错误,但一次只报告一个,因为它们是在不同的编译器阶段发出的。
为了澄清这个问题,除了“typer”之外的各个阶段都可以创建和类型检查树,并且即使在树被键入之后也可以强制执行良好的类型化。 (还有其他类型的错误,比如“无法写入输出文件”。)
对于C,解析器针对已弃用的八进制语法发出错误(在-Xfuture 下),类型器报告g 中的类型不匹配,并且抓取袋refchecks 阶段检查已声明但未定义(空)会员f。您通常会一次修复一个错误。如果解析器错误作为警告发出,则警告将被抑制,直到错误得到修复,所以这将是最后一个弹出而不是第一个弹出。
这是一个示例报告器,它试图做的不仅仅是输出巨大的堆栈跟踪。
package myrep
import scala.tools.nsc.Settings
import scala.tools.nsc.reporters.ConsoleReporter
import scala.reflect.internal.util._
class DebugReporter(ss: Settings) extends ConsoleReporter(ss) {
override def warning(pos: Position, msg: String) = debug {
super.warning(pos, msg)
}
override def error(pos: Position, msg: String) = debug {
super.error(pos, msg)
}
// let it ride
override def hasErrors = false
private def debug(body: => Unit): Unit = {
val pkgs = Set("nsc.ast.parser", "nsc.typechecker", "nsc.transform")
def compilerPackages(e: StackTraceElement): Boolean = pkgs exists (e.getClassName contains _)
def classname(e: StackTraceElement): String = (e.getClassName split """\.""").last
if (ss.Yissuedebug) echo {
((new Throwable).getStackTrace filter compilerPackages map classname).distinct mkString ("Issued from: ", ",", "\n")
}
body
}
}
关键在于没有错误,这样编译器就不会提前中止。
它将以这种方式调用,报告者类位于“工具类路径”上:
scalacm -toolcp repdir -Xreporter myrep.DebugReporter -Yissue-debug -deprecation errs.scala
在哪里
$ scalacm -version
Scala compiler version 2.12.0-M2 -- Copyright 2002-2013, LAMP/EPFL
样本输出:
Issued from: Scanners$UnitScanner,Scanners$Scanner,Parsers$Parser,Parsers$Parser$$anonfun$templateStat$1,Parsers$Parser$$anonfun$topStat$1,Parsers$SourceFileParser,Parsers$UnitParser,SyntaxAnalyzer,SyntaxAnalyzer$ParserPhase
errs.scala:4: warning: Octal escape literals are deprecated, use \u0000 instead.
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
^
Issued from: Contexts$ImmediateReporter,Contexts$ContextReporter,Contexts$Context,ContextErrors$ErrorUtils$,ContextErrors$TyperContextErrors$TyperErrorGen$,Typers$Typer,Analyzer$typerFactory$$anon$3
errs.scala:4: error: type mismatch;
found : String("")
required: Int
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
^
Issued from: RefChecks$RefCheckTransformer,Transform$Phase
errs.scala:4: error: class C needs to be abstract, since method f is not defined
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
^
one warning found
two errors found