Skip to content

Commit d2a2198

Browse files
rochaladwijnand
authored andcommitted
add missing renamed method shadowing, remove empty imports
1 parent f61adcd commit d2a2198

File tree

2 files changed

+72
-18
lines changed

2 files changed

+72
-18
lines changed

compiler/src/dotty/tools/repl/transform/CollectTopLevelImports.scala

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import dotty.tools.dotc.ast.untpd
55
import dotty.tools.dotc.core.Contexts._
66
import dotty.tools.dotc.core.Names.Name
77
import dotty.tools.dotc.core.Phases.Phase
8-
import dotty.tools.dotc.core.StdNames.ScalaTermNames
8+
import dotty.tools.dotc.core.StdNames.nme
99

1010

1111
/** This phase collects and transforms top-level Import trees to handle definition shadowing.
@@ -15,7 +15,7 @@ import dotty.tools.dotc.core.StdNames.ScalaTermNames
1515
*
1616
* Import transformation is necessary for excluding its members when they are shadowed in the same run.
1717
* This is done by finding all members defined after the Import clause calculating
18-
* their intersection with available members from selectors
18+
* their intersection with available members from selectors including renaming.
1919
*
2020
* This step is necessary for proper new run initialization since we need to import the previous run
2121
* into Context. It is accomplished in the following order:
@@ -40,23 +40,39 @@ class CollectTopLevelImports extends Phase {
4040
/** Transforms top-level imports to exclude intersecting members declared after the Import clause.
4141
* To properly handle imports such as: `import A.f; def f = 3` consequently making sure that original selectors are
4242
* filtered to eliminate potential duplications that would result in compilation error.
43+
*
44+
* Transformed imports of which selectors were all shadowed will be ignored in the future runs.
4345
*/
4446
private def transformTopLevelImports(trees: List[Tree])(using Context): List[Import] =
4547
val definitions = collectTopLevelMemberDefs(trees)
4648

4749
trees.collect {
4850
case tree @ Import(expr, selectors) =>
4951
val definitionsAfterImport = definitions.filter(_._2 > tree.endPos.end).map(_._1)
50-
val membersIntersection = expr.tpe.allMembers.map(_.name).intersect(definitionsAfterImport)
5152

52-
val transformedSelectors = membersIntersection.map(collidingMember => {
53-
untpd.ImportSelector(untpd.Ident(collidingMember), untpd.Ident(CollectTopLevelImports.nme.WILDCARD))
54-
}).toList
55-
56-
val filteredSelectors = selectors.filterNot(importSelector => membersIntersection.contains(importSelector.imported.name))
57-
58-
Import(expr, transformedSelectors.toList ::: filteredSelectors)
59-
}
53+
val importedNames: List[Name] = (if selectors.exists(_.isWildcard) then
54+
val allImportTypeMembers = expr.tpe.allMembers.map(_.name)
55+
val nonWildcardSelectors = selectors.filter(_.isWildcard)
56+
val renamedMembers = nonWildcardSelectors.map(_.imported.name)
57+
nonWildcardSelectors.map(_.rename) ++ allImportTypeMembers.filterNot(renamedMembers.contains)
58+
else
59+
selectors.map(_.rename)
60+
)
61+
62+
val shadowedMembers = importedNames.intersect(definitionsAfterImport)
63+
val adjustedSelectors = shadowedMembers.map(collidingMember => {
64+
untpd.ImportSelector(untpd.Ident(collidingMember), untpd.Ident(nme.WILDCARD))
65+
})
66+
67+
val remainingSelectors = selectors.filterNot(importSelector => {
68+
shadowedMembers.contains(importSelector.rename)
69+
})
70+
71+
if remainingSelectors.isEmpty then
72+
None
73+
else
74+
Some(Import(expr, adjustedSelectors ++ remainingSelectors))
75+
}.flatten
6076

6177
private def collectTopLevelMemberDefs(trees: List[Tree])(using Context): List[(Name, Int)] =
6278
trees.collect {
@@ -67,7 +83,3 @@ class CollectTopLevelImports extends Phase {
6783

6884
}
6985

70-
object CollectTopLevelImports {
71-
private lazy val nme: ScalaTermNames = new ScalaTermNames
72-
}
73-

compiler/test-resources/repl/import-shadowing

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
scala> object A { def f = 1 }
1+
scala> object A { def f = 1; def t = 2 }
22
// defined object A
33

44
scala> object B { def f = 2 }
@@ -32,12 +32,12 @@ def f: Int
3232
scala> val x4 = f
3333
val x4: Int = 5
3434

35-
scala> def f = 6; println(f); import A._; println(f); // import shadowing should only work on toplevel definitions in next runs
35+
scala> def f = 6; println(f); import A._; println(f); // import shadowing should only work on toplevel definitions in the following runs
3636
6
3737
6
3838
def f: Int
3939

40-
scala> import A._; println(f); def f = 7; println(f)
40+
scala> import A._; println(f); def f = 7; println(f) // import shadowing should only work on toplevel definitions in the following runs
4141
7
4242
7
4343
def f: Int
@@ -53,3 +53,45 @@ def f: Int
5353

5454
scala> val x6 = f
5555
val x6: Int = 9
56+
57+
scala> import A.{f => ff}; def f = 10
58+
def f: Int
59+
60+
scala> val x7 = f
61+
val x7: Int = 10
62+
63+
scala> val x8 = ff
64+
val x8: Int = 1
65+
66+
scala> def f = 10; import A.{f => ff}
67+
def f: Int
68+
69+
scala> val x9 = f
70+
val x9: Int = 10
71+
72+
scala> val x10 = ff
73+
val x10: Int = 1
74+
75+
scala> import A.{t, _}; def f = 11
76+
def f: Int
77+
78+
scala> val x11 = f
79+
val x11: Int = 11
80+
81+
scala> def f = 12; import A.{t, _}
82+
def f: Int
83+
84+
scala> val x12 = f
85+
val x12: Int = 1
86+
87+
scala> def f = 13; import A.{t => f}
88+
def f: Int
89+
90+
scala> val x13 = f
91+
val x13: Int = 2
92+
93+
scala> import A.{t => f}; def f = 14
94+
def f: Int
95+
96+
scala> val x14 = f
97+
val x14: Int = 14

0 commit comments

Comments
 (0)