Skip to content

Commit 340a3b9

Browse files
committed
Make export of default getters work also with named and given exports
1 parent f4ce826 commit 340a3b9

File tree

3 files changed

+68
-20
lines changed

3 files changed

+68
-20
lines changed

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

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,26 @@ class Namer { typer: Typer =>
10701070
else Yes
10711071
}
10721072

1073+
def defaultGetters(sym: TermSymbol): List[Symbol] =
1074+
def recur(params: List[Symbol], paramss: List[List[Symbol]], n: Int): List[Symbol] =
1075+
params match
1076+
case param :: params1 =>
1077+
def otherGetters =
1078+
recur(params1, paramss, if param.isType then n else n + 1)
1079+
if param.is(HasDefault) then
1080+
val getterName = DefaultGetterName(sym.name, n)
1081+
val getter = path.tpe.member(DefaultGetterName(sym.name, n)).symbol
1082+
assert(getter.exists, i"$path does not have a default getter named $getterName")
1083+
getter :: otherGetters
1084+
else
1085+
otherGetters
1086+
case Nil =>
1087+
paramss match
1088+
case params1 :: paramss1 => recur(params1, paramss1, n)
1089+
case Nil => Nil
1090+
recur(Nil, sym.paramSymss, 0)
1091+
.showing(i"default getters of $sym, ${sym.paramSymss.nestedMap(_.flagsString)} = $result")
1092+
10731093
/** Add a forwarder with name `alias` or its type name equivalent to `mbr`,
10741094
* provided `mbr` is accessible and of the right implicit/non-implicit kind.
10751095
*/
@@ -1125,20 +1145,18 @@ class Namer { typer: Typer =>
11251145
forwarder.info = avoidPrivateLeaks(forwarder)
11261146
forwarder.addAnnotations(sym.annotations)
11271147

1128-
val forwarderDef =
1129-
if (forwarder.isType) tpd.TypeDef(forwarder.asType)
1130-
else {
1131-
import tpd._
1132-
val ref = path.select(sym.asTerm)
1133-
val ddef = tpd.DefDef(forwarder.asTerm, prefss =>
1134-
ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss))
1135-
)
1136-
if forwarder.isInlineMethod then
1137-
PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs)
1138-
ddef
1139-
}
1140-
1141-
buf += forwarderDef.withSpan(span)
1148+
if forwarder.isType then
1149+
buf += tpd.TypeDef(forwarder.asType).withSpan(span)
1150+
else
1151+
import tpd._
1152+
val ref = path.select(sym.asTerm)
1153+
val ddef = tpd.DefDef(forwarder.asTerm, prefss =>
1154+
ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss)))
1155+
if forwarder.isInlineMethod then
1156+
PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs)
1157+
buf += ddef.withSpan(span)
1158+
for getter <- defaultGetters(sym.asTerm) do
1159+
addForwarder(getter.name.asTermName, getter, span)
11421160
end addForwarder
11431161

11441162
def addForwardersNamed(name: TermName, alias: TermName, span: Span): Unit =
@@ -1162,11 +1180,15 @@ class Namer { typer: Typer =>
11621180
def isCaseClassSynthesized(mbr: Symbol) =
11631181
fromCaseClass && defn.caseClassSynthesized.contains(mbr)
11641182
for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) do
1165-
if !mbr.symbol.isSuperAccessor && !isCaseClassSynthesized(mbr.symbol) then
1166-
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1167-
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1168-
// Symbols from base traits of case classes that will get synthesized implementations
1169-
// at PostTyper are also excluded.
1183+
if !mbr.symbol.isSuperAccessor
1184+
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1185+
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1186+
// Symbols from base traits of case classes that will get synthesized implementations
1187+
// at PostTyper are also excluded.
1188+
&& !isCaseClassSynthesized(mbr.symbol)
1189+
&& !mbr.symbol.name.is(DefaultGetterName)
1190+
// default getters are exported with the members they belong to
1191+
then
11701192
val alias = mbr.name.toTermName
11711193
if mbr.symbol.is(Given) then
11721194
if !seen.contains(alias) && mbr.matchesImportBound(givenBound) then

tests/run/i14020.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
Hello you
22
Hello John
33
Hello you
4+
Hello you
5+
Hello John
6+
Hello you
7+
bark: Woof!

tests/run/i14020.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,31 @@ class B:
55
val a = A()
66
export a.*
77

8+
class C:
9+
val a = A()
10+
export a.greeting
11+
812
@main def Test =
913
val b = B()
1014

1115
println(b.a.greeting()) // works
1216
println(b.greeting("John")) // works
13-
println(b.greeting()) // nope !
17+
println(b.greeting()) // nope !
18+
19+
val c = C()
20+
21+
println(c.a.greeting()) // works
22+
println(c.greeting("John")) // works
23+
println(c.greeting()) // nope !
24+
25+
val w = Wolf()
26+
import w.given
27+
28+
println(summon[String]) // error: I found: w.bark(/* missing */summon[String])
29+
30+
class Dog:
31+
given bark(using msg: String = "Woof!"): String = s"bark: $msg"
32+
33+
class Wolf:
34+
private val dog = Dog()
35+
export dog.given // needs to be `export dog.{given, *}` to export the default arguments

0 commit comments

Comments
 (0)