Skip to content

Commit 78e036b

Browse files
oderskysmarter
authored andcommitted
Handle import aliases of implicit definitions
This makes scala#2405 work again.
1 parent 9e65352 commit 78e036b

File tree

5 files changed

+64
-14
lines changed

5 files changed

+64
-14
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ object Contexts {
201201
def implicits: ContextualImplicits = {
202202
if (implicitsCache == null )
203203
implicitsCache = {
204-
val implicitRefs: List[TermRef] =
204+
val implicitRefs: List[ImplicitDef] =
205205
if (isClassDefContext)
206206
try owner.thisType.implicitMembers
207207
catch {

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1969,7 +1969,16 @@ object Types {
19691969
override def eql(that: Type) = this eq that // safe because named types are hash-consed separately
19701970
}
19711971

1972-
abstract case class TermRef(override val prefix: Type, var designator: Designator) extends NamedType with SingletonType {
1972+
/** A reference to an implicit definition. This can be either a TermRef or a
1973+
* Implicits.RenamedImplicitDef.
1974+
*/
1975+
trait ImplicitDef {
1976+
def implicitName(implicit ctx: Context): TermName
1977+
def implicitRef: TermRef
1978+
}
1979+
1980+
abstract case class TermRef(override val prefix: Type, var designator: Designator)
1981+
extends NamedType with SingletonType with ImplicitDef {
19731982

19741983
type ThisType = TermRef
19751984
type ThisName = TermName
@@ -1987,6 +1996,9 @@ object Types {
19871996

19881997
def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] =
19891998
denot.altsWith(p).map(withDenot(_))
1999+
2000+
def implicitName(implicit ctx: Context): TermName = name
2001+
def implicitRef = this
19902002
}
19912003

19922004
abstract case class TypeRef(override val prefix: Type, var designator: Designator) extends NamedType {

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,20 @@ object Implicits {
4545
*/
4646
val DelayedImplicit = new Property.Key[TermRef]
4747

48+
/** An implicit definition `implicitRef` that is visible under a different name, `alias`.
49+
* Gets generated if an implicit ref is imported via a renaming import.
50+
*/
51+
class RenamedImplicitDef(val implicitRef: TermRef, val alias: TermName) extends ImplicitDef {
52+
def implicitName(implicit ctx: Context): TermName = alias
53+
}
54+
4855
/** An eligible implicit candidate, consisting of an implicit reference and a nesting level */
49-
case class Candidate(ref: TermRef, level: Int)
56+
case class Candidate(implicitDef: ImplicitDef, level: Int) {
57+
def ref: TermRef = implicitDef.implicitRef
58+
}
5059

5160
/** A common base class of contextual implicits and of-type implicits which
52-
* represents a set of implicit references.
61+
* represents a set of references to implicit definitions.
5362
*/
5463
abstract class ImplicitRefs(initctx: Context) {
5564
implicit val ctx: Context =
@@ -59,7 +68,7 @@ object Implicits {
5968
def level: Int = 0
6069

6170
/** The implicit references */
62-
def refs: List[TermRef]
71+
def refs: List[ImplicitDef]
6372

6473
/** Return those references in `refs` that are compatible with type `pt`. */
6574
protected def filterMatching(pt: Type)(implicit ctx: Context): List[Candidate] = track("filterMatching") {
@@ -138,7 +147,7 @@ object Implicits {
138147
else {
139148
val nestedCtx = ctx.fresh.addMode(Mode.TypevarsMissContext)
140149
refs
141-
.filter(ref => nestedCtx.typerState.test(refMatches(ref)(nestedCtx)))
150+
.filter(ref => nestedCtx.typerState.test(refMatches(ref.implicitRef)(nestedCtx)))
142151
.map(Candidate(_, level))
143152
}
144153
}
@@ -150,7 +159,7 @@ object Implicits {
150159
*/
151160
class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) {
152161
assert(initctx.typer != null)
153-
lazy val refs: List[TermRef] = {
162+
lazy val refs: List[ImplicitDef] = {
154163
val buf = new mutable.ListBuffer[TermRef]
155164
for (companion <- companionRefs) buf ++= companion.implicitMembers
156165
buf.toList
@@ -176,7 +185,7 @@ object Implicits {
176185
* name, b, whereas the name of the symbol is the original name, a.
177186
* @param outerCtx the next outer context that makes visible further implicits
178187
*/
179-
class ContextualImplicits(val refs: List[TermRef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) {
188+
class ContextualImplicits(val refs: List[ImplicitDef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) {
180189
private val eligibleCache = new mutable.AnyRefMap[Type, List[Candidate]]
181190

182191
/** The level increases if current context has a different owner or scope than
@@ -188,7 +197,7 @@ object Implicits {
188197
else if (ctx.scala2Mode ||
189198
(ctx.owner eq outerImplicits.ctx.owner) &&
190199
(ctx.scope eq outerImplicits.ctx.scope) &&
191-
!refs.head.name.is(LazyImplicitName)) outerImplicits.level
200+
!refs.head.implicitName.is(LazyImplicitName)) outerImplicits.level
192201
else outerImplicits.level + 1
193202

194203
/** Is this the outermost implicits? This is the case if it either the implicits
@@ -231,8 +240,8 @@ object Implicits {
231240
val ownEligible = filterMatching(tp)
232241
if (isOuterMost) ownEligible
233242
else ownEligible ::: {
234-
val shadowed = ownEligible.map(_.ref.name).toSet
235-
outerImplicits.eligible(tp).filterNot(cand => shadowed.contains(cand.ref.name))
243+
val shadowed = ownEligible.map(_.ref.implicitName).toSet
244+
outerImplicits.eligible(tp).filterNot(cand => shadowed.contains(cand.ref.implicitName))
236245
}
237246
}
238247

@@ -818,7 +827,7 @@ trait Implicits { self: Typer =>
818827
pt)
819828
val generated1 = adapt(generated, pt)
820829
lazy val shadowing =
821-
typed(untpd.Ident(ref.name) withPos pos.toSynthetic, funProto)(
830+
typed(untpd.Ident(cand.implicitDef.implicitName) withPos pos.toSynthetic, funProto)(
822831
nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState())
823832
def refSameAs(shadowing: Tree): Boolean =
824833
ref.symbol == closureBody(shadowing).symbol || {

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import printing.{Printer, Showable}
99
import util.SimpleIdentityMap
1010
import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._
1111
import Decorators.StringInterpolators
12+
import Implicits.RenamedImplicitDef
1213

1314
object ImportInfo {
1415
/** The import info for a root import from given symbol `sym` */
@@ -92,7 +93,7 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree],
9293
}
9394

9495
/** The implicit references imported by this import clause */
95-
def importedImplicits(implicit ctx: Context): List[TermRef] = {
96+
def importedImplicits(implicit ctx: Context): List[ImplicitDef] = {
9697
val pre = site
9798
if (isWildcardImport) {
9899
val refs = pre.implicitMembers
@@ -102,7 +103,12 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree],
102103
for {
103104
renamed <- reverseMapping.keys
104105
denot <- pre.member(reverseMapping(renamed)).altsWith(_ is Implicit)
105-
} yield TermRef(pre, renamed, denot)
106+
} yield {
107+
val original = reverseMapping(renamed)
108+
val ref = TermRef(pre, original, denot)
109+
if (renamed == original) ref
110+
else new RenamedImplicitDef(ref, renamed)
111+
}
106112
}
107113

108114
/** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden.

tests/pos/t2405.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
object A { implicit val x: Int = 1 }
2+
3+
// Problem as stated in the ticket.
4+
object Test1 {
5+
import A.{x => y}
6+
implicitly[Int]
7+
}
8+
9+
// Testing for the absense of shadowing #1.
10+
object Test2 {
11+
import A.{x => y}
12+
val x = 2
13+
implicitly[Int]
14+
}
15+
16+
// Testing for the absense of shadowing #2.
17+
object Test3 {
18+
{
19+
import A.{x => y}
20+
def x: Int = 0
21+
implicitly[Int]
22+
}
23+
}

0 commit comments

Comments
 (0)