1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
package dotty.tools
package dotc
package typer
import ast._
import core._
import Trees._
import Types._, Inferencing._, Contexts._, Decorators._, Denotations._, Symbols._
import Applications._, Implicits._
import util.Positions._
import printing.Showable
import printing.Disambiguation.disambiguated
import reporting.Reporter.SuppressedMessage
object ErrorReporting {
import tpd._
def errorTree(tree: untpd.Tree, msg: => String)(implicit ctx: Context): tpd.Tree =
tree withType errorType(msg, tree.pos)
def errorType(msg: => String, pos: Position)(implicit ctx: Context): ErrorType = {
ctx.error(msg, pos)
ErrorType
}
class Errors(implicit ctx: Context) {
def expectedTypeStr(tp: Type): String = tp match {
case tp: FunProto =>
val result = tp.resultType match {
case tp: WildcardType => ""
case tp => i"and expected result type $tp"
}
i"arguments (${tp.typedArgs.tpes}%, %)$result"
case _ =>
i"expected type $tp"
}
def anonymousTypeMemberStr(tpe: Type) = {
val kind = tpe match {
case _: TypeBounds => "type with bounds"
case _: PolyType | _: MethodType => "method"
case _ => "value of type"
}
i"$kind $tpe"
}
def overloadedAltsStr(alts: List[SingleDenotation]) =
i"overloaded alternatives of ${denotStr(alts.head)} with types\n" +
i" ${alts map (_.info)}%\n %"
def denotStr(denot: Denotation): String =
if (denot.isOverloaded) overloadedAltsStr(denot.alternatives)
else if (denot.symbol.exists) denot.symbol.showLocated
else anonymousTypeMemberStr(denot.info)
def refStr(tp: Type): String = tp match {
case tp: NamedType => denotStr(tp.denot)
case _ => anonymousTypeMemberStr(tp)
}
def exprStr(tree: Tree): String = refStr(tree.tpe)
def patternConstrStr(tree: Tree): String = ???
def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = {
errorTree(tree, typeMismatchStr(tree.tpe, pt) + implicitFailure.postscript)
}
def typeMismatchStr(found: Type, expected: Type) = disambiguated { implicit ctx =>
val (typerStateStr, explanationStr) =
if (ctx.settings.explaintypes.value) {
val nestedCtx = ctx.fresh.withTypeComparerFn(new ExplainingTypeComparer(_))
(found <:< expected)(nestedCtx)
("\n" + ctx.typerState.show, "\n" + nestedCtx.typeComparer.toString)
}
else ("", "")
i"""type mismatch:
| found : $found
| required: $expected""".stripMargin + typerStateStr + explanationStr
}
}
def err(implicit ctx: Context): Errors = new Errors
/** Implementation of i"..." string interpolator */
implicit class InfoString(val sc: StringContext) extends AnyVal {
def i(args: Any*)(implicit ctx: Context): String = {
def isSensical(arg: Any): Boolean = arg match {
case tpe: Type if tpe.isErroneous => false
case NoType => false
case sym: Symbol if sym.isCompleted =>
sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info != NoType
case _ => true
}
def treatArg(arg: Any, suffix: String): (Any, String) = arg match {
case arg: List[_] if suffix.nonEmpty && suffix.head == '%' =>
val (rawsep, rest) = suffix.tail.span(_ != '%')
val sep = StringContext.treatEscapes(rawsep)
if (rest.nonEmpty) (arg map treatSingleArg mkString sep, rest.tail)
else (arg, suffix)
case _ =>
(treatSingleArg(arg), suffix)
}
def treatSingleArg(arg: Any) : Any = arg match {
case arg: Showable => arg.show
case _ => arg
}
if (ctx.reporter.hasErrors &&
ctx.suppressNonSensicalErrors &&
!ctx.settings.YshowSuppressedErrors.value &&
!args.forall(isSensical(_)))
throw new SuppressedMessage
val prefix :: suffixes = sc.parts.toList
val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip
new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*)
}
}
}
|