-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Improved error messages in Desugar.scala #1611
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,11 +5,12 @@ package diagnostic | |
|
||
import dotc.core._ | ||
import Contexts.Context, Decorators._, Symbols._, Names._, Types._ | ||
import ast.untpd.{Modifiers, ModuleDef} | ||
import util.{SourceFile, NoSource} | ||
import util.{SourcePosition, NoSourcePosition} | ||
import config.Settings.Setting | ||
import interfaces.Diagnostic.{ERROR, WARNING, INFO} | ||
import printing.SyntaxHighlighting._ | ||
import printing.Highlighting._ | ||
import printing.Formatting | ||
|
||
object messages { | ||
|
@@ -318,4 +319,85 @@ object messages { | |
|$code2 | ||
|""".stripMargin | ||
} | ||
|
||
def implicitClassRestrictionsText(implicit ctx: Context) = | ||
hl"""${NoColor("For a full list of restrictions on implicit classes visit")} | ||
| ${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}""".stripMargin | ||
|
||
case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) | ||
extends Message(10) { | ||
val kind = "Syntax" | ||
|
||
val msg = hl"""|An ${"implicit class"} may not be top-level""" | ||
|
||
val explanation = { | ||
val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef | ||
val exampleArgs = constr0.vparamss(0).map(_.withMods(Modifiers()).show).mkString(", ") | ||
def defHasBody[T] = impl.body.exists(!_.isEmpty) | ||
val exampleBody = if (defHasBody) "{\n ...\n }" else "" | ||
hl"""|There may not be any method, member or object in scope with the same name as the | ||
|implicit class and a case class automatically gets a companion object with the same name | ||
|created by the compiler which would cause a naming conflict if it were allowed. | ||
| | ||
|""".stripMargin + implicitClassRestrictionsText + hl"""| | ||
| | ||
|To resolve the conflict declare ${cdef.name} inside of an ${"object"} then import the class | ||
|from the object at the use site if needed, for example: | ||
| | ||
|object Implicits { | ||
| implicit class ${cdef.name}($exampleArgs)$exampleBody | ||
|} | ||
| | ||
|// At the use site: | ||
|import Implicits.${cdef.name}""".stripMargin | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Example output:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated error on def with body to prevent overly long error explanation:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be nice to make it more explicit that the object Implicits {
implicit class Foo(val bar: Int, val baz: String){
...
}
}
...
// At the use site:
import Implicits.Foo |
||
|
||
case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) | ||
extends Message(11) { | ||
val kind = "Syntax" | ||
|
||
val msg = hl"""|A ${"case class"} may not be defined as ${"implicit"}""" | ||
|
||
val explanation = | ||
hl"""|implicit classes may not be case classes. Instead use a plain class: | ||
| example: implicit class ${cdef.name}... | ||
| | ||
|""".stripMargin + implicitClassRestrictionsText | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) | ||
extends Message(12) { | ||
val kind = "Syntax" | ||
|
||
val msg = hl"""|${"objects"} must not have a ${"self type"}""" | ||
|
||
val explanation = { | ||
val ModuleDef(name, tmpl) = mdef | ||
val ValDef(_, selfTpt, _) = tmpl.self | ||
hl"""|objects must not have a ${"self type"}: | ||
| | ||
|Consider these alternative solutions: | ||
| - Create a trait or a class instead of an object | ||
| - Let the object extend a trait containing the self type: | ||
| example: object $name extends ${selfTpt.show}""".stripMargin | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
case class TupleTooLong(ts: List[untpd.Tree])(implicit ctx: Context) | ||
extends Message(13) { | ||
import Definitions.MaxTupleArity | ||
val kind = "Syntax" | ||
|
||
val msg = hl"""|A ${"tuple"} cannot have more than ${MaxTupleArity} members""" | ||
|
||
val explanation = { | ||
val members = ts.map(_.showSummary).grouped(MaxTupleArity) | ||
val nestedRepresentation = members.map(_.mkString(", ")).mkString(")(") | ||
hl"""|This restriction will be removed in the future. | ||
|Currently it is possible to use nested tuples when more than ${MaxTupleArity} are needed, for example: | ||
| | ||
| ((${nestedRepresentation}))""".stripMargin | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is duplicated from Desugar.scala. Is it preferred to duplicate it here to keep the coupling looser or should I instead add more parameters to the case class and pass along explicitely what I need, name, impl, constr0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, I think there's a risk that more people will need to print the class def and as such perhaps we should factor this out into a method call that takes the
cdef
- a small bit of duplication here is fine in order for it to be easy to use for new contributors IMHO.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that the explanation body has been simplified there isn't really much here worth extracting.