diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index c753150bc4b5..5efd0cb31aaa 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -949,26 +949,28 @@ class Namer { typer: Typer => lazy val wildcardBound = importBound(selectors, isGiven = false) lazy val givenBound = importBound(selectors, isGiven = true) - def whyNoForwarder(mbr: SingleDenotation): String = { + def whyNoForwarder(mbr: SingleDenotation, isSameName: Boolean): String = { val sym = mbr.symbol - if (!sym.isAccessibleFrom(path.tpe)) "is not accessible" - else if (sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge)) SKIP - else if (cls.derivesFrom(sym.owner) && - (sym.owner == cls || !sym.is(Deferred))) i"is already a member of $cls" - else if (sym.is(Override)) - sym.allOverriddenSymbols.find( - other => cls.derivesFrom(other.owner) && !other.is(Deferred)) match { - case Some(other) => i"overrides ${other.showLocated}, which is already a member of $cls" - case None => "" - } + if !sym.isAccessibleFrom(path.tpe) then "is not accessible" + else if sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge) then SKIP + else if isSameName then + if cls.derivesFrom(sym.owner) && (sym.owner == cls || !sym.is(Deferred)) then + i"is already a member of $cls" + else if sym.is(Override) then + sym.allOverriddenSymbols.find( + other => cls.derivesFrom(other.owner) && !other.is(Deferred)) match { + case Some(other) => i"overrides ${other.showLocated}, which is already a member of $cls" + case None => "" + } + else "" else "" } /** Add a forwarder with name `alias` or its type name equivalent to `mbr`, * provided `mbr` is accessible and of the right implicit/non-implicit kind. */ - def addForwarder(alias: TermName, mbr: SingleDenotation, span: Span): Unit = - if (whyNoForwarder(mbr) == "") { + def addForwarder(alias: TermName, isSameName: Boolean, mbr: SingleDenotation, span: Span): Unit = + if (whyNoForwarder(mbr, isSameName) == "") { val sym = mbr.symbol val forwarder = if mbr.isType then @@ -1017,9 +1019,10 @@ class Namer { typer: Typer => def addForwardersNamed(name: TermName, alias: TermName, span: Span): Unit = { val size = buf.size val mbrs = List(name, name.toTypeName, name.toExtensionName).flatMap(path.tpe.member(_).alternatives) - mbrs.foreach(addForwarder(alias, _, span)) + val isSameName = name == alias + mbrs.foreach(addForwarder(alias, isSameName, _, span)) if (buf.size == size) { - val reason = mbrs.map(whyNoForwarder).dropWhile(_ == SKIP) match { + val reason = mbrs.map(whyNoForwarder(_, isSameName)).dropWhile(_ == SKIP) match { case Nil => "" case why :: _ => i"\n$path.$name cannot be exported because it $why" } @@ -1035,7 +1038,7 @@ class Namer { typer: Typer => val alias = mbr.name.toTermName if !seen.contains(alias) && mbr.matchesImportBound(if mbr.symbol.is(Given) then givenBound else wildcardBound) - then addForwarder(alias, mbr, span) + then addForwarder(alias, isSameName = true, mbr, span) def addForwarders(sels: List[untpd.ImportSelector], seen: List[TermName]): Unit = sels match case sel :: sels1 => diff --git a/tests/neg/exports.check b/tests/neg/exports.check index 13299a35d258..4d3f8fd87240 100644 --- a/tests/neg/exports.check +++ b/tests/neg/exports.check @@ -33,19 +33,21 @@ | final def status: => List[String] in class Copier at line 24 and | final def status: => List[String] in class Copier at line 26 | have the same type after erasure. --- Error: tests/neg/exports.scala:35:24 -------------------------------------------------------------------------------- -35 | export this.{concat => ++} // error: no eligible member - | ^^^^^^^^^^^^ - | no eligible member concat at this - | this.concat cannot be exported because it is already a member of trait IterableOps --- Error: tests/neg/exports.scala:41:15 -------------------------------------------------------------------------------- -41 | export foo.foo // error: no eligible member +-- [E120] Naming Error: tests/neg/exports.scala:42:24 ------------------------------------------------------------------ +42 | export this.{addAll => alias} // error: double definition + | ^ + | Double definition: + | def alias(ints: Int*): (Buf.this : Buf) in class Buf at line 41 and + | final def alias(ints: Int*): (Buf.this : Buf) in class Buf at line 42 + | have the same type after erasure. +-- Error: tests/neg/exports.scala:47:15 -------------------------------------------------------------------------------- +47 | export foo.foo // error: no eligible member | ^^^ | no eligible member foo at this.foo | this.foo.foo cannot be exported because it is already a member of class Foo --- [E120] Naming Error: tests/neg/exports.scala:46:15 ------------------------------------------------------------------ -46 | export bar._ // error: double definition +-- [E120] Naming Error: tests/neg/exports.scala:52:15 ------------------------------------------------------------------ +52 | export bar._ // error: double definition | ^ | Double definition: - | val bar: Bar in class Baz at line 45 and - | final def bar: => (Baz.this.bar.bar : => (Baz.this.bar.baz.bar : Bar)) in class Baz at line 46 + | val bar: Bar in class Baz at line 51 and + | final def bar: => (Baz.this.bar.bar : => (Baz.this.bar.baz.bar : Bar)) in class Baz at line 52 diff --git a/tests/neg/exports.scala b/tests/neg/exports.scala index 1972158bf58e..01ba818bd1c9 100644 --- a/tests/neg/exports.scala +++ b/tests/neg/exports.scala @@ -32,10 +32,16 @@ def concat[B >: A](other: List[B]): CC[B] - export this.{concat => ++} // error: no eligible member + export this.{concat => ++} } + class Buf { + def addAll(ints: Int*): this.type = this + def alias(ints: Int*): this.type = this + export this.{addAll => alias} // error: double definition + } + class Foo { val foo : Foo = new Foo export foo.foo // error: no eligible member @@ -49,3 +55,7 @@ val baz: Baz = new Baz export baz._ } + class Qux { + val qux: Qux = new Qux + export qux.{qux => innerQux} + } diff --git a/tests/neg/exports1.scala b/tests/neg/exports1.scala index ecd89c694043..f91156f14ca0 100644 --- a/tests/neg/exports1.scala +++ b/tests/neg/exports1.scala @@ -18,3 +18,7 @@ object D1 extends B: object D2 extends B: object b2 extends B2 export b2.f // error + +object D3 extends B: + object b2 extends B2 + export b2.{f => g} // ok diff --git a/tests/pos/i9704.scala b/tests/pos/i9704.scala new file mode 100644 index 000000000000..fbe214ddc904 --- /dev/null +++ b/tests/pos/i9704.scala @@ -0,0 +1,16 @@ +abstract class WordSpec { + export this.{extension_in => extension_should} + + extension(s: String) def in(f: => Any): Unit = { + println(s) + f + } +} + +object test extends WordSpec { + "X" should { + "add numbers" in { + assert(1 + 1 == 2) + } + } +}