aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-02-02 17:09:33 +0100
committerMartin Odersky <odersky@gmail.com>2014-02-02 17:32:04 +0100
commit20c0a6a92dc2d618fa557bb19d78d8595ca527e6 (patch)
tree3fdbd3aac9bd22335ba5cb2b2fb0dc64577f4a72
parentc683f1c1d8235fffc4475e7b51ddc7536ec7eaa1 (diff)
downloaddotty-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.)
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala11
-rw-r--r--src/dotty/tools/dotc/typer/Implicits.scala18
-rw-r--r--src/dotty/tools/dotc/typer/ImportInfo.scala13
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala7
-rw-r--r--test/dotc/tests.scala2
-rw-r--r--tests/neg/rootImplicits.scala2
6 files changed, 39 insertions, 14 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
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 0b36fb810..c32492778 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -43,7 +43,7 @@ class tests extends CompilerTest {
@Test def neg_typedidents() = compileFile(negDir, "typedidents", xerrors = 2)
@Test def neg_assignments() = compileFile(negDir, "assignments", xerrors = 3)
@Test def neg_typers() = compileFile(negDir, "typers", xerrors = 10)
- //@Test def neg_rootImports = compileFile(negDir, "rootImplicits", xerrors = 2)
+ @Test def neg_rootImports = compileFile(negDir, "rootImplicits", xerrors = 2)
@Test def dotc = compileDir(dotcDir + "tools/dotc")
@Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast")
diff --git a/tests/neg/rootImplicits.scala b/tests/neg/rootImplicits.scala
index 4b833c503..f527333b5 100644
--- a/tests/neg/rootImplicits.scala
+++ b/tests/neg/rootImplicits.scala
@@ -1,7 +1,7 @@
package test
import dotty._
-import Predef.{any2stringadd => _, _}
+import Predef.{any2stringadd => _, StringAdd => _, _}
object rootImplicits {