aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-11-29 18:35:15 +0100
committerMartin Odersky <odersky@gmail.com>2013-11-29 18:35:15 +0100
commiteb6eb2cded84f0e0240f4b706c1ed41459946db2 (patch)
tree856e852838e4b7f8d0cba707abf07f40361265ad /src
parent0581e8bac449ac720bd666e7f7fdb010d810a3cd (diff)
downloaddotty-eb6eb2cded84f0e0240f4b706c1ed41459946db2.tar.gz
dotty-eb6eb2cded84f0e0240f4b706c1ed41459946db2.tar.bz2
dotty-eb6eb2cded84f0e0240f4b706c1ed41459946db2.zip
Tweaking Implicits
Still to do: catch cycles.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala78
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala4
2 files changed, 40 insertions, 42 deletions
diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala
index dbe86d3c9..5f9f49453 100644
--- a/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/src/dotty/tools/dotc/typer/Implicits.scala
@@ -28,13 +28,12 @@ import collection.mutable
/** Implicit resolution */
object Implicits {
- private def disableImplicits(ctx: Context): Context =
- if (ctx == NoContext) ctx else ctx retractMode Mode.ImplicitsEnabled
-
/** A common base class of contextual implicits and of-type implicits which
* represents as set of implicit references.
*/
- abstract class ImplicitRefs extends Compatibility {
+ abstract class ImplicitRefs(initctx: Context) extends Compatibility {
+ implicit val ctx: Context =
+ if (initctx == NoContext) initctx else initctx retractMode Mode.ImplicitsEnabled
/** The implicit references */
def refs: List[TermRef]
@@ -42,7 +41,7 @@ object Implicits {
/** Return those references in `refs` that are compatible with type `pt`. */
protected def filterMatching(pt: Type)(implicit ctx: Context): List[TermRef] = track("filterMatching") {
def refMatches(ref: TermRef)(implicit ctx: Context) = isCompatible(normalize(ref), pt)
- refs filter (ref => refMatches(ref)(ctx.fresh.withExploreTyperState)) // create a defensive copy of ctx to avoid constraint pollution
+ refs filter (refMatches(_)(ctx.fresh.withExploreTyperState)) // create a defensive copy of ctx to avoid constraint pollution
}
/** No further implicit conversions can be applied when searching for implicits. */
@@ -53,10 +52,13 @@ object Implicits {
* @param tp the type determining the implicit scope
* @param companionRefs the companion objects in the implicit scope.
*/
- class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs {
+ class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) {
assert(initctx.typer != null)
- implicit val ctx: Context = disableImplicits(initctx)
- val refs: List[TermRef] = companionRefs.toList flatMap (_.implicitMembers)
+ val refs: List[TermRef] = {
+ val buf = new mutable.ListBuffer[TermRef]
+ for (companion <- companionRefs) buf ++= companion.implicitMembers
+ buf.toList
+ }
/** The implicit references that are eligible for expected type `tp` */
lazy val eligible: List[TermRef] = ctx.traceIndented(i"eligible($tp)", show = true)(filterMatching(tp))
@@ -72,10 +74,8 @@ object Implicits {
* name, b, whereas the name of the symbol is the original name, a.
* @param outerCtx the next outer context that makes visible further implicits
*/
- class ContextualImplicits(val refs: List[TermRef], val outerCtx: Context)(initctx: Context) extends ImplicitRefs {
- implicit val ctx: Context = disableImplicits(initctx)
-
- private val eligibleCache = new mutable.HashMap[Type, List[TermRef]]
+ class ContextualImplicits(val refs: List[TermRef], val outerCtx: Context)(initctx: Context) extends ImplicitRefs(initctx) {
+ private val eligibleCache = new mutable.LinkedHashMap[Type, List[TermRef]]
/** The implicit references that are eligible for type `tp`. */
def eligible(tp: Type): List[TermRef] =
@@ -87,7 +87,7 @@ object Implicits {
if (outerCtx == NoContext) ownEligible
else ownEligible ::: {
val shadowed = (ownEligible map (_.name)).toSet
- outerCtx.implicits.eligible(tp).filter(ref => !(shadowed contains ref.name))
+ outerCtx.implicits.eligible(tp) filterNot (ref => shadowed contains ref.name)
}
}
@@ -105,7 +105,7 @@ object Implicits {
* @param tree The typed tree that can needs to be inserted
* @param ctx The context after the implicit search
*/
- case class SearchSuccess(tree: tpd.Tree)(val ref: TermRef, val tstate: TyperState) extends SearchResult
+ case class SearchSuccess(tree: tpd.Tree, ref: TermRef, tstate: TyperState) extends SearchResult
/** A failed search */
abstract class SearchFailure extends SearchResult {
@@ -184,7 +184,7 @@ trait ImplicitRunInfo { self: RunInfo =>
}
}
- // todo: compute implicits directly, without going via companionRefs
+ // todo: compute implicits directly, without going via companionRefs?
private def computeImplicitScope(tp: Type): OfTypeImplicits = track("computeImplicicScope") {
val comps = new TermRefSet
tp match {
@@ -192,10 +192,8 @@ trait ImplicitRunInfo { self: RunInfo =>
val pre = tp.prefix
comps ++= implicitScope(pre).companionRefs
def addClassScope(cls: ClassSymbol): Unit = {
- def addRef(companion: TermRef): Unit = {
- val comp1 @ TermRef(_, _) = companion.asSeenFrom(pre, companion.symbol.owner)
- comps += comp1
- }
+ def addRef(companion: TermRef): Unit =
+ comps += companion.asSeenFrom(pre, companion.symbol.owner).asInstanceOf[TermRef]
def addParentScope(parent: TypeRef): Unit = {
implicitScope(parent).companionRefs foreach addRef
for (param <- parent.typeParams)
@@ -247,7 +245,7 @@ trait Implicits { self: Typer =>
/** Find an implicit conversion to apply to given tree `from` so that the
* result is compatible with type `to`.
*/
- def inferView(from: tpd.Tree, to: Type)(implicit ctx: Context): SearchResult = track("inferView") {
+ def inferView(from: Tree, to: Type)(implicit ctx: Context): SearchResult = track("inferView") {
inferImplicit(to, from, from.pos)
}
@@ -256,6 +254,7 @@ trait Implicits { self: Typer =>
* @param argument If an implicit conversion is searched, the argument to which
* it should be applied, EmptyTree otherwise.
* @param pos The position where errors should be reported.
+ * !!! todo: catch potential cycles
*/
def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") {
ctx.traceIndented(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", show = true) {
@@ -281,14 +280,22 @@ trait Implicits { self: Typer =>
case _ =>
}
- val initctx: Context = disableImplicits(ctx.fresh.withNewTyperState)
- def nestedContext = initctx.fresh.withNewTyperState
+ private def nestedContext = ctx.fresh.withNewMode(ctx.mode &~ Mode.ImplicitsEnabled)
+
+ private def implicitProto(resultType: Type) =
+ if (argument.isEmpty) resultType else ViewProto(argument.tpe, resultType)
+
+ /** The expected type for the searched implicit */
+ lazy val fullProto = implicitProto(pt)
+ /** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
+ val wildProto = implicitProto((new WildApprox) apply pt)
+
+ /** Search failures; overridden in ExplainedImplicitSearch */
protected def nonMatchingImplicit(ref: TermRef): SearchFailure = NoImplicitMatches
protected def shadowedImplicit(ref: TermRef, shadowing: Type): SearchFailure = NoImplicitMatches
protected def failedSearch: SearchFailure = NoImplicitMatches
-
/** Search a list of eligible implicit references */
def searchImplicits(eligible: List[TermRef], contextual: Boolean): SearchResult = {
@@ -301,20 +308,20 @@ trait Implicits { self: Typer =>
pt)
val generated1 = adapt(generated, pt)
lazy val shadowing =
- typed(untpd.Ident(ref.name) withPos pos.toSynthetic, ref)(nestedContext).tpe
+ typed(untpd.Ident(ref.name) withPos pos.toSynthetic, fullProto)(nestedContext.withNewTyperState).tpe
if (ctx.typerState.reporter.hasErrors) nonMatchingImplicit(ref)
else if (contextual && !(shadowing =:= ref)) shadowedImplicit(ref, shadowing)
- else SearchSuccess(generated)(ref, ctx.typerState)
+ else SearchSuccess(generated, ref, ctx.typerState)
}}
/** Given a list of implicit references, produce a list of all implicit search successes,
* where the first is supposed to be the best one.
- * @param pending The list of implicit references
+ * @param pending The list of implicit references that remain to be investigated
* @param acc An accumulator of successful matches found so far.
*/
def rankImplicits(pending: List[TermRef], acc: List[SearchSuccess]): List[SearchSuccess] = pending match {
case ref :: pending1 =>
- typedImplicit(ref)(nestedContext) match {
+ typedImplicit(ref)(nestedContext.withNewTyperState) match {
case fail: SearchFailure =>
rankImplicits(pending1, acc)
case best: SearchSuccess =>
@@ -357,22 +364,13 @@ trait Implicits { self: Typer =>
condense(rankImplicits(sort(eligible), Nil))
}
- /** The expected type where parameters and uninstantiated typevars
- * are replaced by wildcard types
- */
- val wildPt: Type = {
- val result = (new WildApprox) apply pt
- if (argument.isEmpty) result
- else ViewProto(argument.tpe, result)
- }
-
/** Find a unique best implicit reference */
def bestImplicit: SearchResult = {
- searchImplicits(ctx.implicits.eligible(wildPt), contextual = true) match {
+ searchImplicits(ctx.implicits.eligible(wildProto), contextual = true) match {
case result: SearchSuccess => result
case result: AmbiguousImplicits => result
case result: SearchFailure =>
- searchImplicits(implicitScope(wildPt).eligible, contextual = false)
+ searchImplicits(implicitScope(wildProto).eligible, contextual = false)
}
}
@@ -392,8 +390,8 @@ trait Implicits { self: Typer =>
override def shadowedImplicit(ref: TermRef, shadowing: Type): SearchFailure =
record(new ShadowedImplicit(ref, shadowing, pt, argument))
override def failedSearch: SearchFailure = {
- //println(s"wildPt = $wildPt")
- //println(s"implicit scope = ${implicitScope(wildPt).companionRefs}")
+ //println(s"wildProto = $wildProto")
+ //println(s"implicit scope = ${implicitScope(wildProto).companionRefs}")
new FailedImplicit(failures, pt, argument)
}
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 5a953004a..f0d4d7493 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1034,7 +1034,7 @@ class Typer extends Namer with Applications with Implicits {
val args = (wtp.paramNames, wtp.paramTypes).zipped map { (pname, formal) =>
def where = i"parameter $pname of $methodStr"
inferImplicit(formal, EmptyTree, tree.pos.endPos) match {
- case SearchSuccess(arg) =>
+ case SearchSuccess(arg, _, _) =>
arg
case ambi: AmbiguousImplicits =>
implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where")
@@ -1084,7 +1084,7 @@ class Typer extends Namer with Applications with Implicits {
}
// try an implicit conversion
inferView(tree, pt) match {
- case SearchSuccess(adapted) =>
+ case SearchSuccess(adapted, _, _) =>
adapted
case failure: SearchFailure =>
if (pt.isInstanceOf[ProtoType]) tree