Skip to content

Commit 8d9af0c

Browse files
committed
Make eraseInfo work for classes with EmptyScopes
Fixes #19506
1 parent 1716bcd commit 8d9af0c

File tree

4 files changed

+30
-19
lines changed

4 files changed

+30
-19
lines changed

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

+17-9
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,27 @@ object Scopes {
159159
}
160160

161161
/** The scope that keeps only those symbols from this scope that match the
162-
* given predicates. If all symbols match, returns the scope itself, otherwise
163-
* a copy with the matching symbols.
162+
* given predicates, renamed with the given rename function.
163+
* If all symbols match and none are renamed, returns the scope itself, otherwise
164+
* a copy with the matching and renamed symbols.
164165
*/
165-
final def filteredScope(p: Symbol => Boolean)(using Context): Scope = {
166+
final def filteredScope(
167+
keep: Symbol => Boolean,
168+
rename: (Symbol, Name) => Name = (_, name) => name)(using Context): Scope =
166169
var result: MutableScope | Null = null
167-
for (sym <- iterator)
168-
if (!p(sym)) {
169-
if (result == null) result = cloneScope
170+
for sym <- iterator do
171+
def drop() =
172+
if result == null then result = cloneScope
170173
result.nn.unlink(sym)
171-
}
174+
if keep(sym) then
175+
val newName = rename(sym, sym.name)
176+
if newName ne sym.name then
177+
drop()
178+
result.nn.enter(newName, sym)
179+
else
180+
drop()
172181
// TODO: improve flow typing to handle this case
173-
if (result == null) this else result.uncheckedNN
174-
}
182+
if result == null then this else result.uncheckedNN
175183

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

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

+9-9
Original file line numberDiff line numberDiff line change
@@ -725,14 +725,13 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
725725
tr1 :: trs1.filterNot(_.isAnyRef)
726726
case nil => nil
727727
}
728-
var erasedDecls = decls.filteredScope(sym => !sym.isType || sym.isClass).openForMutations
729-
for dcl <- erasedDecls.iterator do
730-
if dcl.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined
731-
&& dcl.targetName != dcl.name
732-
then
733-
if erasedDecls eq decls then erasedDecls = erasedDecls.cloneScope
734-
erasedDecls.unlink(dcl)
735-
erasedDecls.enter(dcl.targetName, dcl)
728+
val erasedDecls = decls.filteredScope(
729+
keep = sym => !sym.isType || sym.isClass,
730+
rename = (sym, name) =>
731+
if sym.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined
732+
then sym.targetName
733+
else name
734+
)
736735
val selfType1 = if cls.is(Module) then cls.sourceModule.termRef else NoType
737736
tp.derivedClassInfo(NoPrefix, erasedParents, erasedDecls, selfType1)
738737
// can't replace selftype by NoType because this would lose the sourceModule link
@@ -814,7 +813,8 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
814813
eraseResult(tp1.resultType) match
815814
case rt: MethodType => rt
816815
case rt => MethodType(Nil, Nil, rt)
817-
case tp1 => this(tp1)
816+
case tp1 =>
817+
this(tp1)
818818

819819
private def eraseDerivedValueClass(tp: Type)(using Context): Type = {
820820
val cls = tp.classSymbol.asClass

tests/neg/i19506.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//> using options "-source:3.4-migration",
1+
//> using options -source 3.4-migration
22

33
trait Reader[T]
44
def read[T: Reader](s: String, trace: Boolean = false): T = ???

tests/pos/i19530.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object A {
2+
def x = classOf[scala.Singleton]
3+
}

0 commit comments

Comments
 (0)