aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/typer/Implicits.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-05-06 12:30:55 +0200
committerMartin Odersky <odersky@gmail.com>2016-05-23 16:11:45 +0200
commitcd8bf2d69cf1463fa16a69badb2a839f540bb2fa (patch)
tree4662148486993086b3f488cd5e41cc7219e5ff5b /src/dotty/tools/dotc/typer/Implicits.scala
parent3676baa4b1422f4ee46098aafc1ccd98f176bad4 (diff)
downloaddotty-cd8bf2d69cf1463fa16a69badb2a839f540bb2fa.tar.gz
dotty-cd8bf2d69cf1463fa16a69badb2a839f540bb2fa.tar.bz2
dotty-cd8bf2d69cf1463fa16a69badb2a839f540bb2fa.zip
Hooks to check that comparisons with == / != make sense
Also, check that pattern matching against idents/selects/literals makes sense. The hooks perform an implicit search for an instance of `Eq[L, R]`, where `L`, `R` are the argument types. So far this always succeeeds because Eq.eqAny matches all such types. A separate commit will check the returned search term for validity.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Implicits.scala')
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index 940170ceb..ff8e607ed 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -23,6 +23,8 @@ import Constants._
import Applications._
import ProtoTypes._
import ErrorReporting._
+import Inferencing.fullyDefinedType
+import Trees._
import Hashable._
import config.Config
import config.Printers._
@@ -415,6 +417,68 @@ trait Implicits { self: Typer =>
}
}
+ /** Find an implicit argument for parameter `formal`.
+ * @param error An error handler that gets an error message parameter
+ * which is itself parameterized by another string,
+ * indicating where the implicit parameter is needed
+ */
+ def inferImplicitArg(formal: Type, error: (String => String) => Unit, pos: Position)(implicit ctx: Context): Tree =
+ inferImplicit(formal, EmptyTree, pos) match {
+ case SearchSuccess(arg, _, _) =>
+ arg
+ case ambi: AmbiguousImplicits =>
+ error(where => s"ambiguous implicits: ${ambi.explanation} of $where")
+ EmptyTree
+ case failure: SearchFailure =>
+ val arg = synthesizedClassTag(formal, pos)
+ if (!arg.isEmpty) arg
+ else {
+ var msgFn = (where: String) =>
+ d"no implicit argument of type $formal found for $where" + failure.postscript
+ for {
+ notFound <- formal.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot)
+ Trees.Literal(Constant(raw: String)) <- notFound.argument(0)
+ } {
+ msgFn = where =>
+ err.implicitNotFoundString(
+ raw,
+ formal.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
+ formal.argInfos)
+ }
+ error(msgFn)
+ EmptyTree
+ }
+ }
+
+ /** If `formal` is of the form ClassTag[T], where `T` is a class type,
+ * synthesize a class tag for `T`.
+ */
+ def synthesizedClassTag(formal: Type, pos: Position)(implicit ctx: Context): Tree = {
+ if (formal.isRef(defn.ClassTagClass))
+ formal.argTypes match {
+ case arg :: Nil =>
+ val tp = fullyDefinedType(arg, "ClassTag argument", pos)
+ tp.underlyingClassRef(refinementOK = false) match {
+ case tref: TypeRef =>
+ return ref(defn.ClassTagModule)
+ .select(nme.apply)
+ .appliedToType(tp)
+ .appliedTo(clsOf(tref))
+ .withPos(pos)
+ case _ =>
+ }
+ case _ =>
+ }
+ EmptyTree
+ }
+
+ def checkCanEqual(ltp: Type, rtp: Type, pos: Position)(implicit ctx: Context): Unit =
+ if (!ctx.isAfterTyper && !ltp.isError && !rtp.isError)
+ inferImplicitArg(
+ defn.EqType.appliedTo(ltp, rtp),
+ _ => d"Values of types $ltp and $rtp cannot be compared with == or !=",
+ pos)
+
/** Find an implicit parameter or conversion.
* @param pt The expected type of the parameter or conversion.
* @param argument If an implicit conversion is searched, the argument to which