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

Don't export members that will be synthesized in case classes #13234

Merged
merged 8 commits into from
Aug 13, 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
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,10 @@ class Definitions {
val AbstractFunctionClassPerRun: PerRun[Array[Symbol]] = new PerRun(AbstractFunctionType.map(_.symbol.asClass))
def AbstractFunctionClass(n: Int)(using Context): Symbol = AbstractFunctionClassPerRun()(using ctx)(n)

@tu lazy val caseClassSynthesized: List[Symbol] = List(
Any_hashCode, Any_equals, Any_toString, Product_canEqual, Product_productArity,
Product_productPrefix, Product_productElement, Product_productElementName)

val LazyHolder: PerRun[Map[Symbol, Symbol]] = new PerRun({
def holderImpl(holderType: String) = requiredClass("scala.runtime." + holderType)
Map[Symbol, Symbol](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
private def initSymbols(using Context) =
if (myValueSymbols.isEmpty) {
myValueSymbols = List(defn.Any_hashCode, defn.Any_equals)
myCaseSymbols = myValueSymbols ++ List(defn.Any_toString, defn.Product_canEqual,
defn.Product_productArity, defn.Product_productPrefix, defn.Product_productElement,
defn.Product_productElementName)
myCaseSymbols = defn.caseClassSynthesized
myCaseModuleSymbols = myCaseSymbols.filter(_ ne defn.Any_equals)
myEnumValueSymbols = List(defn.Product_productPrefix)
myNonJavaEnumValueSymbols = myEnumValueSymbols :+ defn.Any_toString
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1156,10 +1156,15 @@ class Namer { typer: Typer =>

def addWildcardForwarders(seen: List[TermName], span: Span): Unit =
val nonContextual = mutable.HashSet(seen: _*)
val fromCaseClass = path.tpe.widen.classSymbols.exists(_.is(Case))
def isCaseClassSynthesized(mbr: Symbol) =
fromCaseClass && defn.caseClassSynthesized.contains(mbr)
for mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) do
if !mbr.symbol.isSuperAccessor then
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.
val alias = mbr.name.toTermName
if mbr.symbol.is(Given) then
if !seen.contains(alias) && mbr.matchesImportBound(givenBound) then
Expand Down
5 changes: 5 additions & 0 deletions tests/run/i13228.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
RegisteredUser(Id,User(Name))
false
false
false
false
13 changes: 13 additions & 0 deletions tests/run/i13228.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
case class User(name: String)

case class RegisteredUser(id: String, data: User) {
export data.*
}

@main def Test() =
println(RegisteredUser("Id", User("Name"))) // RegisteredUser(Name)
println(RegisteredUser("Id", User("Name")).canEqual(User("Name"))) // True
// The rest works as expected
println(RegisteredUser("Id", User("Name")) == User("Name")) // False
println(RegisteredUser("Id", User("Name")).hashCode == User("Name").hashCode) // False
println(RegisteredUser("Id", User("Name")).productArity == User("Name").productArity) // False