Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Operation beautify error messages #1521

Merged
merged 53 commits into from Oct 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
281dbb5
Add initial structure for improved explanations of error messages
felixmulder Sep 14, 2016
a699758
Add highlighter string interpolator
felixmulder Sep 15, 2016
d2c9e19
Return iterable from highlighting function instead of vector
felixmulder Sep 15, 2016
6495210
Add highlighting for `???`
felixmulder Sep 15, 2016
e4a7db1
Simplify "hl" interpolator
felixmulder Sep 15, 2016
66f7f7d
Use highlighting in explanation classes
felixmulder Sep 15, 2016
c9a8bb8
Add more examples to Typer
felixmulder Sep 15, 2016
1946f94
Change layout of ErrorMessages
felixmulder Sep 15, 2016
11cfc30
Add missing star in docstring
felixmulder Sep 15, 2016
15db5f6
Add smart comment formatting in ConsoleReporter
felixmulder Sep 15, 2016
f8456fc
Add error kind to diagnostic
felixmulder Sep 15, 2016
fb4f8ce
Rename `ConsoleReporter` => `FancyConsoleReporter`
felixmulder Sep 16, 2016
12ac305
Add ability to choose between fancy and non-fancy output
felixmulder Sep 16, 2016
18a69f7
Rename Diagnostic to diagnostic.Message
felixmulder Sep 16, 2016
2b2cfe7
Refactor common error messages to `diagnostic.basic`
felixmulder Sep 16, 2016
2764609
Complete better structure to diagnostic messages
felixmulder Sep 16, 2016
15dfb56
Add coloring util
felixmulder Sep 16, 2016
30b5410
Factor out explanation header to Reporter
felixmulder Sep 16, 2016
5c24377
Add `MissingIdent` message to `Typer`
felixmulder Sep 16, 2016
787a2ce
Add modifiers to highlighting
felixmulder Sep 16, 2016
628b7f3
Make `FancyConsoleReporter` and `Highlighting` obey color setting
felixmulder Sep 18, 2016
e24289a
Make relevant parts of compiler conform to new error handling
felixmulder Sep 19, 2016
1532c82
Remove duplication of console reporters
felixmulder Sep 19, 2016
146add1
Improve syntax highlighting for ValDefs
felixmulder Sep 19, 2016
bf8803d
Add deprecation message on `with` type operator
felixmulder Sep 19, 2016
af25cb1
Improve syntax highlighting on polymorphic defs
felixmulder Sep 19, 2016
48000c6
Fix underline position
felixmulder Sep 20, 2016
f1cc4f2
Better operator highlighting
felixmulder Sep 20, 2016
68eae1a
Indent 2 after newline in REPL
felixmulder Sep 20, 2016
6b12f65
Fix #1525: start repl if first arg to dotr starts with hyphen
felixmulder Sep 20, 2016
153c566
Fix multiple parsing errors on e.g. `try 1`
felixmulder Sep 20, 2016
88e4146
Add basic diffing for shown values
felixmulder Sep 20, 2016
8743fa8
Unrainbow syntax highlighting
felixmulder Sep 22, 2016
aa55935
Refactor explanation interpolator
felixmulder Sep 21, 2016
33d4490
Make `typeDiff` aware of placeholder types
felixmulder Sep 26, 2016
24bcdfd
Add `dotty.jar` to gitignore
felixmulder Sep 27, 2016
f5ad849
Fix reporting of ErrorTypes in highlighted segments
felixmulder Sep 27, 2016
a7d3f6e
Don't force Message twice in MessageContainer
felixmulder Sep 27, 2016
7561db0
Fix TypeMismatch not getting nonsensical tags in some cases
felixmulder Sep 27, 2016
18d63fe
Get rid of `kind` in `MessageContainer`
felixmulder Sep 28, 2016
f7b8980
Improve documentation for message framework
felixmulder Sep 28, 2016
e42bb30
Change Message#errorId to type Int
felixmulder Sep 28, 2016
a0026a0
Make reporter hint about existing explanations
felixmulder Sep 29, 2016
0781b31
Handle multiline messages in ConsoleReporter
felixmulder Sep 29, 2016
f23ff3a
Improve positions for MemberDefs using `namePos`
felixmulder Sep 29, 2016
41d6429
Get rid of unnecessary fields in `MessageContainer`
felixmulder Oct 3, 2016
29d19ba
Correct line extraction from SourcePosition
felixmulder Oct 3, 2016
d2b6205
Insert message "inline" into multiline code at point
felixmulder Oct 3, 2016
e754a2d
Change `typeDiff` to highlight changes less than 50%
felixmulder Oct 4, 2016
45a2df1
Fix TreeChecker mismatch string
felixmulder Oct 7, 2016
b9e03b8
Remove unnecessary printing of hints for `-explain`
felixmulder Oct 7, 2016
d490f7d
Add Levenshtein distance for member values and types
felixmulder Oct 7, 2016
550c643
Adopt delegating reporter to new scheme
felixmulder Oct 10, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -3,7 +3,6 @@
*.log
*.swp
*~
*.swp

