Skip to content

Commit aa7e335

Browse files
author
Hao Xia
committed
Fix ImportHandler's reporting of importedNames and importedSymbols
1 parent c89d821 commit aa7e335

File tree

5 files changed

+102
-17
lines changed

5 files changed

+102
-17
lines changed

src/compiler/scala/tools/nsc/typechecker/Contexts.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,19 @@ trait Contexts { self: Analyzer =>
6464
for (imps <- allImportInfos.remove(unit)) {
6565
for (imp <- imps.reverse.distinct) {
6666
val used = allUsedSelectors(imp)
67-
def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD
6867

69-
imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel =>
68+
imp.tree.selectors filterNot (s => isMaskImport(s) || used(s)) foreach { sel =>
7069
reporter.warning(imp posOf sel, "Unused import")
7170
}
7271
}
7372
allUsedSelectors --= imps
7473
}
7574
}
7675

76+
def isMaskImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename == nme.WILDCARD
77+
def isIndividualImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename != nme.WILDCARD
78+
def isWildcardImport(s: ImportSelector): Boolean = s.name == nme.WILDCARD
79+
7780
var lastAccessCheckDetails: String = ""
7881

7982
/** List of symbols to import from in a root context. Typically that

src/repl/scala/tools/nsc/interpreter/ExprTyper.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ trait ExprTyper {
1313
import global.{ reporter => _, Import => _, _ }
1414
import naming.freshInternalVarName
1515

16+
private def doInterpret(code: String): IR.Result = {
17+
// interpret/interpretSynthetic may change the phase, which would have unintended effects on types.
18+
val savedPhase = phase
19+
try interpretSynthetic(code) finally phase = savedPhase
20+
}
21+
1622
def symbolOfLine(code: String): Symbol = {
1723
def asExpr(): Symbol = {
1824
val name = freshInternalVarName()
@@ -21,7 +27,7 @@ trait ExprTyper {
2127
// behind a def and strip the NullaryMethodType which wraps the expr.
2228
val line = "def " + name + " = " + code
2329

24-
interpretSynthetic(line) match {
30+
doInterpret(line) match {
2531
case IR.Success =>
2632
val sym0 = symbolOfTerm(name)
2733
// drop NullaryMethodType
@@ -32,7 +38,7 @@ trait ExprTyper {
3238
def asDefn(): Symbol = {
3339
val old = repl.definedSymbolList.toSet
3440

35-
interpretSynthetic(code) match {
41+
doInterpret(code) match {
3642
case IR.Success =>
3743
repl.definedSymbolList filterNot old match {
3844
case Nil => NoSymbol
@@ -43,7 +49,7 @@ trait ExprTyper {
4349
}
4450
}
4551
def asError(): Symbol = {
46-
interpretSynthetic(code)
52+
doInterpret(code)
4753
NoSymbol
4854
}
4955
beSilentDuring(asExpr()) orElse beSilentDuring(asDefn()) orElse asError()
@@ -72,7 +78,7 @@ trait ExprTyper {
7278
def asProperType(): Option[Type] = {
7379
val name = freshInternalVarName()
7480
val line = "def %s: %s = ???" format (name, typeString)
75-
interpretSynthetic(line) match {
81+
doInterpret(line) match {
7682
case IR.Success =>
7783
val sym0 = symbolOfTerm(name)
7884
Some(sym0.asMethod.returnType)

src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,29 +213,40 @@ trait MemberHandlers {
213213

214214
class ImportHandler(imp: Import) extends MemberHandler(imp) {
215215
val Import(expr, selectors) = imp
216+
216217
def targetType = intp.global.rootMirror.getModuleIfDefined("" + expr) match {
217218
case NoSymbol => intp.typeOfExpression("" + expr)
218-
case sym => sym.thisType
219+
case sym => sym.tpe
219220
}
220-
private def importableTargetMembers = importableMembers(targetType).toList
221-
// wildcard imports, e.g. import foo._
222-
private def selectorWild = selectors filter (_.name == nme.USCOREkw)
223-
// renamed imports, e.g. import foo.{ bar => baz }
224-
private def selectorRenames = selectors map (_.rename) filterNot (_ == null)
221+
222+
private def isFlattenedSymbol(sym: Symbol) =
223+
sym.owner.isPackageClass &&
224+
sym.name.containsName(nme.NAME_JOIN_STRING) &&
225+
sym.owner.info.member(sym.name.take(sym.name.indexOf(nme.NAME_JOIN_STRING))) != NoSymbol
226+
227+
private def importableTargetMembers =
228+
importableMembers(exitingTyper(targetType)).filterNot(isFlattenedSymbol).toList
229+
230+
// non-wildcard imports
231+
private def individualSelectors = selectors filter analyzer.isIndividualImport
225232

226233
/** Whether this import includes a wildcard import */
227-
val importsWildcard = selectorWild.nonEmpty
234+
val importsWildcard = selectors exists analyzer.isWildcardImport
228235

