Skip to content
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

Explain unresolvable references better #20477

Merged
merged 4 commits into from
May 28, 2024
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
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 @@ -301,6 +301,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 @@ -318,6 +319,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 @@ -329,7 +339,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
1 change: 1 addition & 0 deletions compiler/test/dotc/neg-best-effort-pickling.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ i17121.scala
illegal-match-types.scala
i13780-1.scala
i20317a.scala
i11226.scala

# semantic db generation fails in the first compilation
i1642.scala
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
}
Loading