From 8d9af0cd6778f10ca85ef2e80d29ee018ac6f8cb Mon Sep 17 00:00:00 2001 From: odersky Date: Sat, 27 Jan 2024 16:47:48 +0100 Subject: [PATCH 1/5] Make eraseInfo work for classes with EmptyScopes Fixes #19506 --- .../src/dotty/tools/dotc/core/Scopes.scala | 26 ++++++++++++------- .../dotty/tools/dotc/core/TypeErasure.scala | 18 ++++++------- tests/neg/i19506.scala | 2 +- tests/pos/i19530.scala | 3 +++ 4 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 tests/pos/i19530.scala diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 7df5a7fa3c09..6e8adc0633b0 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -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) => Name = (_, name) => name)(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, sym.name) + if newName ne sym.name 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 diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 48559787c6a1..2916b39ace6e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -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, name) => + if sym.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined + then sym.targetName + else name + ) 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 @@ -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 diff --git a/tests/neg/i19506.scala b/tests/neg/i19506.scala index 0d3f9770a7ae..1b877a0bae7d 100644 --- a/tests/neg/i19506.scala +++ b/tests/neg/i19506.scala @@ -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 = ??? diff --git a/tests/pos/i19530.scala b/tests/pos/i19530.scala new file mode 100644 index 000000000000..01c3cc50a12d --- /dev/null +++ b/tests/pos/i19530.scala @@ -0,0 +1,3 @@ +object A { + def x = classOf[scala.Singleton] +} \ No newline at end of file From 7fd99b689506f42d0ee34f9093d211e504b4afee Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 28 Jan 2024 20:29:46 +0100 Subject: [PATCH 2/5] Update compiler/src/dotty/tools/dotc/core/Scopes.scala --- compiler/src/dotty/tools/dotc/core/Scopes.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 6e8adc0633b0..939f1e8fb371 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -173,7 +173,7 @@ object Scopes { result.nn.unlink(sym) if keep(sym) then val newName = rename(sym, sym.name) - if newName ne sym.name then + if newName != sym.name then drop() result.nn.enter(newName, sym) else From cb1d50fd2c1bbbfabb94ac362a66625ff3f40507 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 29 Jan 2024 14:34:53 +0100 Subject: [PATCH 3/5] Do not use the name of a symbol when not needed. --- compiler/src/dotty/tools/dotc/core/Scopes.scala | 6 +++--- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 939f1e8fb371..944d9bd37d43 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -165,15 +165,15 @@ object Scopes { */ final def filteredScope( keep: Symbol => Boolean, - rename: (Symbol, Name) => Name = (_, name) => name)(using Context): Scope = + rename: Symbol => Name | Null = _ => null)(using Context): Scope = var result: MutableScope | Null = null for sym <- iterator do def drop() = if result == null then result = cloneScope result.nn.unlink(sym) if keep(sym) then - val newName = rename(sym, sym.name) - if newName != sym.name then + val newName = rename(sym) + if newName != null then drop() result.nn.enter(newName, sym) else diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 2916b39ace6e..56f0eb045dc5 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -727,10 +727,10 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst } val erasedDecls = decls.filteredScope( keep = sym => !sym.isType || sym.isClass, - rename = (sym, name) => + rename = sym => if sym.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined then sym.targetName - else name + else null ) val selfType1 = if cls.is(Module) then cls.sourceModule.termRef else NoType tp.derivedClassInfo(NoPrefix, erasedParents, erasedDecls, selfType1) From 64319eb19b0be91835bde14f5081cc078a9437bf Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 29 Jan 2024 16:23:49 +0100 Subject: [PATCH 4/5] Add a missing condition back. --- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 56f0eb045dc5..0474aff4087a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -729,6 +729,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst keep = sym => !sym.isType || sym.isClass, rename = sym => if sym.lastKnownDenotation.unforcedAnnotation(defn.TargetNameAnnot).isDefined + && sym.targetName != sym.name then sym.targetName else null ) From b23da16699b389abd8059d78466b13e35192419e Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 29 Jan 2024 16:29:24 +0100 Subject: [PATCH 5/5] Add a comment for the default value of the rename function. --- compiler/src/dotty/tools/dotc/core/Scopes.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/src/dotty/tools/dotc/core/Scopes.scala b/compiler/src/dotty/tools/dotc/core/Scopes.scala index 944d9bd37d43..d6387ea1fe46 100644 --- a/compiler/src/dotty/tools/dotc/core/Scopes.scala +++ b/compiler/src/dotty/tools/dotc/core/Scopes.scala @@ -160,6 +160,7 @@ object Scopes { /** The scope that keeps only those symbols from this scope that match the * given predicates, renamed with the given rename function. + * If renaming is not needed for a symbol, the rename function should return `null`. * If all symbols match and none are renamed, returns the scope itself, otherwise * a copy with the matching and renamed symbols. */