Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retain HasDefaultParams flag on export. #14051

Merged
merged 5 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ object SymDenotations {
def hasDefaultParams(using Context): Boolean =
if ctx.erasedTypes then false
else if is(HasDefaultParams) then true
else if is(NoDefaultParams) then false
else if is(NoDefaultParams) || !is(Method) then false
else
val result =
rawParamss.nestedExists(_.is(HasDefault))
Expand Down
59 changes: 38 additions & 21 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,17 @@ class Namer { typer: Typer =>
else Yes
}

def foreachDefaultGetterOf(sym: TermSymbol, op: TermSymbol => Unit): Unit =
var n = 0
for params <- sym.paramSymss; param <- params do
if param.isTerm then
if param.is(HasDefault) then
val getterName = DefaultGetterName(sym.name, n)
val getter = path.tpe.member(DefaultGetterName(sym.name, n)).symbol
assert(getter.exists, i"$path does not have a default getter named $getterName")
op(getter.asTerm)
n += 1

/** 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.
*/
Expand All @@ -1092,6 +1103,7 @@ class Namer { typer: Typer =>

if canForward(mbr) == CanForward.Yes then
val sym = mbr.symbol
val hasDefaults = sym.hasDefaultParams // compute here to ensure HasDefaultParams and NoDefaultParams flags are set
val forwarder =
if mbr.isType then
val forwarderName = checkNoConflict(alias.toTypeName, isPrivate = false, span)
Expand All @@ -1116,28 +1128,29 @@ class Namer { typer: Typer =>
(StableRealizable, ExprType(path.tpe.select(sym)))
else
(EmptyFlags, mbr.info.ensureMethodic)
var mbrFlags = Exported | Method | Final | maybeStable | sym.flags & RetainedExportFlags
var flagMask = RetainedExportFlags
if sym.isTerm then flagMask |= HasDefaultParams | NoDefaultParams
var mbrFlags = Exported | Method | Final | maybeStable | sym.flags & flagMask
if sym.is(ExtensionMethod) then mbrFlags |= ExtensionMethod
val forwarderName = checkNoConflict(alias, isPrivate = false, span)
newSymbol(cls, forwarderName, mbrFlags, mbrInfo, coord = span)

forwarder.info = avoidPrivateLeaks(forwarder)
forwarder.addAnnotations(sym.annotations)

val forwarderDef =
if (forwarder.isType) tpd.TypeDef(forwarder.asType)
else {
import tpd._
val ref = path.select(sym.asTerm)
val ddef = tpd.DefDef(forwarder.asTerm, prefss =>
ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss))
)
if forwarder.isInlineMethod then
PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs)
ddef
}
forwarder.addAnnotations(sym.annotations.filterConserve(_.symbol != defn.BodyAnnot))

buf += forwarderDef.withSpan(span)
if forwarder.isType then
buf += tpd.TypeDef(forwarder.asType).withSpan(span)
else
import tpd._
val ref = path.select(sym.asTerm)
val ddef = tpd.DefDef(forwarder.asTerm, prefss =>
ref.appliedToArgss(adaptForwarderParams(Nil, sym.info, prefss)))
if forwarder.isInlineMethod then
PrepareInlineable.registerInlineInfo(forwarder, ddef.rhs)
buf += ddef.withSpan(span)
if hasDefaults then
foreachDefaultGetterOf(sym.asTerm,
getter => addForwarder(getter.name.asTermName, getter, span))
end addForwarder

def addForwardersNamed(name: TermName, alias: TermName, span: Span): Unit =
Expand All @@ -1161,11 +1174,15 @@ class Namer { typer: Typer =>
def isCaseClassSynthesized(mbr: Symbol) =
fromCaseClass && defn.caseClassSynthesized.contains(mbr)
for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) do
if !mbr.symbol.isSuperAccessor && !isCaseClassSynthesized(mbr.symbol) then
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
// Symbols from base traits of case classes that will get synthesized implementations
// at PostTyper are also excluded.
if !mbr.symbol.isSuperAccessor
// Scala 2 superaccessors have neither Synthetic nor Artfact set, so we
// need to filter them out here (by contrast, Scala 3 superaccessors are Artifacts)
// Symbols from base traits of case classes that will get synthesized implementations
// at PostTyper are also excluded.
&& !isCaseClassSynthesized(mbr.symbol)
&& !mbr.symbol.name.is(DefaultGetterName)
// default getters are exported with the members they belong to
then
val alias = mbr.name.toTermName
if mbr.symbol.is(Given) then
if !seen.contains(alias) && mbr.matchesImportBound(givenBound) then
Expand Down
7 changes: 7 additions & 0 deletions tests/run/i14020.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Hello you
Hello John
Hello you
Hello you
Hello John
Hello you
bark: Woof!
39 changes: 39 additions & 0 deletions tests/run/i14020.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class A:
def greeting(name: String = "you") = s"Hello $name"
Copy link
Member

@bishabosha bishabosha Dec 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried making greeting inline and now we get a crash when calling c.greeting(), (before this PR is just the standard missing argument error)

