Skip to content

Commit 34e3508

Browse files
committed
Explanations for recursive/cyclic type requirements
1 parent e1e13e9 commit 34e3508

File tree

2 files changed

+81
-21
lines changed

2 files changed

+81
-21
lines changed

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

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,46 +1146,48 @@ object messages {
11461146
|""".stripMargin
11471147
}
11481148

1149+
case class AnnotatedPrimaryConstructorRequiresModifierOrThis(cls: Name)(implicit ctx: Context)
1150+
extends Message(AnnotatedPrimaryConstructorRequiresModifierOrThisID) {
1151+
val kind = "Syntax"
1152+
val msg = hl"""${"private"}, ${"protected"}, or ${"this"} expected for annotated primary constructor"""
1153+
val explanation =
1154+
hl"""|When using annotations with a primary constructor of a class,
1155+
|the annotation must be followed by an access modifier
1156+
|(${"private"} or ${"protected"}) or ${"this"}.
1157+
|
1158+
|For example:
1159+
| ${"class Sample @deprecated this(param: Parameter) { ..."}
1160+
| ^^^^
1161+
|""".stripMargin
1162+
}
1163+
11491164
case class OverloadedOrRecursiveMethodNeedsResultType(tree: Names.TermName)(implicit ctx: Context)
11501165
extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) {
11511166
val kind = "Syntax"
11521167
val msg = hl"""overloaded or recursive method ${tree} needs result type"""
11531168
val explanation =
1154-
hl"""
1155-
|
1156-
""".stripMargin
1169+
hl"""|${tree} is overloaded and at least one definition of it calls another.
1170+
|You need to specify the calling method's return type.
1171+
""".stripMargin
11571172
}
11581173

11591174
case class RecursiveValueNeedsResultType(tree: Names.TermName)(implicit ctx: Context)
1160-
extends Message(RecursiveValueNeedsResultTypeID) {
1175+
extends Message(RecursiveValueNeedsResultTypeID) {
11611176
val kind = "Syntax"
11621177
val msg = hl"""recursive value ${tree.name} needs type"""
11631178
val explanation =
1164-
hl"""""".stripMargin
1179+
hl"""|The definition of `${tree.name}` is recursive and you need to specify its type.
1180+
""".stripMargin
11651181
}
11661182

11671183
case class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context)
1168-
extends Message(CyclicReferenceInvolvingImplicitID) {
1184+
extends Message(CyclicReferenceInvolvingImplicitID) {
11691185
val kind = "Syntax"
11701186
val msg = hl"""cyclic reference involving implicit $cycleSym"""
11711187
val explanation =
11721188
hl"""|This happens when the right hand-side of $cycleSym's definition involves an implicit search.
1173-
|To avoid the error, give $cycleSym an explicit type.
1189+
|To avoid this error, give `${cycleSym.name}` an explicit type.
11741190
|""".stripMargin
11751191
}
11761192

1177-
case class AnnotatedPrimaryConstructorRequiresModifierOrThis(cls: Name)(implicit ctx: Context)
1178-
extends Message(AnnotatedPrimaryConstructorRequiresModifierOrThisID) {
1179-
val kind = "Syntax"
1180-
val msg = hl"""${"private"}, ${"protected"}, or ${"this"} expected for annotated primary constructor"""
1181-
val explanation =
1182-
hl"""|When using annotations with a primary constructor of a class,
1183-
|the annotation must be followed by an access modifier
1184-
|(${"private"} or ${"protected"}) or ${"this"}.
1185-
|
1186-
|For example:
1187-
| ${"class Sample @deprecated this(param: Parameter) { ..."}
1188-
| ^^^^
1189-
|""".stripMargin
1190-
}
11911193
}

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,62 @@ class ErrorMessagesTests extends ErrorMessagesTest {
212212
val AnnotatedPrimaryConstructorRequiresModifierOrThis(cls) :: Nil = messages
213213
assertEquals("AnotherClass", cls.show)
214214
}
215+
216+
@Test def overloadedMethodNeedsReturnType =
217+
checkMessagesAfter("frontend") {
218+
"""
219+
|class Scope() {
220+
| def foo(i: Int) = foo(i.toString)
221+
| def foo(s: String) = s
222+
|}
223+
""".stripMargin
224+
}
225+
.expect { (ictx, messages) =>
226+
implicit val ctx: Context = ictx
227+
val defn = ictx.definitions
228+
229+
assertMessageCount(1, messages)
230+
val OverloadedOrRecursiveMethodNeedsResultType(tree) :: Nil = messages
231+
assertEquals("foo", tree.show)
232+
}
233+
234+
@Test def recursiveValueNeedsReturnType =
235+
checkMessagesAfter("frontend") {
236+
"""
237+
|class Scope() {
238+
| lazy val i = i + 5
239+
|}
240+
""".stripMargin
241+
}
242+
.expect { (ictx, messages) =>
243+
implicit val ctx: Context = ictx
244+
val defn = ictx.definitions
245+
246+
assertMessageCount(1, messages)
247+
val RecursiveValueNeedsResultType(tree) :: Nil = messages
248+
assertEquals("i", tree.show)
249+
}
250+
251+
@Test def cyclicReferenceInvolvingImplicit =
252+
checkMessagesAfter("frontend") {
253+
"""
254+
|object implicitDefs {
255+
| def foo(implicit x: String) = 1
256+
| def bar() = {
257+
| implicit val x = foo
258+
| x
259+
| }
260+
|}
261+
""".stripMargin
262+
}
263+
.expect { (ictx, messages) =>
264+
implicit val ctx: Context = ictx
265+
val defn = ictx.definitions
266+
267+
assertMessageCount(1, messages)
268+
val CyclicReferenceInvolvingImplicit(tree) :: Nil = messages
269+
assertEquals("x", tree.name.show)
270+
}
271+
272+
215273
}

0 commit comments

Comments
 (0)