Skip to content

Give reasonable error messages when classfiles are not found #8414

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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -832,9 +832,10 @@ object Denotations {

private def updateValidity()(implicit ctx: Context): this.type = {
assert(
ctx.runId >= validFor.runId ||
ctx.settings.YtestPickler.value || // mixing test pickler with debug printing can travel back in time
symbol.is(Permanent), // Permanent symbols are valid in all runIds
ctx.runId >= validFor.runId
|| ctx.settings.YtestPickler.value // mixing test pickler with debug printing can travel back in time
|| ctx.mode.is(Mode.Printing) // no use to be picky when printing error messages
|| symbol.isOneOf(ValidForeverFlags),
s"denotation $this invalid in run ${ctx.runId}. ValidFor: $validFor")
var d: SingleDenotation = this
while ({
Expand Down
14 changes: 8 additions & 6 deletions compiler/src/dotty/tools/dotc/core/TypeErrors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import config.Printers.cyclicErrors

class TypeError(msg: String) extends Exception(msg) {
def this() = this("")
def toMessage(implicit ctx: Context): Message = super.getMessage
final def toMessage(implicit ctx: Context): Message =
produceMessage(using ctx.addMode(Mode.Printing))
def produceMessage(using Context): Message = super.getMessage
override def getMessage: String = super.getMessage
}

class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name]) extends TypeError {
override def toMessage(implicit ctx: Context): Message =
override def produceMessage(implicit ctx: Context): Message =
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(", ")}"
}

Expand All @@ -33,7 +35,7 @@ class MissingType(pre: Type, name: Name) extends TypeError {
case _ => ""
}

override def toMessage(implicit ctx: Context): Message = {
override def produceMessage(implicit ctx: Context): Message = {
if (ctx.debug) printStackTrace()
i"""cannot resolve reference to type $pre.$name
|the classfile defining the type might be missing from the classpath${otherReason(pre)}"""
Expand Down Expand Up @@ -67,7 +69,7 @@ class RecursionOverflow(val op: String, details: => String, val previous: Throwa
(rs.map(_.explanation): List[String]).mkString("\n ", "\n| ", "")
}

override def toMessage(implicit ctx: Context): Message = {
override def produceMessage(implicit ctx: Context): Message = {
val mostCommon = recursions.groupBy(_.op).toList.maxBy(_._2.map(_.weight).sum)._2.reverse
s"""Recursion limit exceeded.
|Maybe there is an illegal cyclic reference?
Expand Down Expand Up @@ -109,7 +111,7 @@ object handleRecursive {
class CyclicReference private (val denot: SymDenotation) extends TypeError {
var inImplicitSearch: Boolean = false

override def toMessage(implicit ctx: Context): Message = {
override def produceMessage(implicit ctx: Context): Message = {
val cycleSym = denot.symbol

// cycleSym.flags would try completing denot and would fail, but here we can use flagsUNSAFE to detect flags
Expand Down Expand Up @@ -182,7 +184,7 @@ class MergeError(val sym1: Symbol, val sym2: Symbol, val tp1: Type, val tp2: Typ
s"\nas members of $owner"
}

override def toMessage(implicit ctx: Context): Message = {
override def produceMessage(implicit ctx: Context): Message = {
if (ctx.debug) printStackTrace()
i"""cannot merge
| ${showSymbol(sym1)} of type ${showType(tp1)} and
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ class TreePickler(pickler: TastyPickler) {
}
}
catch {
case ex: TypeError =>
ctx.error(ex.toMessage, tree.sourcePos.focus)
case ex: AssertionError =>
println(i"error when pickling tree $tree")
throw ex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class NoExplanation(val msg: String) extends Message(ErrorMessageID.NoExplanatio
val explanation: String = ""
val kind: String = ""

override def toString(): String = s"NoExplanation($msg)"
override def toString(): String = msg
}

/** The extractor for `NoExplanation` can be used to check whether any error
Expand Down
24 changes: 24 additions & 0 deletions tests/neg/i6501.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import scala.collection.immutable.HashMap

trait MapImpl {
type Key
type Value
type Map
val lookup: Map => Key => Value
}
class HashMapImpl[K, V] extends MapImpl {
type Key = K
type Value = V
type Map = HashMap[K, V]
val lookup: Map => Key => Value = m => k => m(k)
}
object Foo {
val Server0:
(mImpl: MapImpl) => mImpl.Map => mImpl.Key => mImpl.Value
= mImpl => mImpl.lookup
val Client:
(server: (mImpl: MapImpl & {type Key = String} & {type Value = Int}) => mImpl.Map => String => Int) => Int =
// server => server(??? : (HashMapImpl[String, Int]))(???)("test lookup key") //works
// server => server(HashMapImpl[String, Int])(???)("") //works
server => server(???)(???)("test lookup key") // error
}
11 changes: 11 additions & 0 deletions tests/neg/i8405.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class ActorRef
trait ActorEventBus {
type Subscriber = ActorRef
}
trait ManagedActorClassification { this: ActorEventBus =>
def unsubscribe(subscriber: Subscriber): Unit = ???
}
class ActorClassificationUnsubscriber(bus: ManagedActorClassification) {
val actor = ???
bus.unsubscribe(actor) // error
}