Skip to content

Commit b3ab102

Browse files
authored
Merge pull request #14051 from dotty-staging/fix-14020
Retain HasDefaultParams flag on export.
2 parents 351cb05 + cbff98d commit b3ab102

File tree

4 files changed

+85
-22
lines changed

4 files changed

+85
-22
lines changed

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ object SymDenotations {
930930
def hasDefaultParams(using Context): Boolean =
931931
if ctx.erasedTypes then false
932932
else if is(HasDefaultParams) then true
933-
else if is(NoDefaultParams) then false
933+
else if is(NoDefaultParams) || !is(Method) then false
934934
else
935935
val result =
936936
rawParamss.nestedExists(_.is(HasDefault))

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

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,17 @@ class Namer { typer: Typer =>
10961096
else Yes
10971097
}
10981098

1099+
def foreachDefaultGetterOf(sym: TermSymbol, op: TermSymbol => Unit): Unit =
1100+
var n = 0
1101+
for params <- sym.paramSymss; param <- params do
1102+
if param.isTerm then
1103+
if param.is(HasDefault) then
1104+
val getterName = DefaultGetterName(sym.name, n)
1105+
val getter = path.tpe.member(DefaultGetterName(sym.name, n)).symbol
1106+
assert(getter.exists, i"$path does not have a default getter named $getterName")
1107+
op(getter.asTerm)
1108+
n += 1
1109+
10991110
/** Add a forwarder with name `alias` or its type name equivalent to `mbr`,
11001111
* provided `mbr` is accessible and of the right implicit/non-implicit kind.
11011112
*/
@@ -1118,6 +1129,7 @@ class Namer { typer: Typer =>
11181129

11191130
if canForward(mbr) == CanForward.Yes then
11201131
val sym = mbr.symbol
1132+
val hasDefaults = sym.hasDefaultParams // compute here to ensure HasDefaultParams and NoDefaultParams flags are set
11211133
val forwarder =
11221134
if mbr.isType then
11231135
val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false, span)
@@ -1142,28 +1154,29 @@ class Namer { typer: Typer =>
11421154
(StableRealizable, ExprType(path.tpe.select(sym)))
11431155
else
11441156
(EmptyFlags, mbr.info.ensureMethodic)
1145-
var mbrFlags = Exported | Method | Final | maybeStable | sym.flags & RetainedExportFlags
1157+
var flagMask = RetainedExportFlags
1158+
if sym.isTerm then flagMask |= HasDefaultParams | NoDefaultParams
1159+
var mbrFlags = Exported | Method | Final | maybeStable | sym.flags & flagMask
11461160
if sym.is(ExtensionMethod) then mbrFlags |= ExtensionMethod
11471161
val forwarderName = checkNoConflict(alias, isPrivate = false, span)
11481162
newSymbol(cls, forwarderName, mbrFlags, mbrInfo, coord = span)
11491163

11501164
forwarder.info = avoidPrivateLeaks(forwarder)
1151-
forwarder.addAnnotations(sym.annotations)
1152-
1153-
val forwarderDef =
1154-
if (forwarder.isType) tpd.TypeDef(forwarder.asType)
1155-
else {
1156-
import tpd._
1157-
val ref = path.select(sym.asTerm)
1158-
val ddef = tpd.DefDef(forwarder.asTerm, prefss =>
1159-
ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss))
1160-
)
1161-
if forwarder.isInlineMethod then
1162-
PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs)
1163-
ddef
1164-
}
1165+
forwarder.addAnnotations(sym.annotations.filterConserve(_.symbol != defn.BodyAnnot))
11651166

1166-
buf += forwarderDef.withSpan(span)
1167+
if forwarder.isType then
1168+
buf += tpd.TypeDef(forwarder.asType).withSpan(span)
1169+
else
1170+
import tpd._
1171+
val ref = path.select(sym.asTerm)
1172+
val ddef = tpd.DefDef(forwarder.asTerm, prefss =>
1173+
ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss)))
1174+
if forwarder.isInlineMethod then
1175+
PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs)
1176+
buf += ddef.withSpan(span)
1177+
if hasDefaults then
1178+
foreachDefaultGetterOf(sym.asTerm,
1179+
getter => addForwarder(getter.name.asTermName, getter, span))
11671180
end addForwarder
11681181

11691182
def addForwardersNamed(name: TermName, alias: TermName, span: Span): Unit =
@@ -1187,11 +1200,15 @@ class Namer { typer: Typer =>
11871200
def isCaseClassSynthesized(mbr: Symbol) =
11881201
fromCaseClass && defn.caseClassSynthesized.contains(mbr)
11891202
for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) do
1190-
if !mbr.symbol.isSuperAccessor && !isCaseClassSynthesized(mbr.symbol) then
1191-
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1192-
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1193-
// Symbols from base traits of case classes that will get synthesized implementations
1194-
// at PostTyper are also excluded.
1203+
if !mbr.symbol.isSuperAccessor
1204+
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
1205+
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
1206+
// Symbols from base traits of case classes that will get synthesized implementations
1207+
// at PostTyper are also excluded.
1208+
&& !isCaseClassSynthesized(mbr.symbol)
1209+
&& !mbr.symbol.name.is(DefaultGetterName)
1210+
// default getters are exported with the members they belong to
1211+
then
11951212
val alias = mbr.name.toTermName
11961213
if mbr.symbol.is(Given) then
11971214
if !seen.contains(alias) && mbr.matchesImportBound(givenBound) then

tests/run/i14020.check

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

tests/run/i14020.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class A:
2+
def greeting(name: String = "you") = s"Hello $name"
3+
4+
class A2:
5+
inline def greeting(name: String = "you") = s"Hello $name"
6+
7+
class B:
8+
val a = A()
9+
export a.*
10+
11+
class C:
12+
val a = A2()
13+
export a.greeting
14+
15+
@main def Test =
16+
val b = B()
17+
18+
println(b.a.greeting()) // works
19+
println(b.greeting("John")) // works
20+
println(b.greeting()) // nope !
21+
22+
val c = C()
23+
24+
println(c.a.greeting()) // works
25+
println(c.greeting("John")) // works
26+
println(c.greeting()) // nope !
27+
28+
val w = Wolf()
29+
import w.given
30+
31+
println(summon[String]) // error: I found: w.bark(/* missing */summon[String])
32+
33+
34+
class Dog:
35+
given bark(using msg: String = "Woof!"): String = s"bark: $msg"
36+
37+
class Wolf:
38+
private val dog = Dog()
39+
export dog.given // needs to be `export dog.{given, *}` to export the default arguments

0 commit comments

Comments
 (0)