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

Make eraseInfo work for classes with EmptyScopes #19550

Merged
merged 6 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
26 changes: 17 additions & 9 deletions compiler/src/dotty/tools/dotc/core/Scopes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,27 @@ object Scopes {
}

/** The scope that keeps only those symbols from this scope that match the
* given predicates. If all symbols match, returns the scope itself, otherwise
* a copy with the matching symbols.
* given predicates, renamed with the given rename function.
* If all symbols match and none are renamed, returns the scope itself, otherwise
* a copy with the matching and renamed symbols.
*/
final def filteredScope(p: Symbol => Boolean)(using Context): Scope = {
final def filteredScope(
keep: Symbol => Boolean,
rename: Symbol => Name | Null = _ => null)(using Context): Scope =
var result: MutableScope | Null = null
for (sym <- iterator)
if (!p(sym)) {
if (result == null) result = cloneScope
for sym <- iterator do
def drop() =
if result == null then result = cloneScope
result.nn.unlink(sym)
}
if keep(sym) then
val newName = rename(sym)
if newName != null then
drop()
result.nn.enter(newName, sym)
else
drop()
// TODO: improve flow typing to handle this case
if (result == null) this else result.uncheckedNN
}
if result == null then this else result.uncheckedNN

def implicitDecls(using Context): List[TermRef] = Nil

Expand Down
18 changes: 9 additions & 9 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -725,14 +725,13 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
tr1 :: trs1.filterNot(_.isAnyRef)
case nil => nil
}
var erasedDecls = decls.filteredScope(sym => !sym.isType || sym.isClass).openForMutations
for dcl <- erasedDecls.iterator do
if dcl.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined
&& dcl.targetName != dcl.name
then
if erasedDecls eq decls then erasedDecls = erasedDecls.cloneScope
erasedDecls.unlink(dcl)
erasedDecls.enter(dcl.targetName, dcl)
val erasedDecls = decls.filteredScope(
keep = sym => !sym.isType || sym.isClass,
rename = sym =>
if sym.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined
then sym.targetName
else null
noti0na1 marked this conversation as resolved.
Show resolved Hide resolved
)
val selfType1 = if cls.is(Module) then cls.sourceModule.termRef else NoType
tp.derivedClassInfo(NoPrefix, erasedParents, erasedDecls, selfType1)
// can't replace selftype by NoType because this would lose the sourceModule link
Expand Down Expand Up @@ -814,7 +813,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
eraseResult(tp1.resultType) match
case rt: MethodType => rt
case rt => MethodType(Nil, Nil, rt)
case tp1 => this(tp1)
case tp1 =>
this(tp1)

private def eraseDerivedValueClass(tp: Type)(using Context): Type = {
val cls = tp.classSymbol.asClass
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i19506.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//> using options "-source:3.4-migration",
//> using options -source 3.4-migration

trait Reader[T]
def read[T: Reader](s: String, trace: Boolean = false): T = ???
Expand Down
3 changes: 3 additions & 0 deletions tests/pos/i19530.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object A {
def x = classOf[scala.Singleton]
}
Loading