Skip to content

Commit d747c45

Browse files
oderskymichelou
authored andcommitted
Detect clashes involving renamed exports
Fixes scala#14818
1 parent 3af9fe5 commit d747c45

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,11 +1072,23 @@ class Namer { typer: Typer =>
10721072
/** The forwarders defined by export `exp` */
10731073
private def exportForwarders(exp: Export)(using Context): List[tpd.MemberDef] =
10741074
val buf = new mutable.ListBuffer[tpd.MemberDef]
1075-
val Export(expr, selectors) = exp
1075+
val Export(expr, selectors0) = exp
10761076
if expr.isEmpty then
10771077
report.error(em"Export selector must have prefix and `.`", exp.srcPos)
10781078
return Nil
10791079

1080+
val renamed = mutable.Set[Name]()
1081+
val selectors = selectors0 map {
1082+
case sel @ ImportSelector(imported, id @ Ident(alias), bound) if alias != nme.WILDCARD =>
1083+
if renamed.contains(alias) then
1084+
report.error(i"duplicate rename target", id.srcPos)
1085+
cpy.ImportSelector(sel)(imported, EmptyTree, bound).asInstanceOf[ImportSelector]
1086+
else
1087+
renamed += alias
1088+
sel
1089+
case sel => sel
1090+
}
1091+
10801092
val path = typedAheadExpr(expr, AnySelectionProto)
10811093
checkLegalExportPath(path, selectors)
10821094
lazy val wildcardBound = importBound(selectors, isGiven = false)
@@ -1091,6 +1103,8 @@ class Namer { typer: Typer =>
10911103
Skip
10921104
else if cls.derivesFrom(sym.owner) && (sym.owner == cls || !sym.is(Deferred)) then
10931105
No(i"is already a member of $cls")
1106+
else if renamed.contains(sym.name.toTermName) then
1107+
No(i"clashes with a renamed export")
10941108
else if sym.is(Override) then
10951109
sym.allOverriddenSymbols.find(
10961110
other => cls.derivesFrom(other.owner) && !other.is(Deferred)

tests/neg/i14818.check

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- Error: tests/neg/i14818.scala:9:12 ----------------------------------------------------------------------------------
2+
9 | export M.{A, B as A} // error
3+
| ^
4+
| no eligible member A at M
5+
| M.A cannot be exported because it clashes with a renamed export
6+
-- [E050] Type Error: tests/neg/i14818.scala:16:10 ---------------------------------------------------------------------
7+
16 | val x = b(1) // error
8+
| ^
9+
| method b in object T3 does not take parameters
10+
|
11+
| longer explanation available when compiling with `-explain`
12+
-- Error: tests/neg/i14818.scala:19:25 ---------------------------------------------------------------------------------
13+
19 | export M.{A as C, B as C} // error
14+
| ^
15+
| duplicate rename target

tests/neg/i14818.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object M {
2+
type A
3+
type B
4+
def a = 1
5+
def b(x: Int) = x
6+
}
7+
8+
object T1:
9+
export M.{A, B as A} // error
10+
11+
object T2:
12+
export M.{A as B, *}
13+
14+
object T3:
15+
export M.{a as b, *}
16+
val x = b(1) // error
17+
18+
object T4:
19+
export M.{A as C, B as C} // error
20+

0 commit comments

Comments
 (0)