diff options
author | Martin Odersky <odersky@gmail.com> | 2014-02-02 17:09:33 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-02-02 17:32:04 +0100 |
commit | 20c0a6a92dc2d618fa557bb19d78d8595ca527e6 (patch) | |
tree | 3fdbd3aac9bd22335ba5cb2b2fb0dc64577f4a72 /src/dotty/tools/dotc | |
parent | c683f1c1d8235fffc4475e7b51ddc7536ec7eaa1 (diff) | |
download | dotty-20c0a6a92dc2d618fa557bb19d78d8595ca527e6.tar.gz dotty-20c0a6a92dc2d618fa557bb19d78d8595ca527e6.tar.bz2 dotty-20c0a6a92dc2d618fa557bb19d78d8595ca527e6.zip |
Avoid accessing implicits that come from root imports that are hidden by some nested import.
This also changes the criterion when a root import is disabled.
A root import is now disabled if there is an inner import from the same package or module, and the inner import contains at least one disabling clause X => _. (The latter crierion is new; without it, we would consider something like
import scala.{collections => c}
as a hiding import for Scala, which seems to go too far.)
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Implicits.scala | 18 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ImportInfo.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 7 |
4 files changed, 37 insertions, 12 deletions
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index b12ed0226..d82826277 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -164,10 +164,13 @@ object Contexts { else if (isImportContext) importInfo.importedImplicits else if (isNonEmptyScopeContext) scope.implicitDecls else Nil - if (implicitRefs.isEmpty && !(isImportContext && importInfo.isRootImport)) - outer.implicits // record root imports because they hide implicits in same import further out - else - new ContextualImplicits(implicitRefs, outer.implicits)(this) + val outerImplicits = + if (isImportContext && importInfo.hiddenRoot.exists) + outer.implicits exclude importInfo.hiddenRoot + else + outer.implicits + if (implicitRefs.isEmpty) outerImplicits + else new ContextualImplicits(implicitRefs, outerImplicits)(this) } implicitsCache } diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 574db1a3d..2bd1731da 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -141,7 +141,7 @@ object Implicits { case Some(eligibles) => def elided(ci: ContextualImplicits): Int = { val n = ci.refs.length - if (ci.outerImplicits == null) n + if (ci.outerImplicits == NoContext.implicits) n else n + elided(ci.outerImplicits) } if (monitored) record(s"elided eligible refs", elided(this)) @@ -156,7 +156,7 @@ object Implicits { private def computeEligible(tp: Type): List[TermRef] = /*>|>*/ ctx.traceIndented(i"computeEligible $tp in $refs%, %", implicitsDetailed) /*<|<*/ { if (monitored) record(s"check eligible refs in ctx", refs.length) val ownEligible = filterMatching(tp) - if (outerImplicits == null) ownEligible + if (outerImplicits == NoContext.implicits) ownEligible else ownEligible ::: { val shadowed = (ownEligible map (_.name)).toSet outerImplicits.eligible(tp) filterNot (ref => shadowed contains ref.name) @@ -165,8 +165,20 @@ object Implicits { override def toString = { val own = s"(implicits: ${refs mkString ","})" - if (outerImplicits == null) own else own + "\n " + outerImplicits + if (outerImplicits == NoContext.implicits) own else own + "\n " + outerImplicits } + + /** This context, or a copy, ensuring root import from symbol `root` + * is not present in outer implicits. + */ + def exclude(root: Symbol): ContextualImplicits = + if (this == NoContext.implicits) this + else { + val outerExcluded = outerImplicits exclude root + if (ctx.importInfo.site.termSymbol == root) outerExcluded + else if (outerExcluded eq outerImplicits) this + else new ContextualImplicits(refs, outerExcluded)(ctx) + } } /** The result of an implicit search */ diff --git a/src/dotty/tools/dotc/typer/ImportInfo.scala b/src/dotty/tools/dotc/typer/ImportInfo.scala index d72e12baa..8c5f0c1e6 100644 --- a/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -89,6 +89,19 @@ class ImportInfo(val sym: Symbol, val selectors: List[untpd.Tree], val isRootImp } yield TermRef.withSig(pre, renamed, denot.signature, denot) } + /** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden. + * Note: this computation needs to work even for un-initialized import infos, and + * is not allowed to force initialization. + */ + lazy val hiddenRoot: Symbol = { + val sym = site.termSymbol + def hasMaskingSelector = selectors exists { + case Pair(_, Ident(nme.WILDCARD)) => true + case _ => false + } + if ((defn.RootImports contains sym) && hasMaskingSelector) sym else NoSymbol + } + override def toString = { val siteStr = site.show val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 9ae8252a1..aad03c47c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -185,11 +185,8 @@ class Typer extends Namer with Applications with Implicits { * import in the same program? */ def isDisabled(imp: ImportInfo, site: Type): Boolean = { - val qualSym = site.termSymbol - if (defn.RootImports contains qualSym) { - if (imp.isRootImport && (importedFromRoot contains qualSym)) return true - importedFromRoot += qualSym - } + if (imp.isRootImport && (importedFromRoot contains site.termSymbol)) return true + if (imp.hiddenRoot.exists) importedFromRoot += imp.hiddenRoot false } |