Skip to content

Commit 460daf5

Browse files
author
Szymon Rodziewicz
committed
Add error reporting for mirror synthesis
1 parent 34261df commit 460daf5

36 files changed

+213
-116
lines changed

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ object SymUtils:
7979
* parameter section.
8080
*/
8181
def whyNotGenericProduct(using Context): String =
82-
if (!self.is(CaseClass)) "it is not a case class"
83-
else if (self.is(Abstract)) "it is an abstract class"
84-
else if (self.primaryConstructor.info.paramInfoss.length != 1) "it takes more than one parameter list"
85-
else if (isDerivedValueClass(self)) "it is a value class"
82+
if (!self.is(CaseClass)) i"$self is not a case class"
83+
else if (self.is(Abstract)) i"$self is an abstract class"
84+
else if (self.primaryConstructor.info.paramInfoss.length != 1) i"$self takes more than one parameter list"
85+
else if (isDerivedValueClass(self)) i"$self is a value class"
8686
else ""
8787

8888
def isGenericProduct(using Context): Boolean = whyNotGenericProduct.isEmpty
@@ -144,9 +144,9 @@ object SymUtils:
144144
*/
145145
def whyNotGenericSum(declScope: Symbol)(using Context): String =
146146
if (!self.is(Sealed))
147-
s"it is not a sealed ${self.kindString}"
147+
s"$self is not a sealed ${self.kindString}"
148148
else if (!self.isOneOf(AbstractOrTrait))
149-
s"it is not an abstract class"
149+
s"$self is not an abstract class"
150150
else {
151151
val children = self.children
152152
val companionMirror = self.useCompanionAsSumMirror
@@ -157,20 +157,20 @@ object SymUtils:
157157
(self.isContainedIn(sym) && (companionMirror || declScope.isContainedIn(sym)))
158158
|| sym.is(Module) && isAccessible(sym.owner)
159159

160-
if (child == self) "it has anonymous or inaccessible subclasses"
161-
else if (!isAccessible(child.owner)) i"its child $child is not accessible"
160+
if (child == self) i"$self has anonymous or inaccessible subclasses"
161+
else if (!isAccessible(child.owner)) i"$self's child $child is not accessible"
162162
else if (!child.isClass) ""
163163
else {
164164
val s = child.whyNotGenericProduct
165165
if (s.isEmpty) s
166166
else if (child.is(Sealed)) {
167167
val s = child.whyNotGenericSum(if child.useCompanionAsSumMirror then child.linkedClass else ctx.owner)
168168
if (s.isEmpty) s
169-
else i"its child $child is not a generic sum because $s"
170-
} else i"its child $child is not a generic product because $s"
169+
else i"$self's child $child is not a generic sum because $s"
170+
} else i"$self's child $child is not a generic product because $s"
171171
}
172172
}
173-
if (children.isEmpty) "it does not have subclasses"
173+
if (children.isEmpty) i"$self does not have subclasses"
174174
else children.map(problem).find(!_.isEmpty).getOrElse("")
175175
}
176176

compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -266,24 +266,26 @@ class ImplicitSearchError(
266266
++ ErrorReporting.matchReductionAddendum(pt)
267267
}
268268

269-
private def formatMsg(shortForm: String)(headline: String = shortForm) = arg match {
269+
private def formatMsg(shortForm: String)(headline: String = shortForm) = arg match
270270
case arg: Trees.SearchFailureIdent[?] =>
271-
shortForm
271+
arg.tpe match
272+
case _: NoMatchingImplicits => headline
273+
case tpe: SearchFailureType =>
274+
i"$headline. ${tpe.explanation}"
275+
case _ => headline
272276
case _ =>
273-
arg.tpe match {
277+
arg.tpe match
274278
case tpe: SearchFailureType =>
275279
val original = arg match
276280
case Inlined(call, _, _) => call
277281
case _ => arg
278-
279282
i"""$headline.
280283
|I found:
281284
|
282285
| ${original.show.replace("\n", "\n ")}
283286
|
284287
|But ${tpe.explanation}."""
285-
}
286-
}
288+
case _ => headline
287289

288290
private def userDefinedErrorString(raw: String, paramNames: List[String], args: List[Type]): String = {
289291
def translate(name: String): Option[String] = {
@@ -307,12 +309,10 @@ class ImplicitSearchError(
307309
private def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where"
308310

309311
private def defaultAmbiguousImplicitMsg(ambi: AmbiguousImplicits) =
310-
formatMsg(s"ambiguous given instances: ${ambi.explanation}${location("of")}")(
311-
s"ambiguous given instances of type ${pt.show} found${location("for")}"
312-
)
312+
s"Ambiguous given instances: ${ambi.explanation}${location("of")}"
313313

314314
private def defaultImplicitNotFoundMessage =
315-
ex"no given instance of type $pt was found${location("for")}"
315+
ex"No given instance of type $pt was found${location("for")}"
316316

317317
/** Construct a custom error message given an ambiguous implicit
318318
* candidate `alt` and a user defined message `raw`.

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,18 @@ object Implicits:
549549
override def msg(using Context) = _msg
550550
def explanation(using Context) = msg.toString
551551

552+
/** A search failure type for failed synthesis of terms for special types */
553+
class SynthesisFailure(reasons: List[String], val expectedType: Type) extends SearchFailureType:
554+
def argument = EmptyTree
555+
556+
private def formatReasons =
557+
if reasons.length > 1 then
558+
reasons.mkString("\n\t* ", "\n\t* ", "")
559+
else
560+
reasons.mkString
561+
562+
def explanation(using Context) = em"Failed to synthesize implicit of type ${clarify(expectedType)}: ${formatReasons}"
563+
552564
end Implicits
553565

554566
import Implicits._
@@ -854,7 +866,12 @@ trait Implicits:
854866
if fail.isAmbiguous then failed
855867
else
856868
if synthesizer == null then synthesizer = Synthesizer(this)
857-
synthesizer.uncheckedNN.tryAll(formal, span).orElse(failed)
869+
val (tree, errors) = synthesizer.uncheckedNN.tryAll(formal, span)
870+
if errors.nonEmpty then
871+
SearchFailure(new SynthesisFailure(errors, formal), span).tree
872+
else
873+
tree.orElse(failed)
874+
858875

859876
/** Search an implicit argument and report error if not found */
860877
def implicitArgTree(formal: Type, span: Span)(using Context): Tree = {

0 commit comments

Comments
 (0)