Skip to content

Commit beb62b1

Browse files
committed
Added import implicit to import definitions into the implicit scope only.
1 parent a455861 commit beb62b1

File tree

6 files changed

+92
-9
lines changed

6 files changed

+92
-9
lines changed

src/compiler/scala/tools/nsc/ast/parser/Parsers.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,12 +2453,14 @@ self =>
24532453

24542454

24552455
/** {{{
2456-
* Import ::= import ImportExpr {`,' ImportExpr}
2456+
* Import ::= import [implicit] ImportExpr {`,' ImportExpr}
24572457
* }}}
24582458
*/
24592459
def importClause(): List[Tree] = {
24602460
val offset = accept(IMPORT)
2461-
commaSeparated(importExpr()) match {
2461+
val implicitMod = in.token == IMPLICIT
2462+
if(implicitMod) in.nextToken
2463+
commaSeparated(importExpr(implicitMod)) match {
24622464
case Nil => Nil
24632465
case t :: rest =>
24642466
// The first import should start at the position of the keyword.
@@ -2471,7 +2473,7 @@ self =>
24712473
* ImportExpr ::= StableId `.' (Id | `_' | ImportSelectors)
24722474
* }}}
24732475
*/
2474-
def importExpr(): Tree = {
2476+
def importExpr(implicitMod: Boolean): Tree = {
24752477
val start = in.offset
24762478
def thisDotted(name: TypeName) = {
24772479
in.nextToken()
@@ -2502,7 +2504,9 @@ self =>
25022504
else List(makeImportSelector(name, nameOffset))
25032505
}
25042506
// reaching here means we're done walking.
2505-
atPos(start)(Import(expr, selectors))
2507+
val tree = Import(expr, selectors)
2508+
if(implicitMod) tree updateAttachment ImplicitImport
2509+
atPos(start)(tree)
25062510
}
25072511

25082512
loop(in.token match {

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ trait Contexts { self: Analyzer =>
3535
override def implicitss: List[List[ImplicitInfo]] = Nil
3636
override def imports: List[ImportInfo] = Nil
3737
override def firstImport: Option[ImportInfo] = None
38+
override def implicitImports: List[ImportInfo] = Nil
3839
override def toString = "NoContext"
3940
}
4041
private object RootImports {
@@ -236,6 +237,7 @@ trait Contexts { self: Analyzer =>
236237

237238
/** The currently visible imports */
238239
def imports: List[ImportInfo] = outer.imports
240+
def implicitImports: List[ImportInfo] = outer.implicitImports
239241
/** Equivalent to `imports.headOption`, but more efficient */
240242
def firstImport: Option[ImportInfo] = outer.firstImport
241243
def isRootImport: Boolean = false
@@ -472,9 +474,12 @@ trait Contexts { self: Analyzer =>
472474
else prefix
473475

474476
// The blank canvas
475-
val c = if (isImport)
476-
new Context(tree, owner, scope, unit, this, reporter) with ImportContext
477-
else
477+
val c = if (isImport) {
478+
if(tree.hasAttachment[ImplicitImport.type])
479+
new Context(tree, owner, scope, unit, this, reporter) with ImplicitImportContext
480+
else
481+
new Context(tree, owner, scope, unit, this, reporter) with ImportContext
482+
} else
478483
new Context(tree, owner, scope, unit, this, reporter)
479484

480485
// Fields that are directly propagated
@@ -1260,6 +1265,13 @@ trait Contexts { self: Analyzer =>
12601265
override final def toString = s"${super.toString} with ImportContext { $impInfo; outer.owner = ${outer.owner} }"
12611266
}
12621267

1268+
trait ImplicitImportContext extends Context {
1269+
private val impInfo: ImportInfo = new ImportInfo(tree.asInstanceOf[Import], outerDepth)
1270+
1271+
override final def implicitImports = impInfo :: super.implicitImports
1272+
override final def toString = super.toString + " with " + s"ImplicitImportContext { $impInfo; outer.owner = ${outer.owner} }"
1273+
}
1274+
12631275
/** A reporter for use during type checking. It has multiple modes for handling errors.
12641276
*
12651277
* The default (immediate mode) is to send the error to the global reporter.

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,8 +1432,20 @@ trait Implicits {
14321432

14331433
// `materializeImplicit` does some preprocessing for `pt`
14341434
// is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`?
1435-
if (result.isFailure && !wasAmbiguous)
1436-
result = searchImplicit(implicitsOfExpectedType, isLocalToCallsite = false)
1435+
if (result.isFailure && !wasAmbiguous) {
1436+
val implicitScope =
1437+
if(context.implicitImports.isEmpty) implicitsOfExpectedType
1438+
else {
1439+
val importedInfos = context.implicitImports.flatMap { imp =>
1440+
imp.allImportedSymbols.filter(_.isImplicit).map { sym =>
1441+
new ImplicitInfo(sym.name, imp.qual.tpe, sym)
1442+
}
1443+
}
1444+
importedInfos :: implicitsOfExpectedType
1445+
}
1446+
1447+
result = searchImplicit(implicitScope, isLocalToCallsite = false)
1448+
}
14371449

14381450
if (result.isFailure)
14391451
context.reporter ++= previousErrs

src/reflect/scala/reflect/internal/StdAttachments.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,6 @@ trait StdAttachments {
100100
case object KnownDirectSubclassesCalled extends PlainAttachment
101101

102102
class QualTypeSymAttachment(val sym: Symbol)
103+
104+
case object ImplicitImport extends PlainAttachment
103105
}

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
5050
this.UseInvokeSpecial
5151
this.TypeParamVarargsAttachment
5252
this.KnownDirectSubclassesCalled
53+
this.ImplicitImport
5354
this.noPrint
5455
this.typeDebug
5556
this.Range
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
class Show[T](val i: Int)
2+
object Show extends Show0 {
3+
def apply[T](i: Int): Show[T] = new Show[T](i)
4+
5+
implicit val show0: Show[Int] = Show[Int](0)
6+
}
7+
8+
trait Show0 {
9+
// currently this generates an ambiguity with showGen ... we need to
10+
// tweak the specificity rules so that showGen is preferred to show1.
11+
//implicit def show1[T]: Show[T] = Show[T](1)
12+
}
13+
14+
class Foo[T]
15+
object Foo {
16+
implicit def showFoo[T](implicit st: Show[T]): Show[Foo[T]] = new Show[Foo[T]](2)
17+
}
18+
19+
class Bar[T]
20+
object Bar {
21+
implicit def barFoo[T]: Bar[Foo[T]] = new Bar[Foo[T]]
22+
implicit def barOption[T]: Bar[Option[T]] = new Bar[Option[T]]
23+
}
24+
25+
object DerivedShow {
26+
implicit def showGen[T](implicit bar: Bar[T]): Show[T] = new Show[T](3)
27+
}
28+
29+
object Test extends App {
30+
def check[T](i: Int)(implicit show: Show[T]): Unit = assert(show.i == i)
31+
32+
check[Int](0)
33+
//check[String](1)
34+
check[Foo[Int]](2)
35+
//check[Option[Int]](1)
36+
37+
{
38+
import DerivedShow._
39+
check[Int](0)
40+
//check[String](1)
41+
check[Foo[Int]](3) // Would like 2
42+
check[Option[Int]](3)
43+
}
44+
45+
{
46+
import implicit DerivedShow._
47+
check[Int](0)
48+
//check[String](1)
49+
check[Foo[Int]](2)
50+
check[Option[Int]](3) // Would like 3
51+
}
52+
}

0 commit comments

Comments
 (0)