Skip to content

Commit d5b8193

Browse files
Backport "Explain unresolvable references better" to LTS (#21129)
Backports #20477 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 386a602 + b838ea1 commit d5b8193

File tree

8 files changed

+94
-15
lines changed

8 files changed

+94
-15
lines changed

compiler/src/dotty/tools/dotc/core/TypeErrors.scala

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,30 @@ end TypeError
5757
class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name])(using Context) extends TypeError:
5858
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(", ")}"
5959

60-
class MissingType(pre: Type, name: Name)(using Context) extends TypeError:
61-
private def otherReason(pre: Type)(using Context): String = pre match {
62-
case pre: ThisType if pre.cls.givenSelfType.exists =>
63-
i"\nor the self type of $pre might not contain all transitive dependencies"
64-
case _ => ""
65-
}
60+
class MissingType(val pre: Type, val name: Name)(using Context) extends TypeError:
61+
62+
def reason(using Context): String =
63+
def missingClassFile =
64+
"The classfile defining the type might be missing from the classpath"
65+
val cls = pre.classSymbol
66+
val givenSelf = cls match
67+
case cls: ClassSymbol => cls.givenSelfType
68+
case _ => NoType
69+
pre match
70+
case pre: ThisType if pre.cls.givenSelfType.exists =>
71+
i"""$missingClassFile
72+
|or the self type of $pre might not contain all transitive dependencies"""
73+
case _ if givenSelf.exists && givenSelf.member(name).exists =>
74+
i"""$name exists as a member of the self type $givenSelf of $cls
75+
|but it cannot be called on a receiver whose type does not extend $cls"""
76+
case _ =>
77+
missingClassFile
78+
6679

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

7386
class RecursionOverflow(val op: String, details: => String, val previous: Throwable, val weight: Int)(using Context)

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ class TypeMismatch(val found: Type, expected: Type, val inTree: Option[untpd.Tre
298298
// these are usually easier to analyze. We exclude F-bounds since these would
299299
// lead to a recursive infinite expansion.
300300
object reported extends TypeMap, IdentityCaptRefMap:
301+
var notes: String = ""
301302
def setVariance(v: Int) = variance = v
302303
val constraint = mapCtx.typerState.constraint
303304
var fbounded = false
@@ -315,6 +316,15 @@ class TypeMismatch(val found: Type, expected: Type, val inTree: Option[untpd.Tre
315316
case tp: LazyRef =>
316317
fbounded = true
317318
tp
319+
case tp @ TypeRef(pre, _) =>
320+
if pre != NoPrefix && !pre.member(tp.name).exists then
321+
notes ++=
322+
i"""
323+
|
324+
|Note that I could not resolve reference $tp.
325+
|${MissingType(pre, tp.name).reason}
326+
"""
327+
mapOver(tp)
318328
case _ =>
319329
mapOver(tp)
320330

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

332342
override def msgPostscript(using Context) =

tests/neg/i11226.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Error: tests/neg/i11226.scala:13:36 ---------------------------------------------------------------------------------
2+
13 | def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
3+
| ^
4+
| Cannot resolve reference to type (Unsubscriber.this.bus : ManagedActorClassification).Subscriber.
5+
| Subscriber exists as a member of the self type ActorEventBus of trait ManagedActorClassification
6+
| but it cannot be called on a receiver whose type does not extend trait ManagedActorClassification.

tests/neg/i11226.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
trait ActorRef
2+
3+
trait ActorEventBus {
4+
type Subscriber = ActorRef
5+
}
6+
7+
trait ManagedActorClassification { this: ActorEventBus =>
8+
def unsubscribe(subscriber: Subscriber, from: Any): Unit
9+
def unsubscribe(subscriber: Subscriber): Unit
10+
}
11+
12+
class Unsubscriber(bus: ManagedActorClassification) {
13+
def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
14+
}

tests/neg/i11226a.check

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- [E007] Type Mismatch Error: tests/neg/i11226a.scala:12:48 -----------------------------------------------------------
2+
12 | def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
3+
| ^
4+
| Found: (a : ActorRef)
5+
| Required: Unsubscriber.this.bus.Subscriber
6+
|
7+
| Note that I could not resolve reference Unsubscriber.this.bus.Subscriber.
8+
| Subscriber exists as a member of the self type ActorEventBus of trait ManagedActorClassification
9+
| but it cannot be called on a receiver whose type does not extend trait ManagedActorClassification
10+
|
11+
|
12+
| longer explanation available when compiling with `-explain`

tests/neg/i11226a.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
trait ActorRef
2+
3+
trait ActorEventBus {
4+
type Subscriber = ActorRef
5+
}
6+
7+
trait ManagedActorClassification { this: ActorEventBus =>
8+
def unsubscribe(subscriber: Subscriber): Unit
9+
}
10+
11+
class Unsubscriber(bus: ManagedActorClassification) {
12+
def test(a: ActorRef): Unit = bus.unsubscribe(a) // error
13+
}

tests/neg/i16407.check

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
-- Error: tests/neg/i16407.scala:2:2 -----------------------------------------------------------------------------------
22
2 | f(g()) // error // error
33
| ^
4-
| cannot resolve reference to type (X.this : Y & X).A
5-
| the classfile defining the type might be missing from the classpath
6-
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
4+
| Cannot resolve reference to type (X.this : Y & X).A.
5+
| The classfile defining the type might be missing from the classpath
6+
| or the self type of (X.this : Y & X) might not contain all transitive dependencies.
77
-- Error: tests/neg/i16407.scala:2:4 -----------------------------------------------------------------------------------
88
2 | f(g()) // error // error
99
| ^
10-
| cannot resolve reference to type (X.this : Y & X).A
11-
| the classfile defining the type might be missing from the classpath
12-
| or the self type of (X.this : Y & X) might not contain all transitive dependencies
10+
| Cannot resolve reference to type (X.this : Y & X).A.
11+
| The classfile defining the type might be missing from the classpath
12+
| or the self type of (X.this : Y & X) might not contain all transitive dependencies.

tests/pos/i11226b.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait A {
2+
class T()
3+
}
4+
trait B {
5+
this: A =>
6+
def f(a: Int = 0): Any
7+
}
8+
trait C extends B {
9+
this: A =>
10+
def f(t: T): Any
11+
}

0 commit comments

Comments
 (0)