Skip to content

Commit b0d9b74

Browse files
committed
Mention cycleSym instead of tree.name in errors
At this point, I can stop using tree.name altogether.
1 parent 6308afd commit b0d9b74

File tree

4 files changed

+72
-16
lines changed

4 files changed

+72
-16
lines changed

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ object handleRecursive {
101101
class CyclicReference private (val denot: SymDenotation, var inImplicitSearch: Boolean = false) extends TypeError {
102102
override def toMessage(implicit ctx: Context): Message = {
103103
val cycleSym = denot.symbol
104+
val unsafeFlags = cycleSym.flagsUNSAFE
105+
val isMethod = unsafeFlags.is(Method)
106+
val isVal = !isMethod && cycleSym.isTerm
107+
val isImplicit = unsafeFlags.is(Implicit)
104108

105109
/* This CyclicReference might have arisen from asking for `m`'s type while trying to infer it.
106110
* To try to diagnose this, walk the context chain searching for context in
@@ -110,13 +114,15 @@ class CyclicReference private (val denot: SymDenotation, var inImplicitSearch: B
110114
def errorMsg(cx: Context): Message = {
111115
if (cx.mode is Mode.InferringReturnType) {
112116
cx.tree match {
113-
case tree: untpd.ValOrDefDef if inImplicitSearch && !tree.tpt.typeOpt.exists =>
114-
// Can happen in implicit defs (#4709) or outside (#3253).
115-
TermMemberNeedsNeedsResultTypeForImplicitSearch(tree.name, cycleSym)
116-
case tree: untpd.DefDef if !tree.tpt.typeOpt.exists =>
117-
OverloadedOrRecursiveMethodNeedsResultType(tree.name, cycleSym)
118-
case tree: untpd.ValDef if !tree.tpt.typeOpt.exists =>
119-
RecursiveValueNeedsResultType(tree.name, cycleSym)
117+
case tree: untpd.ValOrDefDef if !tree.tpt.typeOpt.exists =>
118+
if (inImplicitSearch)
119+
TermMemberNeedsNeedsResultTypeForImplicitSearch(tree.name, cycleSym)
120+
else if (isMethod)
121+
OverloadedOrRecursiveMethodNeedsResultType(tree.name, cycleSym)
122+
else if (isVal)
123+
RecursiveValueNeedsResultType(tree.name, cycleSym)
124+
else
125+
errorMsg(cx.outer)
120126
case _ =>
121127
errorMsg(cx.outer)
122128
}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,24 +1263,24 @@ object messages {
12631263
case class OverloadedOrRecursiveMethodNeedsResultType(methodName: Names.TermName, cycleSym: Symbol)(implicit ctx: Context)
12641264
extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) {
12651265
val kind = "Syntax"
1266-
val msg = hl"""overloaded or recursive method ${methodName} needs return type"""
1266+
val msg = hl"""overloaded or recursive ${cycleSym} needs return type"""
12671267
val explanation =
1268-
hl"""Case 1: ${methodName} is overloaded
1269-
|If there are multiple methods named `${methodName}` and at least one definition of
1268+
hl"""Case 1: ${cycleSym} is overloaded
1269+
|If there are multiple methods named `${cycleSym}` and at least one definition of
12701270
|it calls another, you need to specify the calling method's return type.
12711271
|
1272-
|Case 2: ${methodName} is recursive
1273-
|If `${methodName}` calls itself on any path (even through mutual recursion), you need to specify the return type
1274-
|of `${methodName}` or of a definition it's mutually recursive with.
1272+
|Case 2: ${cycleSym} is recursive
1273+
|If `${cycleSym}` calls itself on any path (even through mutual recursion), you need to specify the return type
1274+
|of `${cycleSym}` or of a definition it's mutually recursive with.
12751275
|""".stripMargin
12761276
}
12771277

12781278
case class RecursiveValueNeedsResultType(valName: Names.TermName, cycleSym: Symbol)(implicit ctx: Context)
12791279
extends Message(RecursiveValueNeedsResultTypeID) {
12801280
val kind = "Syntax"
1281-
val msg = hl"""recursive value ${valName} needs type"""
1281+
val msg = hl"""recursive ${cycleSym} needs type"""
12821282
val explanation =
1283-
hl"""The definition of `${valName}` is recursive and you need to specify its type.
1283+
hl"""The definition of `${cycleSym}` is recursive and you need to specify its type.
12841284
|""".stripMargin
12851285
}
12861286

@@ -2117,7 +2117,7 @@ object messages {
21172117
val msg = hl"""$cycleSym needs result type because its right-hand side attempts implicit search"""
21182118
val explanation =
21192119
hl"""|The right hand-side of $cycleSym's definition requires an implicit search at the highlighted position.
2120-
|To avoid this error, give `${cycleSym.name}` an explicit type.
2120+
|To avoid this error, give `$cycleSym` an explicit type.
21212121
|""".stripMargin
21222122
}
21232123
}

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,24 @@ class ErrorMessagesTests extends ErrorMessagesTest {
246246
assertEquals("i", cycleSym.name.show)
247247
}
248248

249+
@Test def recursiveValueNeedsReturnType2 =
250+
checkMessagesAfter(FrontEnd.name) {
251+
"""
252+
|class Scope() {
253+
| lazy val i = j + 5
254+
| lazy val j = i
255+
|}
256+
""".stripMargin
257+
}
258+
.expect { (ictx, messages) =>
259+
implicit val ctx: Context = ictx
260+
261+
assertMessageCount(1, messages)
262+
val RecursiveValueNeedsResultType(valName, cycleSym) :: Nil = messages
263+
assertEquals("j", valName.show)
264+
assertEquals("i", cycleSym.name.show)
265+
}
266+
249267
@Test def cyclicReferenceInvolving =
250268
checkMessagesAfter(FrontEnd.name) {
251269
"""
@@ -322,6 +340,29 @@ class ErrorMessagesTests extends ErrorMessagesTest {
322340
assertEquals("odd", cycleSym.name.show)
323341
}
324342

343+
@Test def mutualRecursion_i2001b =
344+
checkMessagesAfter(FrontEnd.name) {
345+
"""
346+
|class A {
347+
| def odd(x: Int) = if (x == 0) false else !even(x-1)
348+
| def even(x: Int) = {
349+
| val foo = {
350+
| if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type
351+
| }
352+
| false
353+
| }
354+
|}
355+
""".stripMargin
356+
}
357+
.expect { (ictx, messages) =>
358+
implicit val ctx: Context = ictx
359+
360+
assertMessageCount(1, messages)
361+
val OverloadedOrRecursiveMethodNeedsResultType(methodName, cycleSym) :: Nil = messages
362+
// Not ideal behavior
363+
assertEquals("foo", methodName.show)
364+
assertEquals("odd", cycleSym.name.show)
365+
}
325366

326367
@Test def termMemberNeedsNeedsResultTypeForImplicitSearch =
327368
checkMessagesAfter(FrontEnd.name) {

tests/neg/i2001b.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class A {
2+
def odd(x: Int) = if (x == 0) false else !even(x-1)
3+
def even(x: Int) = {
4+
val foo = {
5+
if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type
6+
}
7+
false
8+
}
9+
}

0 commit comments

Comments
 (0)