Skip to content

Commit cb89d50

Browse files
committed
Generalize addenda handling for typeMismatch errors
1 parent 553aa8a commit cb89d50

File tree

2 files changed

+24
-15
lines changed

2 files changed

+24
-15
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ object ErrorReporting {
7070
case _ => foldOver(s, tp)
7171
tps.foldLeft("")(collectMatchTrace)
7272

73+
/** A mixin trait that can produce added elements for an error message */
74+
trait Addenda:
75+
self =>
76+
def toAdd(using Context): List[String] = Nil
77+
def ++ (follow: Addenda) = new Addenda:
78+
override def toAdd(using Context) = self.toAdd ++ follow.toAdd
79+
80+
object NothingToAdd extends Addenda
81+
7382
class Errors(using Context) {
7483

7584
/** An explanatory note to be added to error messages
@@ -162,7 +171,7 @@ object ErrorReporting {
162171

163172
def patternConstrStr(tree: Tree): String = ???
164173

165-
def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailureType = NoMatchingImplicits): Tree = {
174+
def typeMismatch(tree: Tree, pt: Type, addenda: Addenda = NothingToAdd): Tree = {
166175
val normTp = normalize(tree.tpe, pt)
167176
val normPt = normalize(pt, pt)
168177

@@ -184,7 +193,7 @@ object ErrorReporting {
184193
"\nMaybe you are missing an else part for the conditional?"
185194
case _ => ""
186195

187-
errorTree(tree, TypeMismatch(treeTp, expectedTp, Some(tree), implicitFailure.whyNoConversion, missingElse))
196+
errorTree(tree, TypeMismatch(treeTp, expectedTp, Some(tree), (addenda.toAdd :+ missingElse)*))
188197
}
189198

190199
/** A subtype log explaining why `found` does not conform to `expected` */

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ object Implicits:
440440
}
441441
}
442442

443-
abstract class SearchFailureType extends ErrorType {
443+
abstract class SearchFailureType extends ErrorType, Addenda {
444444
def expectedType: Type
445445
def argument: Tree
446446

@@ -457,11 +457,6 @@ object Implicits:
457457
if (argument.isEmpty) i"match type ${clarify(expectedType)}"
458458
else i"convert from ${argument.tpe} to ${clarify(expectedType)}"
459459
}
460-
461-
/** If search was for an implicit conversion, a note describing the failure
462-
* in more detail - this is either empty or starts with a '\n'
463-
*/
464-
def whyNoConversion(using Context): String = ""
465460
}
466461

467462
class NoMatchingImplicits(val expectedType: Type, val argument: Tree, constraint: Constraint = OrderingConstraint.empty)
@@ -515,33 +510,38 @@ object Implicits:
515510

516511
/** A failure value indicating that an implicit search for a conversion was not tried */
517512
case class TooUnspecific(target: Type) extends NoMatchingImplicits(NoType, EmptyTree, OrderingConstraint.empty):
518-
override def whyNoConversion(using Context): String =
513+
514+
override def toAdd(using Context) =
519515
i"""
520516
|Note that implicit conversions were not tried because the result of an implicit conversion
521-
|must be more specific than $target"""
517+
|must be more specific than $target""" :: Nil
522518

523519
override def msg(using Context) =
524520
super.msg.append("\nThe expected type $target is not specific enough, so no search was attempted")
521+
525522
override def toString = s"TooUnspecific"
523+
end TooUnspecific
526524

527525
/** An ambiguous implicits failure */
528-
class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType {
526+
class AmbiguousImplicits(val alt1: SearchSuccess, val alt2: SearchSuccess, val expectedType: Type, val argument: Tree) extends SearchFailureType:
527+
529528
def msg(using Context): Message =
530529
var str1 = err.refStr(alt1.ref)
531530
var str2 = err.refStr(alt2.ref)
532531
if str1 == str2 then
533532
str1 = ctx.printer.toTextRef(alt1.ref).show
534533
str2 = ctx.printer.toTextRef(alt2.ref).show
535534
em"both $str1 and $str2 $qualify".withoutDisambiguation()
536-
override def whyNoConversion(using Context): String =
535+
536+
override def toAdd(using Context) =
537537
if !argument.isEmpty && argument.tpe.widen.isRef(defn.NothingClass) then
538-
""
538+
Nil
539539
else
540540
val what = if (expectedType.isInstanceOf[SelectionProto]) "extension methods" else "conversions"
541541
i"""
542542
|Note that implicit $what cannot be applied because they are ambiguous;
543-
|$explanation"""
544-
}
543+
|$explanation""" :: Nil
544+
end AmbiguousImplicits
545545

546546
class MismatchedImplicit(ref: TermRef,
547547
val expectedType: Type,

0 commit comments

Comments
 (0)