Skip to content

Commit 0d1721c

Browse files
authored
Merge pull request #1611 from ShaneDelmore/1589_Missing_error_messages
Improved error messages in Desugar.scala
2 parents b648d1d + 2a310ac commit 0d1721c

File tree

2 files changed

+87
-5
lines changed

2 files changed

+87
-5
lines changed

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -433,11 +433,11 @@ object desugar {
433433
if (!mods.is(Implicit))
434434
Nil
435435
else if (ctx.owner is Package) {
436-
ctx.error("implicit classes may not be toplevel", cdef.pos)
436+
ctx.error(TopLevelImplicitClass(cdef), cdef.pos)
437437
Nil
438438
}
439439
else if (isCaseClass) {
440-
ctx.error("implicit classes may not be case classes", cdef.pos)
440+
ctx.error(ImplicitCaseClass(cdef), cdef.pos)
441441
Nil
442442
}
443443
else
@@ -497,7 +497,7 @@ object desugar {
497497
.withPos(mdef.pos)
498498
val ValDef(selfName, selfTpt, _) = tmpl.self
499499
val selfMods = tmpl.self.mods
500-
if (!selfTpt.isEmpty) ctx.error("object definition may not have a self type", tmpl.self.pos)
500+
if (!selfTpt.isEmpty) ctx.error(ObjectMayNotHaveSelfType(mdef), tmpl.self.pos)
501501
val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(name)), tmpl.self.rhs)
502502
.withMods(selfMods)
503503
.withPos(tmpl.self.pos orElse tmpl.pos.startPos)
@@ -931,7 +931,7 @@ object desugar {
931931
val arity = ts.length
932932
def tupleTypeRef = defn.TupleType(arity)
933933
if (arity > Definitions.MaxTupleArity) {
934-
ctx.error(s"tuple too long (max allowed: ${Definitions.MaxTupleArity})", tree.pos)
934+
ctx.error(TupleTooLong(ts), tree.pos)
935935
unitLiteral
936936
} else if (arity == 1) ts.head
937937
else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts)

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

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ package diagnostic
55

66
import dotc.core._
77
import Contexts.Context, Decorators._, Symbols._, Names._, Types._
8+
import ast.untpd.{Modifiers, ModuleDef}
89
import util.{SourceFile, NoSource}
910
import util.{SourcePosition, NoSourcePosition}
1011
import config.Settings.Setting
1112
import interfaces.Diagnostic.{ERROR, WARNING, INFO}
12-
import printing.SyntaxHighlighting._
13+
import printing.Highlighting._
1314
import printing.Formatting
1415

1516
object messages {
@@ -318,4 +319,85 @@ object messages {
318319
|$code2
319320
|""".stripMargin
320321
}
322+
323+
def implicitClassRestrictionsText(implicit ctx: Context) =
324+
hl"""${NoColor("For a full list of restrictions on implicit classes visit")}
325+
| ${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}""".stripMargin
326+
327+
case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context)
328+
extends Message(10) {
329+
val kind = "Syntax"
330+
331+
val msg = hl"""|An ${"implicit class"} may not be top-level"""
332+
333+
val explanation = {
334+
val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef
335+
val exampleArgs = constr0.vparamss(0).map(_.withMods(Modifiers()).show).mkString(", ")
336+
def defHasBody[T] = impl.body.exists(!_.isEmpty)
337+
val exampleBody = if (defHasBody) "{\n ...\n }" else ""
338+
hl"""|There may not be any method, member or object in scope with the same name as the
339+
|implicit class and a case class automatically gets a companion object with the same name
340+
|created by the compiler which would cause a naming conflict if it were allowed.
341+
|
342+
|""".stripMargin + implicitClassRestrictionsText + hl"""|
343+
|
344+
|To resolve the conflict declare ${cdef.name} inside of an ${"object"} then import the class
345+
|from the object at the use site if needed, for example:
346+
|
347+
|object Implicits {
348+
| implicit class ${cdef.name}($exampleArgs)$exampleBody
349+
|}
350+
|
351+
|// At the use site:
352+
|import Implicits.${cdef.name}""".stripMargin
353+
}
354+
}
355+
356+
case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context)
357+
extends Message(11) {
358+
val kind = "Syntax"
359+
360+
val msg = hl"""|A ${"case class"} may not be defined as ${"implicit"}"""
361+
362+
val explanation =
363+
hl"""|implicit classes may not be case classes. Instead use a plain class:
364+
| example: implicit class ${cdef.name}...
365+
|
366+
|""".stripMargin + implicitClassRestrictionsText
367+
}
368+
369+
case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context)
370+
extends Message(12) {
371+
val kind = "Syntax"
372+
373+
val msg = hl"""|${"objects"} must not have a ${"self type"}"""
374+
375+
val explanation = {
376+
val ModuleDef(name, tmpl) = mdef
377+
val ValDef(_, selfTpt, _) = tmpl.self
378+
hl"""|objects must not have a ${"self type"}:
379+
|
380+
|Consider these alternative solutions:
381+
| - Create a trait or a class instead of an object
382+
| - Let the object extend a trait containing the self type:
383+
| example: object $name extends ${selfTpt.show}""".stripMargin
384+
}
385+
}
386+
387+
case class TupleTooLong(ts: List[untpd.Tree])(implicit ctx: Context)
388+
extends Message(13) {
389+
import Definitions.MaxTupleArity
390+
val kind = "Syntax"
391+
392+
val msg = hl"""|A ${"tuple"} cannot have more than ${MaxTupleArity} members"""
393+
394+
val explanation = {
395+
val members = ts.map(_.showSummary).grouped(MaxTupleArity)
396+
val nestedRepresentation = members.map(_.mkString(", ")).mkString(")(")
397+
hl"""|This restriction will be removed in the future.
398+
|Currently it is possible to use nested tuples when more than ${MaxTupleArity} are needed, for example:
399+
|
400+
| ((${nestedRepresentation}))""".stripMargin
401+
}
402+
}
321403
}

0 commit comments

Comments
 (0)