-
Notifications
You must be signed in to change notification settings - Fork 3.1k
SI-3772 Fix detection of term-owned companions #5550
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
Conversation
9e10201
to
b6e0798
Compare
@som-snytt Could you think of any additional test cases for this? |
This progresses to a VerifyError. (https://issues.scala-lang.org/browse/SI-8733) I was thinking of those odd constructor contexts. Maybe there's a better corner case; I've forgotten the context.
|
There was a test for your other case that fails now: test/files/pos/t8002-nested-scope.scala |
f1a4d59
to
83d1197
Compare
What if |
case entry if entry.sym == original => | ||
entry.owner.lookupAllEntries(original.name.companionName) | ||
.filter(_.owner eq entry.owner) | ||
.filter(x => original.isTerm || x.sym.hasModuleFlag).toList match { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment on this filter would help - i guess original
is either a class symbol or a module symbol? I see it was copied from the original code, but it's not very clear. Also, the original code had a check for isCoDefinedWith
- is this no longer needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've re-added the isCodefinedWith
check, moved some code around, and added a comment for the hasModuleFlag
check.
Companion detection consults the scopes of enclosing Contexts during typechecking to avoid the cycles that would ensue if we had to look at into the info of enclosing class symbols. For example, this used to typecheck: object CC { val outer = 42 } if ("".isEmpty) { case class CC(c: Int) CC.outer } This logic was not suitably hardened to find companions in exactly the same nesting level. After fixing this problem, a similar problem in `Namer::inCurrentScope` could be solved to be more selective about synthesizing a companion object. In particular, if a manually defined companion trails after the case class, don't create an addiotional synthetic comanpanion object.
83d1197
to
37037fe
Compare
final def lookupCompanion(original: Symbol): Symbol = { | ||
lookupSymbolEntry(original) match { | ||
case null => | ||
case entry if entry.sym == original => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the implementation of lookupSymbolEntry
, the guard here seems redundant.
// 1) Must be owned by the same Scope, to ensure that in | ||
// `{ class C; { ...; object C } }`, the class is not seen as a comaniopn of the object. | ||
// 2) Must be in exactly the same scope, so that `{ class C; def C }` are not companions | ||
// TODO Exclude type aliases as companions of terms? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we should. sym.companionClass
also does since https://github.com/scala/scala/pull/5482/commits
final def lookupCompanionOf(original: Symbol): Symbol = { | ||
lookupScopeEntry(original) match { | ||
case null => NoSymbol | ||
case entry => entry.owner.lookupCompanion(original).filter(_.isCoDefinedWith(original)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason to put the filter here, instead of inside lookupCompanion
?
Pushed a commit with your suggestions. We could go a bit further and change |
LGTM, thanks! |
The behaviour changed in scala#5550, this commit adapts to the change so that we'll be binary compatible after boostrapping. MiMa alerted us to a change in the parentage of two objects in the forkjoin package object. In Scala 2.12.0/1, they implemented `scala.Serializable`. Recently, this (synthetically added) parent was absent. This appears to be due to a bug fix in `companionSymbolOf`, which no longer treats objects and same-named type aliases to be companions. This commit manually adds the formerly-synthetic parents to these objects, and documents the change in compiler behaviour with a test. Fixes scala/scala-dev#290
The behaviour changed in scala#5550, this commit adapts to the change so that we'll be binary compatible after boostrapping. MiMa alerted us to a change in the parentage of two objects in the forkjoin package object. In Scala 2.12.0/1, they implemented `scala.Serializable`. Recently, this (synthetically added) parent was absent. This appears to be due to a bug fix in `companionSymbolOf`, which no longer treats objects and same-named type aliases to be companions. This commit manually adds the formerly-synthetic parents to these objects, and documents the change in compiler behaviour with a test. Fixes scala/scala-dev#290
A recent change to fix lookup of companion implicits of term-owned classes (scala#5550) caused a regression in the enclosed test case. The previous approach of calling `Symbol#companionModule` was replaced with `Namers#companionSymbolOf`. However, this fails to determine that a method-owned object is the companion of its own module class, as the module class itself is not entered into the scope of the method. This commit uses `Symbol#companionSymbol` when the original symbol is a module class. All term-owned module class symbols will from the current run, and are represented with `ModuleClassSymbol`, which ...
A recent change to fix lookup of companion implicits of term-owned classes (scala#5550) caused a regression in the enclosed test case. The previous approach of calling `Scope#lookup(companionName)` was replaced by a lookup of the scope entry of the original name followed by a narrower search lookup for the companion name, to ensure that it was a true companion, and not just a same-named module from defined at a different nested scope. However, module class symbols are not themselves entered into scopes, so the first part of the new scheme fails. We need to add a special case modules here. I've chosen to just call `.sourceModule` on module classes. For module classes in the current run (all term owned symbols will fall into this category), this amounts to using the value of the field `ModuleClassSymbol#module`.
Companion detection consults the scopes of enclosing Contexts during
typechecking to avoid the cycles that would ensue if we had to look
at into the info of enclosing class symbols. For example, this used
to typecheck:
This logic was not suitably hardened to find companions in exactly
the same nesting level.
After fixing this problem, a similar problem in
Namer::inCurrentScope
could be solved to be more selective about synthesizing a companion
object. In particular, if a manually defined companion trails after
the case class, don't create an addiotional synthetic comanpanion object.
JIRA: https://issues.scala-lang.org/browse/SI-3772