Skip to content

Commit 20c0a6a

Browse files
committed
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.)
1 parent c683f1c commit 20c0a6a

File tree

6 files changed

+39
-14
lines changed

6 files changed

+39
-14
lines changed

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,13 @@ object Contexts {
164164
else if (isImportContext) importInfo.importedImplicits
165165
else if (isNonEmptyScopeContext) scope.implicitDecls
166166
else Nil
167-
if (implicitRefs.isEmpty && !(isImportContext && importInfo.isRootImport))
168-
outer.implicits // record root imports because they hide implicits in same import further out
169-
else
170-
new ContextualImplicits(implicitRefs, outer.implicits)(this)
167+
val outerImplicits =
168+
if (isImportContext && importInfo.hiddenRoot.exists)
169+
outer.implicits exclude importInfo.hiddenRoot
170+
else
171+
outer.implicits
172+
if (implicitRefs.isEmpty) outerImplicits
173+
else new ContextualImplicits(implicitRefs, outerImplicits)(this)
171174
}
172175
implicitsCache
173176
}

src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ object Implicits {
141141
case Some(eligibles) =>
142142
def elided(ci: ContextualImplicits): Int = {
143143
val n = ci.refs.length
144-
if (ci.outerImplicits == null) n
144+
if (ci.outerImplicits == NoContext.implicits) n
145145
else n + elided(ci.outerImplicits)
146146
}
147147
if (monitored) record(s"elided eligible refs", elided(this))
@@ -156,7 +156,7 @@ object Implicits {
156156
private def computeEligible(tp: Type): List[TermRef] = /*>|>*/ ctx.traceIndented(i"computeEligible $tp in $refs%, %", implicitsDetailed) /*<|<*/ {
157157
if (monitored) record(s"check eligible refs in ctx", refs.length)
158158
val ownEligible = filterMatching(tp)
159-
if (outerImplicits == null) ownEligible
159+
if (outerImplicits == NoContext.implicits) ownEligible
160160
else ownEligible ::: {
161161
val shadowed = (ownEligible map (_.name)).toSet
162162
outerImplicits.eligible(tp) filterNot (ref => shadowed contains ref.name)
@@ -165,8 +165,20 @@ object Implicits {
165165

166166
override def toString = {
167167
val own = s"(implicits: ${refs mkString ","})"
168-
if (outerImplicits == null) own else own + "\n " + outerImplicits
168+
if (outerImplicits == NoContext.implicits) own else own + "\n " + outerImplicits
169169
}
170+
171+
/** This context, or a copy, ensuring root import from symbol `root`
172+
* is not present in outer implicits.
173+
*/
174+
def exclude(root: Symbol): ContextualImplicits =
175+
if (this == NoContext.implicits) this
176+
else {
177+
val outerExcluded = outerImplicits exclude root
178+
if (ctx.importInfo.site.termSymbol == root) outerExcluded
179+
else if (outerExcluded eq outerImplicits) this
180+
else new ContextualImplicits(refs, outerExcluded)(ctx)
181+
}
170182
}
171183

172184
/** The result of an implicit search */

src/dotty/tools/dotc/typer/ImportInfo.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ class ImportInfo(val sym: Symbol, val selectors: List[untpd.Tree], val isRootImp
8989
} yield TermRef.withSig(pre, renamed, denot.signature, denot)
9090
}
9191

92+
/** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden.
93+
* Note: this computation needs to work even for un-initialized import infos, and
94+
* is not allowed to force initialization.
95+
*/
96+
lazy val hiddenRoot: Symbol = {
97+
val sym = site.termSymbol
98+
def hasMaskingSelector = selectors exists {
99+
case Pair(_, Ident(nme.WILDCARD)) => true
100+
case _ => false
101+
}
102+
if ((defn.RootImports contains sym) && hasMaskingSelector) sym else NoSymbol
103+
}
104+
92105
override def toString = {
93106
val siteStr = site.show
94107
val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,8 @@ class Typer extends Namer with Applications with Implicits {
185185
* import in the same program?
186186
*/
187187
def isDisabled(imp: ImportInfo, site: Type): Boolean = {
188-
val qualSym = site.termSymbol
189-
if (defn.RootImports contains qualSym) {
190-
if (imp.isRootImport && (importedFromRoot contains qualSym)) return true
191-
importedFromRoot += qualSym
192-
}
188+
if (imp.isRootImport && (importedFromRoot contains site.termSymbol)) return true
189+
if (imp.hiddenRoot.exists) importedFromRoot += imp.hiddenRoot
193190
false
194191
}
195192

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class tests extends CompilerTest {
4343
@Test def neg_typedidents() = compileFile(negDir, "typedidents", xerrors = 2)
4444
@Test def neg_assignments() = compileFile(negDir, "assignments", xerrors = 3)
4545
@Test def neg_typers() = compileFile(negDir, "typers", xerrors = 10)
46-
//@Test def neg_rootImports = compileFile(negDir, "rootImplicits", xerrors = 2)
46+
@Test def neg_rootImports = compileFile(negDir, "rootImplicits", xerrors = 2)
4747

4848
@Test def dotc = compileDir(dotcDir + "tools/dotc")
4949
@Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast")

tests/neg/rootImplicits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package test
22

33
import dotty._
4-
import Predef.{any2stringadd => _, _}
4+
import Predef.{any2stringadd => _, StringAdd => _, _}
55

66
object rootImplicits {
77

0 commit comments

Comments
 (0)