Skip to content

Commit 98f0a63

Browse files
committed
Add tests for error conditions
1 parent 9af2ec5 commit 98f0a63

File tree

5 files changed

+88
-6
lines changed

5 files changed

+88
-6
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,7 @@ class Namer { typer: Typer =>
11131113
else if sym.isAllOf(JavaModule) then
11141114
Skip
11151115
else if pathMethod.exists && mbr.isType then
1116-
No("cannot be exported as extension method")
1116+
No("is a type, so it cannot be exported as extension method")
11171117
else
11181118
Yes
11191119
}
@@ -1306,7 +1306,8 @@ class Namer { typer: Typer =>
13061306
process(stats1)(using ctx.importContext(stat, symbolOfTree(stat)))
13071307
case (stat: ExtMethods) :: stats1 =>
13081308
for case exp: Export <- stat.methods do
1309-
processExport(exp, exportPathSym(exp.expr, stat))
1309+
val pathSym = exportPathSym(exp.expr, stat)
1310+
if pathSym.exists then processExport(exp, pathSym)
13101311
process(stats1)
13111312
case stat :: stats1 =>
13121313
process(stats1)

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,10 +2584,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25842584
val selectors1 = typedSelectors(imp.selectors)
25852585
assignType(cpy.Import(imp)(expr1, selectors1), sym)
25862586

2587-
def typedExport(exp: untpd.Export)(using Context): Export =
2588-
val expr1 = exp.expr.removeAttachment(TypedAhead).getOrElse(EmptyTree)
2589-
val selectors1 = typedSelectors(exp.selectors)
2590-
assignType(cpy.Export(exp)(expr1, selectors1))
2587+
def typedExport(exp: untpd.Export)(using Context): Tree =
2588+
exp.expr.removeAttachment(TypedAhead) match
2589+
case Some(expr1) =>
2590+
val selectors1 = typedSelectors(exp.selectors)
2591+
assignType(cpy.Export(exp)(expr1, selectors1))
2592+
case _ =>
2593+
errorTree(exp, em"exports are only allowed from objects and classes")
25912594

25922595
def typedPackageDef(tree: untpd.PackageDef)(using Context): Tree =
25932596
val pid1 = withMode(Mode.InPackageClauseName)(typedExpr(tree.pid, AnySelectionProto))

tests/neg/export-in-extension.check

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
-- Error: tests/neg/export-in-extension.scala:14:13 --------------------------------------------------------------------
2+
14 | export c1.* // error
3+
| ^^
4+
| export qualifier c1 is not a parameterless companion extension method
5+
-- Error: tests/neg/export-in-extension.scala:19:22 --------------------------------------------------------------------
6+
19 | export cm.{bar, D} // error
7+
| ^
8+
| no eligible member D at O.O2.cm
9+
| O.O2.cm.D cannot be exported because it is a type, so it cannot be exported as extension method
10+
-- Error: tests/neg/export-in-extension.scala:20:18 --------------------------------------------------------------------
11+
20 | export this.cm.baz // error
12+
| ^^^^^^^
13+
| export qualifier must be a simple reference to a companion extension method
14+
-- Error: tests/neg/export-in-extension.scala:24:13 --------------------------------------------------------------------
15+
24 | export missing.* // error
16+
| ^^^^^^^
17+
| export qualifier missing is not a parameterless companion extension method
18+
-- Error: tests/neg/export-in-extension.scala:28:13 --------------------------------------------------------------------
19+
28 | export cm.* // error
20+
| ^^
21+
| export qualifier cm is not a parameterless companion extension method
22+
-- Error: tests/neg/export-in-extension.scala:33:13 --------------------------------------------------------------------
23+
33 | export cm.* // error
24+
| ^^
25+
| export qualifier cm is not a parameterless companion extension method
26+
-- Error: tests/neg/export-in-extension.scala:38:13 --------------------------------------------------------------------
27+
38 | export cm.* // error
28+
| ^^^^^^^^^^^
29+
| exports are only allowed from objects and classes

tests/neg/export-in-extension.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
object O:
2+
3+
class C(x: Int):
4+
def bar = x
5+
def baz(y: Int) = x + y
6+
val bam = x * x
7+
def :: (y: Int) = x - y
8+
class D
9+
10+
val c1 = C(1)
11+
12+
object O1:
13+
extension (x: Int)
14+
export c1.* // error
15+
16+
object O2:
17+
extension (x: Int)
18+
private def cm = new C(x)
19+
export cm.{bar, D} // error
20+
export this.cm.baz // error
21+
22+
object O3:
23+
extension (x: Int)
24+
export missing.* // error
25+
26+
object O4:
27+
extension (x: Int)
28+
export cm.* // error
29+
30+
object O5:
31+
extension (x: Int)
32+
private def cm(y: C) = C
33+
export cm.* // error
34+
35+
{
36+
extension (x: Int)
37+
private def cm = new C(x)
38+
export cm.* // error
39+
}
40+

tests/run/export-in-extension.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ object O:
1313
def succ2: Int = succ + 1
1414
def ::: (y: Int) = x - y
1515

16+
object O2:
17+
import O.C
18+
extension (x: Int)
19+
private def cm = new C(x)
20+
export cm.{bar, baz, bam, ::}
21+
def succ: Int = x + 1
22+
def succ2: Int = succ + 1
23+
def ::: (y: Int) = x - y
24+
1625
@main def Test =
1726
import O.*
1827
assert(3.succ2 == 5)

0 commit comments

Comments
 (0)