Skip to content

Commit

Permalink
Backport "Explain unresolvable references better" to LTS (#21129)
Browse files Browse the repository at this point in the history
Backports #20477 to the LTS branch.

PR submitted by the release tooling.
[skip ci]
  • Loading branch information
WojciechMazur authored Jul 9, 2024
2 parents 386a602 + b838ea1 commit d5b8193
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 15 deletions.
29 changes: 21 additions & 8 deletions compiler/src/dotty/tools/dotc/core/TypeErrors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,30 @@ end TypeError
class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name])(using Context) extends TypeError:
def toMessage(using Context) = em"malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}"

class MissingType(pre: Type, name: Name)(using Context) extends TypeError:
private def otherReason(pre: Type)(using Context): String = pre match {
case pre: ThisType if pre.cls.givenSelfType.exists =>
i"\nor the self type of $pre might not contain all transitive dependencies"
case _ => ""
}
class MissingType(val pre: Type, val name: Name)(using Context) extends TypeError:

def reason(using Context): String =
def missingClassFile =
"The classfile defining the type might be missing from the classpath"
val cls = pre.classSymbol
val givenSelf = cls match
case cls: ClassSymbol => cls.givenSelfType
case _ => NoType
pre match
case pre: ThisType if pre.cls.givenSelfType.exists =>
i"""$missingClassFile
|or the self type of $pre might not contain all transitive dependencies"""
case _ if givenSelf.exists && givenSelf.member(name).exists =>
i"""$name exists as a member of the self type $givenSelf of $cls
|but it cannot be called on a receiver whose type does not extend $cls"""
case _ =>
missingClassFile


override def toMessage(using Context): Message =
if ctx.debug then printStackTrace()
em"""cannot resolve reference to type $pre.$name
|the classfile defining the type might be missing from the classpath${otherReason(pre)}"""
em"""Cannot resolve reference to type $pre.$name.
|$reason."""
end MissingType

class RecursionOverflow(val op: String, details: => String, val previous: Throwable, val weight: Int)(using Context)
Expand Down
12 changes: 11 additions & 1 deletion compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ class TypeMismatch(val found: Type, expected: Type, val inTree: Option[untpd.Tre
// these are usually easier to analyze. We exclude F-bounds since these would
// lead to a recursive infinite expansion.
object reported extends TypeMap, IdentityCaptRefMap:
var notes: String = ""
def setVariance(v: Int) = variance = v
val constraint = mapCtx.typerState.constraint
var fbounded = false
Expand All @@ -315,6 +316,15 @@ class TypeMismatch(val found: Type, expected: Type, val inTree: Option[untpd.Tre
case tp: LazyRef =>
fbounded = true
tp
case tp @ TypeRef(pre, _) =>
if pre != NoPrefix && !pre.member(tp.name).exists then
notes ++=
i"""
|
|Note that I could not resolve reference $tp.
|${MissingType(pre, tp.name).reason}
"""
mapOver(tp)
case _ =>
mapOver(tp)

Expand All @@ -326,7 +336,7 @@ class TypeMismatch(val found: Type, expected: Type, val inTree: Option[untpd.Tre
else (found1, expected1)
val (foundStr, expectedStr) = Formatting.typeDiff(found2, expected2)
i"""|Found: $foundStr
|Required: $expectedStr"""
|Required: $expectedStr${reported.notes}"""
end msg

override def msgPostscript(using Context) =
Expand Down
6 changes: 6 additions & 0 deletions tests/neg/i11226.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Error: tests/neg/i11226.scala:13:36 ---------------------------------------------------------------------------------
13 | def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
| ^
| Cannot resolve reference to type (Unsubscriber.this.bus : ManagedActorClassification).Subscriber.
| Subscriber exists as a member of the self type ActorEventBus of trait ManagedActorClassification
| but it cannot be called on a receiver whose type does not extend trait ManagedActorClassification.
14 changes: 14 additions & 0 deletions tests/neg/i11226.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
trait ActorRef

trait ActorEventBus {
type Subscriber = ActorRef
}

trait ManagedActorClassification { this: ActorEventBus =>
def unsubscribe(subscriber: Subscriber, from: Any): Unit
def unsubscribe(subscriber: Subscriber): Unit
}

class Unsubscriber(bus: ManagedActorClassification) {
def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
}
12 changes: 12 additions & 0 deletions tests/neg/i11226a.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- [E007] Type Mismatch Error: tests/neg/i11226a.scala:12:48 -----------------------------------------------------------
12 | def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
| ^
| Found: (a : ActorRef)
| Required: Unsubscriber.this.bus.Subscriber
|
| Note that I could not resolve reference Unsubscriber.this.bus.Subscriber.
| Subscriber exists as a member of the self type ActorEventBus of trait ManagedActorClassification
| but it cannot be called on a receiver whose type does not extend trait ManagedActorClassification
|
|
| longer explanation available when compiling with `-explain`
13 changes: 13 additions & 0 deletions tests/neg/i11226a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
trait ActorRef

trait ActorEventBus {
type Subscriber = ActorRef
}

trait ManagedActorClassification { this: ActorEventBus =>
def unsubscribe(subscriber: Subscriber): Unit
}

class Unsubscriber(bus: ManagedActorClassification) {
def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
}
12 changes: 6 additions & 6 deletions tests/neg/i16407.check
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
-- Error: tests/neg/i16407.scala:2:2 -----------------------------------------------------------------------------------
2 | f(g()) // error // error
| ^
| cannot resolve reference to type (X.this : Y & X).A
| the classfile defining the type might be missing from the classpath
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
| Cannot resolve reference to type (X.this : Y & X).A.
| The classfile defining the type might be missing from the classpath
| or the self type of (X.this : Y & X) might not contain all transitive dependencies.
-- Error: tests/neg/i16407.scala:2:4 -----------------------------------------------------------------------------------
2 | f(g()) // error // error
| ^
| cannot resolve reference to type (X.this : Y & X).A
| the classfile defining the type might be missing from the classpath
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
| Cannot resolve reference to type (X.this : Y & X).A.
| The classfile defining the type might be missing from the classpath
| or the self type of (X.this : Y & X) might not contain all transitive dependencies.
11 changes: 11 additions & 0 deletions tests/pos/i11226b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
trait A {
class T()
}
trait B {
this: A =>
def f(a: Int = 0): Any
}
trait C extends B {
this: A =>
def f(t: T): Any
}

0 comments on commit d5b8193

Please sign in to comment.