# sbt specific
dist/*
Expand All @@ -29,6 +28,7 @@ classes/
/.worksheet/

# Partest
dotty.jar
tests/partest-generated/
tests/locks/
/test-classes/
Expand Down
4 changes: 4 additions & 0 deletions bin/dotr
Expand Up @@ -29,9 +29,13 @@ function runMain {
fi
}

first_arg=$1

if [ -z "$1" ]; then
echo "Starting dotty REPL..."
eval "$DOTTY_ROOT/bin/dotc -repl"
elif [[ ${first_arg:0:1} == "-" ]]; then
eval "$DOTTY_ROOT/bin/dotc -repl $@"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sophisticated enough for now - we will have to revisit this script to get it on par with the scala script eventually - see: #1526

else
runMain "$@"
fi
28 changes: 15 additions & 13 deletions bridge/src/main/scala/xsbt/DelegatingReporter.scala
Expand Up @@ -6,6 +6,8 @@ package xsbt
import dotty.tools._
import dotc._
import reporting._
import reporting.diagnostic.MessageContainer
import reporting.diagnostic.messages
import core.Contexts._

import xsbti.{Maybe, Position}
Expand All @@ -16,19 +18,19 @@ final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter

override def printSummary(implicit ctx: Context): Unit = delegate.printSummary()

def doReport(d: Diagnostic)(implicit ctx: Context): Unit = {
val severity =
d match {
case _: Reporter.Error => xsbti.Severity.Error
case _: Reporter.Warning => xsbti.Severity.Warn
def doReport(cont: MessageContainer)(implicit ctx: Context): Unit = {
val severity =
cont match {
case _: messages.Error => xsbti.Severity.Error
case _: messages.Warning => xsbti.Severity.Warn
case _ => xsbti.Severity.Info
}
val pos =
if (d.pos.exists) Some(d.pos)
val pos =
if (cont.pos.exists) Some(cont.pos)
else None

val file =
if (d.pos.source.file.exists) Option(d.pos.source.file.file)
val file =
if (cont.pos.source.file.exists) Option(cont.pos.source.file.file)
else None

val offset0 = pos.map(_.point)
Expand All @@ -43,16 +45,16 @@ final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter
def sourcePath: Maybe[String] = maybe(file.map(_.getPath))
}

delegate.log(position, d.message, severity)
delegate.log(position, cont.message, severity)
}

private[this] def maybe[T](opt: Option[T]): Maybe[T] = opt match {
private[this] def maybe[T](opt: Option[T]): Maybe[T] = opt match {
case None => Maybe.nothing[T]
case Some(s) => Maybe.just[T](s)
}
import java.lang.{ Integer => I }
private[this] def maybeInt(opt: Option[Int]): Maybe[I] = opt match {
private[this] def maybeInt(opt: Option[Int]): Maybe[I] = opt match {
case None => Maybe.nothing[I]
case Some(s) => Maybe.just[I](s)
}
}
}
7 changes: 5 additions & 2 deletions src/dotty/tools/dotc/ast/Desugar.scala
Expand Up @@ -9,6 +9,7 @@ import Decorators._
import language.higherKinds
import collection.mutable.ListBuffer
import util.Property
import reporting.diagnostic.messages._

object desugar {
import untpd._
Expand Down Expand Up @@ -71,7 +72,9 @@ object desugar {
val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next
var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor).symbol
if (local.exists) (defctx.owner.thisType select local).dealias
else throw new Error(s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}")
else throw new java.lang.Error(
s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}"
)
case _ =>
mapOver(tp)
}
Expand Down Expand Up @@ -281,7 +284,7 @@ object desugar {
val constrVparamss =
if (constr1.vparamss.isEmpty) { // ensure parameter list is non-empty
if (isCaseClass)
ctx.error("case class needs to have at least one parameter list", cdef.pos)
ctx.error(CaseClassMissingParamList(cdef), cdef.namePos)
ListOfNil
}
else constr1.vparamss.nestedMap(toDefParam)
Expand Down
6 changes: 2 additions & 4 deletions src/dotty/tools/dotc/ast/Trees.scala
Expand Up @@ -3,8 +3,8 @@ package dotc
package ast

import core._
import Types._, Names._, Flags._, util.Positions._, Contexts._, Constants._, SymDenotations._, Symbols._
import Denotations._, StdNames._, Comments._
import Types._, Names._, Flags._, util.Positions._, Contexts._, Constants._
import SymDenotations._, Symbols._, Denotations._, StdNames._, Comments._
import annotation.tailrec
import language.higherKinds
import collection.IndexedSeqOptimized
Expand Down Expand Up @@ -308,8 +308,6 @@ object Trees {
if (rawMods.is(Synthetic)) Position(pos.point, pos.point)
else Position(pos.point, pos.point + name.length, pos.point)
else pos


}

/** A ValDef or DefDef tree */
Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/config/ScalaSettings.scala
Expand Up @@ -23,6 +23,7 @@ class ScalaSettings extends Settings.SettingGroup {
val migration = BooleanSetting("-migration", "Emit warning and location for migration issues from Scala 2.")
val encoding = StringSetting("-encoding", "encoding", "Specify character encoding used by source files.", Properties.sourceEncoding)
val explaintypes = BooleanSetting("-explaintypes", "Explain type errors in more detail.")
val explain = BooleanSetting("-explain", "Explain errors in more detail.")
val feature = BooleanSetting("-feature", "Emit warning and location for usages of features that should be imported explicitly.")
val g = ChoiceSetting("-g", "level", "Set level of generated debugging info.", List("none", "source", "line", "vars", "notailcalls"), "vars")
val help = BooleanSetting("-help", "Print a synopsis of standard options")
Expand Down
4 changes: 4 additions & 0 deletions src/dotty/tools/dotc/core/Decorators.scala
Expand Up @@ -176,6 +176,10 @@ object Decorators {
*/
def ex(args: Any*)(implicit ctx: Context): String =
explained2(implicit ctx => em(args: _*))

/** Formatter that adds syntax highlighting to all interpolated values */
def hl(args: Any*)(implicit ctx: Context): String =
new SyntaxFormatter(sc).assemble(args)
}
}

