|
| 1 | +package dotty.tools |
| 2 | +package dotc |
| 3 | +package core |
| 4 | + |
| 5 | +import util.common._ |
| 6 | +import Types._ |
| 7 | +import Symbols._ |
| 8 | +import Flags._ |
| 9 | +import Names._ |
| 10 | +import Contexts._ |
| 11 | +import SymDenotations._ |
| 12 | +import Denotations._ |
| 13 | +import Decorators._ |
| 14 | +import reporting.diagnostic.Message |
| 15 | +import reporting.diagnostic.messages._ |
| 16 | +import ast.untpd |
| 17 | +import config.Printers.cyclicErrors |
| 18 | + |
| 19 | +class TypeError(msg: String) extends Exception(msg) { |
| 20 | + def this() = this("") |
| 21 | + def toMessage(implicit ctx: Context): Message = getMessage |
| 22 | +} |
| 23 | + |
| 24 | +class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name]) extends TypeError { |
| 25 | + override def toMessage(implicit ctx: Context): Message = |
| 26 | + i"malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}" |
| 27 | +} |
| 28 | + |
| 29 | +class MissingType(pre: Type, name: Name) extends TypeError { |
| 30 | + private def otherReason(pre: Type)(implicit ctx: Context): String = pre match { |
| 31 | + case pre: ThisType if pre.cls.givenSelfType.exists => |
| 32 | + i"\nor the self type of $pre might not contain all transitive dependencies" |
| 33 | + case _ => "" |
| 34 | + } |
| 35 | + |
| 36 | + override def toMessage(implicit ctx: Context): Message = { |
| 37 | + if (ctx.debug) printStackTrace() |
| 38 | + i"""cannot resolve reference to type $pre.$name |
| 39 | + |the classfile defining the type might be missing from the classpath${otherReason(pre)}""" |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +class RecursionOverflow(val op: String, details: => String, previous: Throwable, val weight: Int) extends TypeError { |
| 44 | + |
| 45 | + def explanation = s"$op $details" |
| 46 | + |
| 47 | + private def recursions: List[RecursionOverflow] = { |
| 48 | + val nested = previous match { |
| 49 | + case previous: RecursionOverflow => previous.recursions |
| 50 | + case _ => Nil |
| 51 | + } |
| 52 | + this :: nested |
| 53 | + } |
| 54 | + |
| 55 | + def opsString(rs: List[RecursionOverflow])(implicit ctx: Context): String = { |
| 56 | + val maxShown = 20 |
| 57 | + if (rs.lengthCompare(maxShown) > 0) |
| 58 | + i"""${opsString(rs.take(maxShown / 2))} |
| 59 | + | ... |
| 60 | + |${opsString(rs.takeRight(maxShown / 2))}""" |
| 61 | + else |
| 62 | + (rs.map(_.explanation): List[String]).mkString("\n ", "\n| ", "") |
| 63 | + } |
| 64 | + |
| 65 | + override def toMessage(implicit ctx: Context): Message = { |
| 66 | + val mostCommon = recursions.groupBy(_.op).toList.maxBy(_._2.map(_.weight).sum)._2.reverse |
| 67 | + s"""Recursion limit exceeded. |
| 68 | + |Maybe there is an illegal cyclic reference? |
| 69 | + |If that's not the case, you could also try to increase the stacksize using the -Xss JVM option. |
| 70 | + |A recurring operation is (inner to outer): |
| 71 | + |${opsString(mostCommon)}""".stripMargin |
| 72 | + } |
| 73 | + |
| 74 | + override def fillInStackTrace(): Throwable = this |
| 75 | + override def getStackTrace() = previous.getStackTrace() |
| 76 | +} |
| 77 | + |
| 78 | +/** Post-process exceptions that might result from StackOverflow to add |
| 79 | + * tracing information while unwalking the stack. |
| 80 | + */ |
| 81 | +// Beware: Since this object is only used when handling a StackOverflow, this code |
| 82 | +// cannot consume significant amounts of stack. |
| 83 | +object handleRecursive { |
| 84 | + def apply(op: String, details: => String, exc: Throwable, weight: Int = 1)(implicit ctx: Context): Nothing = { |
| 85 | + if (ctx.settings.YnoDecodeStacktraces.value) { |
| 86 | + throw exc |
| 87 | + } else { |
| 88 | + exc match { |
| 89 | + case _: RecursionOverflow => |
| 90 | + throw new RecursionOverflow(op, details, exc, weight) |
| 91 | + case _ => |
| 92 | + var e = exc |
| 93 | + while (e != null && !e.isInstanceOf[StackOverflowError]) e = e.getCause |
| 94 | + if (e != null) throw new RecursionOverflow(op, details, e, weight) |
| 95 | + else throw exc |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +class CyclicReference private (val denot: SymDenotation) extends TypeError { |
| 102 | + |
| 103 | + override def toMessage(implicit ctx: Context) = { |
| 104 | + |
| 105 | + def errorMsg(cx: Context): Message = |
| 106 | + if (cx.mode is Mode.InferringReturnType) { |
| 107 | + cx.tree match { |
| 108 | + case tree: untpd.DefDef if !tree.tpt.typeOpt.exists => |
| 109 | + OverloadedOrRecursiveMethodNeedsResultType(tree.name) |
| 110 | + case tree: untpd.ValDef if !tree.tpt.typeOpt.exists => |
| 111 | + RecursiveValueNeedsResultType(tree.name) |
| 112 | + case _ => |
| 113 | + errorMsg(cx.outer) |
| 114 | + } |
| 115 | + } |
| 116 | + else CyclicReferenceInvolving(denot) |
| 117 | + |
| 118 | + val cycleSym = denot.symbol |
| 119 | + if (cycleSym.is(Implicit, butNot = Method) && cycleSym.owner.isTerm) |
| 120 | + CyclicReferenceInvolvingImplicit(cycleSym) |
| 121 | + else |
| 122 | + errorMsg(ctx) |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +object CyclicReference { |
| 127 | + def apply(denot: SymDenotation)(implicit ctx: Context): CyclicReference = { |
| 128 | + val ex = new CyclicReference(denot) |
| 129 | + if (!(ctx.mode is Mode.CheckCyclic)) { |
| 130 | + cyclicErrors.println(ex.getMessage) |
| 131 | + for (elem <- ex.getStackTrace take 200) |
| 132 | + cyclicErrors.println(elem.toString) |
| 133 | + } |
| 134 | + ex |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +class MergeError(val sym1: Symbol, val sym2: Symbol, val tp1: Type, val tp2: Type, prefix: Type) extends TypeError { |
| 139 | + |
| 140 | + private def showSymbol(sym: Symbol)(implicit ctx: Context): String = |
| 141 | + if (sym.exists) sym.showLocated else "[unknown]" |
| 142 | + |
| 143 | + private def showType(tp: Type)(implicit ctx: Context) = tp match { |
| 144 | + case ClassInfo(_, cls, _, _, _) => cls.showLocated |
| 145 | + case _ => tp.show |
| 146 | + } |
| 147 | + |
| 148 | + protected def addendum(implicit ctx: Context) = |
| 149 | + if (prefix `eq` NoPrefix) "" else i"\nas members of type $prefix" |
| 150 | + |
| 151 | + override def toMessage(implicit ctx: Context): Message = { |
| 152 | + if (ctx.debug) printStackTrace() |
| 153 | + i"""cannot merge |
| 154 | + | ${showSymbol(sym1)} of type ${showType(tp1)} and |
| 155 | + | ${showSymbol(sym2)} of type ${showType(tp2)}$addendum |
| 156 | + """ |
| 157 | + } |
| 158 | +} |
0 commit comments