diff --git a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala index 5b19fe0e7bdd..11e313c47932 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index ceb8ecbc8e03..9558981be800 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -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 @@ -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) @@ -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) = diff --git a/compiler/test/dotc/neg-best-effort-pickling.blacklist b/compiler/test/dotc/neg-best-effort-pickling.blacklist index 1c8421b44539..2daf32509ed1 100644 --- a/compiler/test/dotc/neg-best-effort-pickling.blacklist +++ b/compiler/test/dotc/neg-best-effort-pickling.blacklist @@ -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 diff --git a/tests/neg/i11226.check b/tests/neg/i11226.check new file mode 100644 index 000000000000..571f54326808 --- /dev/null +++ b/tests/neg/i11226.check @@ -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. diff --git a/tests/neg/i11226.scala b/tests/neg/i11226.scala new file mode 100644 index 000000000000..34c6eb78fd2d --- /dev/null +++ b/tests/neg/i11226.scala @@ -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 +} \ No newline at end of file diff --git a/tests/neg/i11226a.check b/tests/neg/i11226a.check new file mode 100644 index 000000000000..ecb0760dd01c --- /dev/null +++ b/tests/neg/i11226a.check @@ -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` diff --git a/tests/neg/i11226a.scala b/tests/neg/i11226a.scala new file mode 100644 index 000000000000..f30530c5a58e --- /dev/null +++ b/tests/neg/i11226a.scala @@ -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 +} \ No newline at end of file diff --git a/tests/neg/i16407.check b/tests/neg/i16407.check index 5c6bd19ca8c1..481d70e83ce3 100644 --- a/tests/neg/i16407.check +++ b/tests/neg/i16407.check @@ -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. diff --git a/tests/pos/i11226b.scala b/tests/pos/i11226b.scala new file mode 100644 index 000000000000..4074cbfc4b2e --- /dev/null +++ b/tests/pos/i11226b.scala @@ -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 +} \ No newline at end of file