diff options
author | Martin Odersky <odersky@gmail.com> | 2014-01-16 18:20:39 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-01-16 18:20:39 +0100 |
commit | e3bc2e9abc9e1749de2cf4ab899d4cb31594869e (patch) | |
tree | 115f62c2d174479d191204001fe59e4a80e0ecbb | |
parent | ef09dd258e91bd83100edae267ffa656461d7bc5 (diff) | |
download | dotty-e3bc2e9abc9e1749de2cf4ab899d4cb31594869e.tar.gz dotty-e3bc2e9abc9e1749de2cf4ab899d4cb31594869e.tar.bz2 dotty-e3bc2e9abc9e1749de2cf4ab899d4cb31594869e.zip |
Generalize implicit scope of ThisType
The implicit scope of a ThisType is now always the implicit scope of the self type. This caused cycles which necessitated cycle detectors in namedParts and computeImplicitScope.
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 38 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 37 |
2 files changed, 45 insertions, 30 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 4e961ecd9..b3d33e358 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2325,22 +2325,28 @@ object Types { class NamedPartsAccumulator(p: NamedType => Boolean)(implicit ctx: Context) extends TypeAccumulator[mutable.Set[NamedType]] { def maybeAdd(x: mutable.Set[NamedType], tp: NamedType) = if (p(tp)) x += tp else x - def apply(x: mutable.Set[NamedType], tp: Type): mutable.Set[NamedType] = tp match { - case tp: TermRef => - apply(foldOver(maybeAdd(x, tp), tp), tp.underlying) - case tp: TypeRef => - foldOver(maybeAdd(x, tp), tp) - case tp: ThisType => - apply(x, if (tp.cls is Module) tp.underlying else tp.cls.typeRef) - case tp: ConstantType => - apply(x, tp.underlying) - case tp: MethodParam => - apply(x, tp.underlying) - case tp: PolyParam => - apply(x, tp.underlying) - case _ => - foldOver(x, tp) - } + val seen: mutable.Set[Type] = mutable.Set() + def apply(x: mutable.Set[NamedType], tp: Type): mutable.Set[NamedType] = + if (seen contains tp) x + else { + seen += tp + tp match { + case tp: TermRef => + apply(foldOver(maybeAdd(x, tp), tp), tp.underlying) + case tp: TypeRef => + foldOver(maybeAdd(x, tp), tp) + case tp: ThisType => + apply(x, tp.underlying) + case tp: ConstantType => + apply(x, tp.underlying) + case tp: MethodParam => + apply(x, tp.underlying) + case tp: PolyParam => + apply(x, tp.underlying) + case _ => + foldOver(x, tp) + } + } } // ----- Name Filters -------------------------------------------------- diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 2c3914800..5ab40d529 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -182,6 +182,8 @@ trait ImplicitRunInfo { self: RunInfo => */ def implicitScope(tp: Type, liftingCtx: Context): OfTypeImplicits = { + val seen: mutable.Set[Type] = mutable.Set() + /** Replace every typeref that does not refer to a class by a conjunction of class types * that has the same implicit scope as the original typeref. The motivation for applying * this map is that it reduces the total number of types for which we need to @@ -204,21 +206,28 @@ trait ImplicitRunInfo { self: RunInfo => } } + def iscopeRefs(tp: Type): TermRefSet = + if (seen contains tp) EmptyTermRefSet + else { + seen += tp + iscope(tp).companionRefs + } + // todo: compute implicits directly, without going via companionRefs? - def computeImplicitScope(tp: Type): OfTypeImplicits = track("computeImplicicScope") { - ctx.traceIndented(implicits, i"computeImplicitScope($tp)") { + def collectCompanions(tp: Type): TermRefSet = track("computeImplicicScope") { + ctx.traceIndented(implicits, i"collectCompanions($tp)") { val comps = new TermRefSet tp match { case tp: NamedType => val pre = tp.prefix - comps ++= iscope(pre).companionRefs + comps ++= iscopeRefs(pre) def addClassScope(cls: ClassSymbol): Unit = { def addRef(companion: TermRef): Unit = comps += companion.asSeenFrom(pre, companion.symbol.owner).asInstanceOf[TermRef] def addParentScope(parent: TypeRef): Unit = { - iscope(parent).companionRefs foreach addRef + iscopeRefs(parent) foreach addRef for (param <- parent.typeParams) - comps ++= iscope(pre.member(param.name).info).companionRefs + comps ++= iscopeRefs(pre.member(param.name).info) } val companion = cls.companionModule if (companion.exists) addRef(companion.valRef) @@ -227,24 +236,24 @@ trait ImplicitRunInfo { self: RunInfo => tp.classSymbols(liftingCtx) foreach addClassScope case _ => for (part <- tp.namedPartsWith(_.isType)) - comps ++= iscope(part).companionRefs + comps ++= iscopeRefs(part) } - new OfTypeImplicits(tp, comps)(ctx) + comps } } - /** The implicit scope of type `tp` + def ofTypeImplicits(comps: TermRefSet) = new OfTypeImplicits(tp, comps)(ctx) + + /** The implicit scope of type `tp` * @param isLifted Type `tp` is the result of a `liftToClasses` application */ def iscope(tp: Type, isLifted: Boolean = false): OfTypeImplicits = - if (tp.hash == NotCached || !Config.cacheImplicitScopes) computeImplicitScope(tp) + if (tp.hash == NotCached || !Config.cacheImplicitScopes) + ofTypeImplicits(collectCompanions(tp)) else implicitScopeCache.getOrElseUpdate(tp, { val liftedTp = if (isLifted) tp else liftToClasses(tp) - if (liftedTp ne tp) { - val liftedImplicits = iscope(liftedTp, isLifted = true) - new OfTypeImplicits(tp, liftedImplicits.companionRefs)(ctx) - } - else computeImplicitScope(tp) + if (liftedTp ne tp) iscope(liftedTp, isLifted = true) + else ofTypeImplicits(collectCompanions(tp)) }) iscope(tp) |