File tree 4 files changed +30
-4
lines changed 4 files changed +30
-4
lines changed Original file line number Diff line number Diff line change @@ -449,6 +449,8 @@ class Definitions {
449
449
def ContravariantBetweenAnnot (implicit ctx : Context ) = ContravariantBetweenAnnotType .symbol.asClass
450
450
lazy val DeprecatedAnnotType = ctx.requiredClassRef(" scala.deprecated" )
451
451
def DeprecatedAnnot (implicit ctx : Context ) = DeprecatedAnnotType .symbol.asClass
452
+ lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef(" scala.annotation.implicitNotFound" )
453
+ def ImplicitNotFoundAnnot (implicit ctx : Context ) = ImplicitNotFoundAnnotType .symbol.asClass
452
454
lazy val InvariantBetweenAnnotType = ctx.requiredClassRef(" dotty.annotation.internal.InvariantBetween" )
453
455
def InvariantBetweenAnnot (implicit ctx : Context ) = InvariantBetweenAnnotType .symbol.asClass
454
456
lazy val MigrationAnnotType = ctx.requiredClassRef(" scala.annotation.migration" )
Original file line number Diff line number Diff line change @@ -116,6 +116,18 @@ object ErrorReporting {
116
116
| found : $found
117
117
| required: $expected""" .stripMargin + whyNoMatchStr(found, expected)
118
118
}
119
+
120
+ /** Format `raw` implicitNotFound argument, replacing all
121
+ * occurrences of `${X}` where `X` is in `paramNames` with the
122
+ * corresponding shown type in `args`.
123
+ */
124
+ def implicitNotFoundString (raw : String , paramNames : List [String ], args : List [Type ]): String = {
125
+ def translate (name : String ): Option [String ] = {
126
+ val idx = paramNames.indexOf(name)
127
+ if (idx >= 0 ) Some (args(idx).show) else None
128
+ }
129
+ """ \$\{\w*\}""" .r.replaceSomeIn(raw, m => translate(m.matched.drop(2 ).init))
130
+ }
119
131
}
120
132
121
133
def err (implicit ctx : Context ): Errors = new Errors
Original file line number Diff line number Diff line change @@ -1541,7 +1541,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
1541
1541
case failure : SearchFailure =>
1542
1542
val arg = synthesizedClassTag(formal)
1543
1543
if (! arg.isEmpty) arg
1544
- else implicitArgError(d " no implicit argument of type $formal found for $where" + failure.postscript)
1544
+ else {
1545
+ var msg = d " no implicit argument of type $formal found for $where" + failure.postscript
1546
+ for (notFound <- formal.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot );
1547
+ Literal (Constant (raw : String )) <- notFound.argument(0 ))
1548
+ msg = err.implicitNotFoundString(
1549
+ raw,
1550
+ formal.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
1551
+ formal.argInfos)
1552
+ implicitArgError(msg)
1553
+ }
1545
1554
}
1546
1555
}
1547
1556
if (errors.nonEmpty) {
Original file line number Diff line number Diff line change 1
1
package strawman .equality
2
+ import annotation .implicitNotFound
2
3
3
4
object EqualityStrawman1 {
4
5
5
6
trait Eq [- T ]
6
- trait Impossible
7
+
8
+ @ implicitNotFound(" cannot compare value of type ${T} with a value outside its equality class" )
9
+ trait Impossible [T ]
7
10
8
11
object Eq extends Eq [Any ]
9
12
10
13
trait Base {
11
14
def === (other : Any ): Boolean = this .equals(other)
12
- def === (other : CondEquals )(implicit ce : Impossible ): Boolean = ???
15
+ def === [ T <: CondEquals ] (other : T )(implicit ce : Impossible [ T ] ): Boolean = ???
13
16
}
14
17
15
18
trait CondEquals extends Base {
16
19
def === [T >: this .type <: CondEquals ](other : T )(implicit ce : Eq [T ]): Boolean = this .equals(other)
17
- def === (other : Any )(implicit ce : Impossible ): Boolean = ???
20
+ def === [ T ] (other : T )(implicit ce : Impossible [ T ] ): Boolean = ???
18
21
}
19
22
20
23
trait Equals [- T ] extends CondEquals
You can’t perform that action at this time.
0 commit comments