Skip to content

Commit 713468b

Browse files
committed
Better error messages when no export aliases exist
1 parent 37aa7c0 commit 713468b

File tree

3 files changed

+80
-11
lines changed

3 files changed

+80
-11
lines changed

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

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -944,19 +944,20 @@ class Namer { typer: Typer =>
944944
val path = typedAheadExpr(expr, AnySelectionProto)
945945
checkLegalImportPath(path)
946946

947-
def needsForwarder(sym: Symbol) =
948-
sym.is(ImplicitOrImplied) == exp.impliedOnly &&
949-
sym.isAccessibleFrom(path.tpe) &&
950-
!sym.isConstructor &&
951-
!sym.is(ModuleClass) &&
952-
!sym.is(Bridge) &&
953-
!cls.derivesFrom(sym.owner)
947+
def whyNoForwarder(mbr: SingleDenotation): String = {
948+
val sym = mbr.symbol
949+
if (sym.is(ImplicitOrImplied) != exp.impliedOnly) s"is ${if (exp.impliedOnly) "not " else ""}implied"
950+
else if (!sym.isAccessibleFrom(path.tpe)) "is not accessible"
951+
else if (sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge)) "_"
952+
else if (cls.derivesFrom(sym.owner)) i"is already a member of $cls"
953+
else ""
954+
}
954955

955956
/** Add a forwarder with name `alias` or its type name equivalent to `mbr`,
956957
* provided `mbr` is accessible and of the right implicit/non-implicit kind.
957958
*/
958-
def addForwarder(alias: TermName, mbr: SingleDenotation, span: Span): Unit =
959-
if (needsForwarder(mbr.symbol)) {
959+
def addForwarder(alias: TermName, mbr: SingleDenotation, span: Span): Unit = {
960+
if (whyNoForwarder(mbr) == "") {
960961

961962
/** The info of a forwarder to type `ref` which has info `info`
962963
*/
@@ -998,12 +999,19 @@ class Namer { typer: Typer =>
998999
}
9991000
buf += forwarderDef.withSpan(span)
10001001
}
1002+
}
10011003

10021004
def addForwardersNamed(name: TermName, alias: TermName, span: Span): Unit = {
1005+
val size = buf.size
10031006
val mbrs = List(name, name.toTypeName).flatMap(path.tpe.member(_).alternatives)
1004-
if (mbrs.isEmpty)
1005-
ctx.error(i"no accessible member $name at $path", ctx.source.atSpan(span))
10061007
mbrs.foreach(addForwarder(alias, _, span))
1008+
if (buf.size == size) {
1009+
val reason = mbrs.map(whyNoForwarder).dropWhile(_ == "-") match {
1010+
case Nil => ""
1011+
case why :: _ => i"\n$path.$name cannot be exported because it $why"
1012+
}
1013+
ctx.error(i"""no eligible member $name at $path$reason""", ctx.source.atSpan(span))
1014+
}
10071015
}
10081016

10091017
def addForwardersExcept(seen: List[TermName], span: Span): Unit =

tests/neg/exports.check

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[991..997] in exports.scala
2+
no eligible member concat at this
3+
this.concat cannot be exported because it is already a member of trait IterableOps
4+
<647..647> in exports.scala
5+
Double definition:
6+
final def status: => List[String] in class Copier at line 23 and
7+
final def status: => List[String] in class Copier at line 24
8+
have the same type after erasure.
9+
<596..596> in exports.scala
10+
Double definition:
11+
def status: => List[String] in class Copier at line 28 and
12+
final def status: => List[String] in class Copier at line 23
13+
have the same type after erasure.
14+
[785..791] in exports.scala
15+
no eligible member status at this.printUnit
16+
this.printUnit.status cannot be exported because it is not implied
17+
[712..718] in exports.scala
18+
no eligible member bitmap at this.printUnit
19+
this.printUnit.bitmap cannot be exported because it is implied
20+
[518..525] in exports.scala
21+
no eligible member scanAll at this.scanUnit
22+
this.scanUnit.scanAll cannot be exported because it is not accessible
23+
[452..458] in exports.scala
24+
no eligible member scanIt at this.scanUnit

tests/neg/exports.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class BitMap
2+
class InkJet
3+
4+
class Printer {
5+
type PrinterType
6+
def print(bits: BitMap): Unit = ???
7+
def status: List[String] = ???
8+
implied bitmap for BitMap
9+
}
10+
11+
class Scanner {
12+
def scan(): BitMap = ???
13+
private def scanAll: BitMap = ???
14+
def status: List[String] = ???
15+
}
16+
17+
class Copier {
18+
private val printUnit = new Printer { type PrinterType = InkJet }
19+
private val scanUnit = new Scanner
20+
21+
export scanUnit.scanIt // error: no eligible member
22+
export scanUnit.{scanAll => foo} // error: no eligible member
23+
export printUnit.{stat => _, _} // error: double definition
24+
export scanUnit._ // error: double definition
25+
export printUnit.bitmap // error: no eligible member
26+
export implied printUnit.status // error: no eligible member
27+
28+
def status: List[String] = printUnit.status ++ scanUnit.status
29+
}
30+
31+
trait IterableOps[+A, +CC[_], +C] {
32+
33+
def concat[B >: A](other: List[B]): CC[B]
34+
35+
export this.{concat => ++} // error: no eligible member
36+
37+
}

0 commit comments

Comments
 (0)