diff options
author | Martin Odersky <odersky@gmail.com> | 2016-05-06 12:30:55 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-05-23 16:11:45 +0200 |
commit | cd8bf2d69cf1463fa16a69badb2a839f540bb2fa (patch) | |
tree | 4662148486993086b3f488cd5e41cc7219e5ff5b /src/dotty/tools/dotc/typer/Implicits.scala | |
parent | 3676baa4b1422f4ee46098aafc1ccd98f176bad4 (diff) | |
download | dotty-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.scala | 64 |
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 |