diff options
author | Martin Odersky <odersky@gmail.com> | 2013-08-23 16:21:27 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-08-23 16:21:27 +0200 |
commit | 873a3bc1a273974d7d47de054e68a92c29a359e8 (patch) | |
tree | 7e6b0fd2c308a855a05350bb4d12d9d2119f382a /src | |
parent | a8467b0a7cddeef7110155f9853ff84feb2281fa (diff) | |
download | dotty-873a3bc1a273974d7d47de054e68a92c29a359e8.tar.gz dotty-873a3bc1a273974d7d47de054e68a92c29a359e8.tar.bz2 dotty-873a3bc1a273974d7d47de054e68a92c29a359e8.zip |
Fixes in implicit handling
Plus a new test file: implicits1
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 49 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inferencing.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Mode.scala | 2 |
6 files changed, 49 insertions, 30 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 582853fdf..50d703a28 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -23,7 +23,7 @@ class Compiler { .withRunInfo(new RunInfo) .withOwner(defn.RootClass) .withTyper(new Typer) - .withMode(Mode.None) + .withMode(Mode.ImplicitsEnabled) .withTyperState(new MutableTyperState(ctx.typerState, new ConsoleReporter()(ctx))) def addImport(ctx: Context, sym: Symbol) = ctx.fresh.withImportInfo(ImportInfo.rootImport(sym)(ctx)) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 6bc932429..531df739e 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -163,7 +163,7 @@ object Contexts { else if (isNonEmptyScopeContext) scope.implicitDecls else Set() if (implicitRefs.isEmpty) outer.implicits - else new ContextualImplicits(implicitRefs, outer.implicits.ctx) + else new ContextualImplicits(implicitRefs, outer.implicits.ctx)(this) } implicitsCache } @@ -330,7 +330,7 @@ object Contexts { object NoContext extends Context { lazy val base = unsupported("base") - override def implicits: ContextualImplicits = new ContextualImplicits(Set(), this) + override def implicits: ContextualImplicits = new ContextualImplicits(Set(), this)(this) } /** A context base defines state and associated methods that exist once per diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 8af9e0b57..e5e8be05b 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -6,7 +6,7 @@ import core._ import ast.{Trees, untpd, tpd, TreeInfo} import util.Positions._ import Trees.Untyped -import Mode.ImplicitsDisabled +import Mode.ImplicitsEnabled import Contexts._ import Flags._ import Denotations._ @@ -629,6 +629,14 @@ trait Applications extends Compatibility { self: Typer => def isApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type = WildcardType)(implicit ctx: Context) = new ApplicableToTypes(methRef, args, resultType)(ctx.fresh.withNewTyperState).success + def isApplicableToTypes(tp: Type, args: List[Type], resultType: Type)(implicit ctx: Context): Boolean = tp match { + case methRef: TermRef => isApplicableToTypes(methRef, args, resultType) + case _ => + val app = tp.member(nme.apply) + app.exists && app.hasAltWith(d => + isApplicableToTypes(TermRef(tp, nme.apply).withDenot(d), args, resultType)) + } + /** Is `tp` a subtype of `pt`? */ def testCompatible(tp: Type, pt: Type)(implicit ctx: Context) = isCompatible(tp, pt)(ctx.fresh.withNewTyperState) @@ -788,6 +796,6 @@ trait Applications extends Compatibility { self: Typer => } if (isDetermined(candidates)) candidates - else narrowMostSpecific(candidates)(ctx.addMode(ImplicitsDisabled)) + else narrowMostSpecific(candidates)(ctx.retractMode(ImplicitsEnabled)) } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 3676cc214..2a92cf442 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -8,7 +8,7 @@ import util.Positions._ import Contexts._ import Types._ import Flags._ -import Mode.ImplicitsDisabled +import Mode.ImplicitsEnabled import Denotations._ import NameOps._ import SymDenotations._ @@ -45,8 +45,9 @@ 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: Set[TermRef])(implicit ctx: Context) - extends ImplicitRefs{ + class OfTypeImplicits(tp: Type, val companionRefs: Set[TermRef])(initctx: Context) + extends ImplicitRefs { + implicit val ctx: Context = initctx retractMode ImplicitsEnabled val refs: Set[TermRef] = companionRefs flatMap (_.implicitMembers) /** The implicit references that are eligible for expected type `tp` */ @@ -57,7 +58,10 @@ object Implicits { * @param refs the implicit references made visible by the current context * @param outerCtx the next outer context that makes visible further implicits */ - class ContextualImplicits(val refs: Set[TermRef], val outerCtx: Context)(implicit val ctx: Context) extends ImplicitRefs { + class ContextualImplicits(val refs: Set[TermRef], val outerCtx: Context)(initctx: Context) extends ImplicitRefs { + implicit val ctx: Context = + if (initctx == NoContext) initctx else initctx retractMode Mode.ImplicitsEnabled + private val eligibleCache = new mutable.HashMap[Type, List[TermRef]] /** The implicit references that are eligible for type `tp`. */ @@ -76,7 +80,7 @@ object Implicits { override def toString = { val own = s"(implicits: ${refs mkString ","})" - if (outerCtx == NoContext) own else own +"\n " + outerCtx.implicits + if (outerCtx == NoContext) own else own + "\n " + outerCtx.implicits } } @@ -144,7 +148,7 @@ trait ImplicitRunInfo { self: RunInfo => (implicitScope(pre).companionRefs /: tp.classSymbols)(addClassScope) case _ => tp.namedParts.flatMap(implicitScope(_).companionRefs) - }) + })(ctx) /** The implicit scope of a type * @param isLifted Type `tp` is the result of a `liftToClasses` application @@ -168,12 +172,11 @@ trait Implicits { self: Typer => import tpd._ - override def viewExists(from: Type, to: Type)(implicit ctx: Context): Boolean = !( - from.isError - || to.isError - || (ctx.mode is Mode.ImplicitsDisabled) - || (inferView(dummyTreeOfType(from), to) eq EmptyTree) - ) + override def viewExists(from: Type, to: Type)(implicit ctx: Context): Boolean = ( + !from.isError + && !to.isError + && (ctx.mode is Mode.ImplicitsEnabled) + && (inferView(dummyTreeOfType(from), to) ne EmptyTree)) /** Find an implicit conversion to apply to given tree `from` so that the * result is compatible with type `to`. @@ -210,15 +213,13 @@ trait Implicits { self: Typer => /** An implicit search; parameters as in `inferImplicit` */ class ImplicitSearch(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context) { - println(s"implicit search in ${ctx.owner} scope ${ctx.implicits}") - /** Try to typecheck an implicit reference */ def typedImplicit(ref: TermRef)(implicit ctx: Context): SearchResult = { val id = Ident(ref).withPos(pos) val tree = if (argument.isEmpty) adapt(id, pt) else typedApply(id, ref, argument :: Nil, pt) - if (tree.tpe.isError) NoImplicitMatches // todo: replace by checking if local errors were reported in ctx. + if (tree.tpe.isError) NoImplicitMatches // todo: replace by checking if local errors were reported in ctx. else SearchSuccess(ref, tree, ctx.typerState) } @@ -229,7 +230,7 @@ trait Implicits { self: Typer => */ private def rankImplicits(pending: List[TermRef], acc: List[SearchSuccess]): List[SearchSuccess] = pending match { case ref :: pending1 => - typedImplicit(ref)(ctx.fresh.withNewTyperState.addMode(ImplicitsDisabled)) match { + typedImplicit(ref)(ctx.fresh.withNewTyperState.retractMode(ImplicitsEnabled)) match { case fail: SearchFailure => rankImplicits(pending1, acc) case best @ SearchSuccess(bestRef, _, _) => @@ -273,15 +274,19 @@ trait Implicits { self: Typer => /** The expected type where parameters and uninstantiated typevars * are replaced by wildcard types */ - val wildPt: Type = (new WildApprox) apply pt + 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)) match { - case result: SearchSuccess => result - case result: AmbiguousImplicits => result - case NoImplicitMatches => searchImplicits(implicitScope(wildPt).eligible) - } + searchImplicits(ctx.implicits.eligible(wildPt)) match { + case result: SearchSuccess => result + case result: AmbiguousImplicits => result + case NoImplicitMatches => searchImplicits(implicitScope(wildPt).eligible) + } } def implicitScope(tp: Type): OfTypeImplicits = ctx.runInfo.implicitScope(tp) diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index efaa48554..46dd9b0ad 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -63,8 +63,8 @@ object Inferencing { case class FunProto(args: List[untpd.Tree], override val resultType: Type, typer: Typer)(implicit ctx: Context) extends UncachedGroundType with ProtoType { private var myTypedArgs: List[Tree] = null - def isMatchedBy(tp: Type)(implicit ctx: Context) = - ctx.typer.isApplicableToTrees(tp, typedArgs, resultType) + def isMatchedBy(tp: Type)(implicit ctx: Context) = + typer.isApplicableToTrees(tp, typedArgs, resultType) def argsAreTyped: Boolean = myTypedArgs != null @@ -75,6 +75,12 @@ object Inferencing { } } + case class ViewProto(argType: Type, override val resultType: Type)(implicit ctx: Context) extends CachedGroundType with ProtoType { + def isMatchedBy(tp: Type)(implicit ctx: Context) = + ctx.typer.isApplicableToTypes(tp, argType :: Nil, resultType) + override def computeHash = doHash(argType, resultType) + } + case class PolyProto(nargs: Int, override val resultType: Type) extends UncachedGroundType /** The normalized form of a type diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala index 88bb3d4d8..1890822b6 100644 --- a/src/dotty/tools/dotc/typer/Mode.scala +++ b/src/dotty/tools/dotc/typer/Mode.scala @@ -29,7 +29,7 @@ object Mode { val Pattern = newMode(0, "Pattern") val Type = newMode(1, "Type") - val ImplicitsDisabled = newMode(2, "ImplicitsDisabled") + val ImplicitsEnabled = newMode(2, "ImplicitsEnabled") val InSuperInit = newMode(3, "InSuperInit") val PatternOrType = Pattern | Type |