Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for SI-9881 in branch 2.11.x #6195

Merged
merged 1 commit into from
Jun 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,19 @@ trait Contexts { self: Analyzer =>
for (imps <- allImportInfos.remove(unit)) {
for (imp <- imps.reverse.distinct) {
val used = allUsedSelectors(imp)
def isMask(s: ImportSelector) = s.name != nme.WILDCARD && s.rename == nme.WILDCARD

imp.tree.selectors filterNot (s => isMask(s) || used(s)) foreach { sel =>
imp.tree.selectors filterNot (s => isMaskImport(s) || used(s)) foreach { sel =>
reporter.warning(imp posOf sel, "Unused import")
}
}
allUsedSelectors --= imps
}
}

def isMaskImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename == nme.WILDCARD
def isIndividualImport(s: ImportSelector): Boolean = s.name != nme.WILDCARD && s.rename != nme.WILDCARD
def isWildcardImport(s: ImportSelector): Boolean = s.name == nme.WILDCARD

var lastAccessCheckDetails: String = ""

/** List of symbols to import from in a root context. Typically that
Expand Down
6 changes: 4 additions & 2 deletions src/reflect/scala/reflect/internal/Names.scala
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,13 @@ trait Names extends api.Names {
*/
final def pos(s: String, start: Int): Int = {
var i = pos(s.charAt(0), start)
while (i + s.length() <= len) {
val sLen = s.length()
if (sLen == 1) return i
while (i + sLen <= len) {
var j = 1
while (s.charAt(j) == chrs(index + i + j)) {
j += 1
if (j == s.length()) return i
if (j == sLen) return i
}
i = pos(s.charAt(0), i + 1)
}
Expand Down
14 changes: 10 additions & 4 deletions src/repl/scala/tools/nsc/interpreter/ExprTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ trait ExprTyper {
import global.{ reporter => _, Import => _, _ }
import naming.freshInternalVarName

private def doInterpret(code: String): IR.Result = {
// interpret/interpretSynthetic may change the phase, which would have unintended effects on types.
val savedPhase = phase
try interpretSynthetic(code) finally phase = savedPhase
}

def symbolOfLine(code: String): Symbol = {
def asExpr(): Symbol = {
val name = freshInternalVarName()
Expand All @@ -23,7 +29,7 @@ trait ExprTyper {
// behind a def and strip the NullaryMethodType which wraps the expr.
val line = "def " + name + " = " + code

interpretSynthetic(line) match {
doInterpret(line) match {
case IR.Success =>
val sym0 = symbolOfTerm(name)
// drop NullaryMethodType
Expand All @@ -34,7 +40,7 @@ trait ExprTyper {
def asDefn(): Symbol = {
val old = repl.definedSymbolList.toSet

interpretSynthetic(code) match {
doInterpret(code) match {
case IR.Success =>
repl.definedSymbolList filterNot old match {
case Nil => NoSymbol
Expand All @@ -45,7 +51,7 @@ trait ExprTyper {
}
}
def asError(): Symbol = {
interpretSynthetic(code)
doInterpret(code)
NoSymbol
}
beSilentDuring(asExpr()) orElse beSilentDuring(asDefn()) orElse asError()
Expand Down Expand Up @@ -74,7 +80,7 @@ trait ExprTyper {
def asProperType(): Option[Type] = {
val name = freshInternalVarName()
val line = "def %s: %s = ???" format (name, typeString)
interpretSynthetic(line) match {
doInterpret(line) match {
case IR.Success =>
val sym0 = symbolOfTerm(name)
Some(sym0.asMethod.returnType)
Expand Down
33 changes: 22 additions & 11 deletions src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -212,29 +212,40 @@ trait MemberHandlers {

class ImportHandler(imp: Import) extends MemberHandler(imp) {
val Import(expr, selectors) = imp

def targetType = intp.global.rootMirror.getModuleIfDefined("" + expr) match {
case NoSymbol => intp.typeOfExpression("" + expr)
case sym => sym.thisType
case sym => sym.tpe
}
private def importableTargetMembers = importableMembers(targetType).toList
// wildcard imports, e.g. import foo._
private def selectorWild = selectors filter (_.name == nme.USCOREkw)
// renamed imports, e.g. import foo.{ bar => baz }
private def selectorRenames = selectors map (_.rename) filterNot (_ == null)

private def isFlattenedSymbol(sym: Symbol) =
sym.owner.isPackageClass &&
sym.name.containsName(nme.NAME_JOIN_STRING) &&
sym.owner.info.member(sym.name.take(sym.name.indexOf(nme.NAME_JOIN_STRING))) != NoSymbol

private def importableTargetMembers =
importableMembers(exitingTyper(targetType)).filterNot(isFlattenedSymbol).toList

// non-wildcard imports
private def individualSelectors = selectors filter analyzer.isIndividualImport

/** Whether this import includes a wildcard import */
val importsWildcard = selectorWild.nonEmpty
val importsWildcard = selectors exists analyzer.isWildcardImport

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

private val selectorNames = selectorRenames filterNot (_ == nme.USCOREkw) flatMap (_.bothNames) toSet
lazy val individualSymbols: List[Symbol] = exitingTyper(importableTargetMembers filter (m => selectorNames(m.name)))
lazy val wildcardSymbols: List[Symbol] = exitingTyper(if (importsWildcard) importableTargetMembers else Nil)
lazy val importableSymbolsWithRenames = {
val selectorRenameMap = individualSelectors.flatMap(x => x.name.bothNames zip x.rename.bothNames).toMap
importableTargetMembers flatMap (m => selectorRenameMap.get(m.name) map (m -> _))
}

lazy val individualSymbols: List[Symbol] = importableSymbolsWithRenames map (_._1)
lazy val wildcardSymbols: List[Symbol] = if (importsWildcard) importableTargetMembers else Nil

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

/** The names imported by this statement */
override lazy val importedNames: List[Name] = wildcardNames ++ individualNames
Expand Down
36 changes: 36 additions & 0 deletions test/files/run/t9880-9881.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

scala> // import in various ways

scala> import java.util.Date
import java.util.Date

scala> import scala.util._
import scala.util._

scala> import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{universe=>ru}

scala> import ru.TypeTag
import ru.TypeTag

scala>

scala> // show the imports

scala> :imports
1) import java.lang._ (...)
2) import scala._ (...)
3) import scala.Predef._ (...)
4) import java.util.Date (...)
5) import scala.util._ (...)
6) import scala.reflect.runtime.{universe=>ru} (...)
7) import ru.TypeTag (...)

scala>

scala> // should be able to define this class with the imports above

scala> class C[T](date: Date, rand: Random, typeTag: TypeTag[T])
defined class C

scala> :quit
29 changes: 29 additions & 0 deletions test/files/run/t9880-9881.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import scala.tools.partest.ReplTest
import scala.tools.nsc.Settings

object Test extends ReplTest {

override def transformSettings(s: Settings): Settings = {
s.Yreplclassbased.value = true
s
}

lazy val normalizeRegex = """(import\s.*)\(.*\)""".r

override def normalize(s: String): String = normalizeRegex.replaceFirstIn(s, "$1(...)")

def code =
"""
|// import in various ways
|import java.util.Date
|import scala.util._
|import scala.reflect.runtime.{universe => ru}
|import ru.TypeTag
|
|// show the imports
|:imports
|
|// should be able to define this class with the imports above
|class C[T](date: Date, rand: Random, typeTag: TypeTag[T])
""".stripMargin
}
28 changes: 28 additions & 0 deletions test/junit/scala/reflect/internal/NamesTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,32 @@ class NamesTest {
assert(h1 string_== h2)
assert(h1 string_== h1y)
}

@Test
def pos(): Unit = {
def check(nameString: String, sub: String) = {
val name = TermName(nameString)
val javaResult = name.toString.indexOf(sub) match {
case -1 => name.length
case x => x
}
val nameResult = name.pos(sub)
assertEquals(javaResult, nameResult)
if (sub.length == 1) {
val nameResultChar = name.pos(sub.head)
assertEquals(javaResult, nameResultChar)
}
}

check("a", "a") // was "String index out of range: 1
check("a", "b")
check("a", "ab")
check("a", "ba")
check("ab", "a")
check("ab", "b")
check("ab", "ab")
check("ab", "ba")
check("", "x")
check("", "xy")
}
}