2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/TypeOps.scala
Expand Up @@ -36,7 +36,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
* Instead we produce an annotated type that marks the prefix as unsafe:
*
* (x: (C @ UnsafeNonvariant)#T)C#T

*
* We also set a global state flag `unsafeNonvariant` to the current run.
* When typing a Select node, typer will check that flag, and if it
* points to the current run will scan the result type of the select for
Expand Down
44 changes: 27 additions & 17 deletions src/dotty/tools/dotc/parsing/Parsers.scala
Expand Up @@ -27,6 +27,8 @@ import rewrite.Rewrites.patch
object Parsers {

import ast.untpd._
import reporting.diagnostic.Message
import reporting.diagnostic.messages._

case class OpInfo(operand: Tree, operator: Name, offset: Offset)

Expand Down Expand Up @@ -97,7 +99,7 @@ object Parsers {
/** Issue an error at given offset if beyond last error offset
* and update lastErrorOffset.
*/
def syntaxError(msg: String, offset: Int = in.offset): Unit =
def syntaxError(msg: Message, offset: Int = in.offset): Unit =
if (offset > lastErrorOffset) {
syntaxError(msg, Position(offset))
lastErrorOffset = in.offset
Expand All @@ -106,7 +108,7 @@ object Parsers {
/** Unconditionally issue an error at given position, without
* updating lastErrorOffset.
*/
def syntaxError(msg: String, pos: Position): Unit =
def syntaxError(msg: Message, pos: Position): Unit =
ctx.error(msg, source atPos pos)

}
Expand Down Expand Up @@ -213,20 +215,23 @@ object Parsers {
}
}

def warning(msg: String, offset: Int = in.offset) =
def warning(msg: Message, sourcePos: SourcePosition) =
ctx.warning(msg, sourcePos)

def warning(msg: Message, offset: Int = in.offset) =
ctx.warning(msg, source atPos Position(offset))

def deprecationWarning(msg: String, offset: Int = in.offset) =
def deprecationWarning(msg: Message, offset: Int = in.offset) =
ctx.deprecationWarning(msg, source atPos Position(offset))

/** Issue an error at current offset taht input is incomplete */
def incompleteInputError(msg: String) =
def incompleteInputError(msg: Message) =
ctx.incompleteInputError(msg, source atPos Position(in.offset))

/** If at end of file, issue an incompleteInputError.
* Otherwise issue a syntax error and skip to next safe point.
*/
def syntaxErrorOrIncomplete(msg: String) =
def syntaxErrorOrIncomplete(msg: Message) =
if (in.token == EOF) incompleteInputError(msg)
else {
syntaxError(msg)
Expand Down Expand Up @@ -732,7 +737,7 @@ object Parsers {

def withTypeRest(t: Tree): Tree =
if (in.token == WITH) {
deprecationWarning("`with' as a type operator has been deprecated; use `&' instead")
deprecationWarning(DeprecatedWithOperator())
in.nextToken()
AndTypeTree(t, withType())
}
Expand Down Expand Up @@ -1004,28 +1009,33 @@ object Parsers {
DoWhile(body, cond)
}
case TRY =>
val tryOffset = in.offset
atPos(in.skipToken()) {
val body = expr()
val handler =
val (handler, handlerStart) =
if (in.token == CATCH) {
val pos = in.offset
in.nextToken()
expr()
} else EmptyTree
(expr(), pos)
} else (EmptyTree, -1)

handler match {
case Block(Nil, EmptyTree) => syntaxError(
"`catch` block does not contain a valid expression, try adding a case like - `case e: Exception =>` to the block",
handler.pos
)
case Block(Nil, EmptyTree) =>
assert(handlerStart != -1)
syntaxError(
new EmptyCatchBlock(body),
Position(handlerStart, handler.pos.end)
)
case _ =>
}

val finalizer =
if (in.token == FINALLY) { accept(FINALLY); expr() }
else {
if (handler.isEmpty)
warning("A try without `catch` or `finally` is equivalent to putting its body in a block; no exceptions are handled.")

if (handler.isEmpty) warning(
EmptyCatchAndFinallyBlock(body),
source atPos Position(tryOffset, body.pos.end)
)
EmptyTree
}
ParsedTry(body, handler, finalizer)
Expand Down