stack trace
scala> c.greeting()
[error] (run-main-2) java.lang.IllegalArgumentException: Could not find proxy for name: String in List(val name, method greeting, class A, module class rs$line$1$, module class repl$, module class <root>), encl = package repl, owners = package repl, package <root>; enclosures = package repl, package <root>
[error] java.lang.IllegalArgumentException: Could not find proxy for name: String in List(val name, method greeting, class A, module class rs$line$1$, module class repl$, module class <root>), encl = package repl, owners = package repl, package <root>; enclosures = package repl, package <root>
[error] 	at dotty.tools.dotc.transform.LambdaLift$Lifter.searchIn$1(LambdaLift.scala:148)
[error] 	at dotty.tools.dotc.transform.LambdaLift$Lifter.proxy(LambdaLift.scala:161)
[error] 	at dotty.tools.dotc.transform.LambdaLift$Lifter.proxyRef(LambdaLift.scala:179)
[error] 	at dotty.tools.dotc.transform.LambdaLift$Lifter.addFreeArgs$$anonfun$1(LambdaLift.scala:185)
[error] 	at scala.collection.immutable.List.map(List.scala:246)
[error] 	at dotty.tools.dotc.transform.LambdaLift$Lifter.addFreeArgs(LambdaLift.scala:185)
[error] 	at dotty.tools.dotc.transform.LambdaLift.transformApply(LambdaLift.scala:322)
[error] 	at dotty.tools.dotc.transform.LambdaLift.transformApply(LambdaLift.scala:321)
[error] 	at dotty.tools.dotc.transform.MegaPhase.goApply(MegaPhase.scala:644)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:281)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] 	at dotty.tools.dotc.transform.MegaPhase.mapValDef$1(MegaPhase.scala:235)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformNamed$1(MegaPhase.scala:240)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:427)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformStat$1(MegaPhase.scala:437)
[error] 	at dotty.tools.dotc.transform.MegaPhase.recur$1(MegaPhase.scala:442)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformStats(MegaPhase.scala:442)
[error] 	at dotty.tools.dotc.transform.MegaPhase.mapPackage$1(MegaPhase.scala:382)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnnamed$1(MegaPhase.scala:385)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformTree(MegaPhase.scala:429)
[error] 	at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:448)
[error] 	at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:460)
[error] 	at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:308)
[error] 	at scala.collection.immutable.List.map(List.scala:246)
[error] 	at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:309)
[error] 	at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:261)
[error] 	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] 	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] 	at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] 	at dotty.tools.dotc.Run.runPhases$1(Run.scala:272)
[error] 	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:280)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
[error] 	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:68)
[error] 	at dotty.tools.dotc.Run.compileUnits(Run.scala:289)
[error] 	at dotty.tools.dotc.Run.compileUnits(Run.scala:228)
[error] 	at dotty.tools.repl.ReplCompiler.runCompilationUnit(ReplCompiler.scala:167)
[error] 	at dotty.tools.repl.ReplCompiler.compile(ReplCompiler.scala:178)
[error] 	at dotty.tools.repl.ReplDriver.compile(ReplDriver.scala:251)
[error] 	at dotty.tools.repl.ReplDriver.interpret(ReplDriver.scala:219)
[error] 	at dotty.tools.repl.ReplDriver.loop$1(ReplDriver.scala:153)
[error] 	at dotty.tools.repl.ReplDriver.runUntilQuit$$anonfun$1(ReplDriver.scala:156)
[error] 	at dotty.tools.repl.ReplDriver.withRedirectedOutput(ReplDriver.scala:175)
[error] 	at dotty.tools.repl.ReplDriver.runUntilQuit(ReplDriver.scala:156)
[error] 	at xsbt.ConsoleInterface.run(ConsoleInterface.java:52)
[error] 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] 	at java.lang.reflect.Method.invoke(Method.java:498)
[error] 	at sbt.internal.inc.AnalyzingCompiler.invoke(AnalyzingCompiler.scala:329)
[error] 	at sbt.internal.inc.AnalyzingCompiler.console(AnalyzingCompiler.scala:233)
[error] 	at sbt.Console.console0$1(Console.scala:64)
[error] 	at sbt.Console.$anonfun$apply$5(Console.scala:74)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] 	at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:17)
[error] 	at sbt.TrapExit$App.run(TrapExit.scala:258)
[error] 	at java.lang.Thread.run(Thread.java:748)
[error] Nonzero exit code: 1
[error] (scala3-compiler-bootstrapped / Compile / console) Nonzero exit code: 1
[error] Total time: 32 s, completed Dec 8, 2021 11:09:44 AM


class A2:
inline def greeting(name: String = "you") = s"Hello $name"

class B:
val a = A()
export a.*
bishabosha marked this conversation as resolved.
Show resolved Hide resolved

class C:
val a = A2()
export a.greeting

@main def Test =
val b = B()

println(b.a.greeting()) // works
println(b.greeting("John")) // works
println(b.greeting()) // nope !

val c = C()

println(c.a.greeting()) // works
println(c.greeting("John")) // works
println(c.greeting()) // nope !

val w = Wolf()
import w.given

println(summon[String]) // error: I found: w.bark(/* missing */summon[String])


class Dog:
given bark(using msg: String = "Woof!"): String = s"bark: $msg"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have found one last issue which is by making bark inline:

class Dog:
   inline given bark(using msg: String = "Woof!"): String = s"bark: $msg"

gives

-- Error: ----------------------------------------------------------------------
31 |summon[String]
   |              ^
   |value dog cannot be accessed as a member of (Wolf_this : (w : Wolf)) from module class i14020$package$.
   | This location contains code that was inlined from i14020.scala:39
1 error found

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't get the same error if you try to manually forward to dog.bark in Wolf:

class Wolf:
  private val dog = Dog()
  inline given bark(using msg: String = "Woof!"): String = dog.bark(using msg)


class Wolf:
private val dog = Dog()
export dog.given // needs to be `export dog.{given, *}` to export the default arguments