229236
def implicitSymbols = importedSymbols filter (_.isImplicit)
230237
def importedSymbols = individualSymbols ++ wildcardSymbols
231238

232-
private val selectorNames = selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames) toSet
233-
lazy val individualSymbols: List[Symbol] = exitingTyper(importableTargetMembers filter (m => selectorNames(m.name)))
234-
lazy val wildcardSymbols: List[Symbol] = exitingTyper(if (importsWildcard) importableTargetMembers else Nil)
239+
lazy val importableSymbolsWithRenames = {
240+
val selectorRenameMap = individualSelectors.flatMap(x => x.name.bothNames zip x.rename.bothNames).toMap
241+
importableTargetMembers flatMap (m => selectorRenameMap.get(m.name) map (m -> _))
242+
}
243+
244+
lazy val individualSymbols: List[Symbol] = importableSymbolsWithRenames map (_._1)
245+
lazy val wildcardSymbols: List[Symbol] = if (importsWildcard) importableTargetMembers else Nil
235246

236247
/** Complete list of names imported by a wildcard */
237248
lazy val wildcardNames: List[Name] = wildcardSymbols map (_.name)
238-
lazy val individualNames: List[Name] = individualSymbols map (_.name)
249+
lazy val individualNames: List[Name] = importableSymbolsWithRenames map (_._2)
239250

240251
/** The names imported by this statement */
241252
override lazy val importedNames: List[Name] = wildcardNames ++ individualNames

test/files/run/t9880-9881.check

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
scala> // import in various ways
3+
4+
scala> import java.util.Date
5+
import java.util.Date
6+
7+
scala> import scala.util._
8+
import scala.util._
9+
10+
scala> import scala.reflect.runtime.{universe => ru}
11+
import scala.reflect.runtime.{universe=>ru}
12+
13+
scala> import ru.TypeTag
14+
import ru.TypeTag
15+
16+
scala>
17+
18+
scala> // show the imports
19+
20+
scala> :imports
21+
1) import java.lang._ (...)
22+
2) import scala._ (...)
23+
3) import scala.Predef._ (...)
24+
4) import java.util.Date (...)
25+
5) import scala.util._ (...)
26+
6) import scala.reflect.runtime.{universe=>ru} (...)
27+
7) import ru.TypeTag (...)
28+
29+
scala>
30+
31+
scala> // should be able to define this class with the imports above
32+
33+
scala> class C[T](date: Date, rand: Random, typeTag: TypeTag[T])
34+
defined class C
35+
36+
scala> :quit

test/files/run/t9880-9881.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import scala.tools.partest.ReplTest
2+
import scala.tools.nsc.Settings
3+
4+
object Test extends ReplTest {
5+
6+
override def transformSettings(s: Settings): Settings = {
7+
s.Yreplclassbased.value = true
8+
s
9+
}
10+
11+
lazy val normalizeRegex = """(import\s.*)\(.*\)""".r
12+
13+
override def normalize(s: String): String = normalizeRegex.replaceFirstIn(s, "$1(...)")
14+
15+
def code =
16+
"""
17+
|// import in various ways
18+
|import java.util.Date
19+
|import scala.util._
20+
|import scala.reflect.runtime.{universe => ru}
21+
|import ru.TypeTag
22+
|
23+
|// show the imports
24+
|:imports
25+
|
26+
|// should be able to define this class with the imports above
27+
|class C[T](date: Date, rand: Random, typeTag: TypeTag[T])
28+
""".stripMargin
29+
}

0 commit comments

Comments
 (0)