Skip to content

Commit 7c542fc

Browse files
committed
Fix #9965: Properly handle class type parameters when copying symbols
1 parent 2a32d6a commit 7c542fc

File tree

3 files changed

+56
-14
lines changed

3 files changed

+56
-14
lines changed

compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc
33
package ast
44

55
import core._
6-
import Types._, Contexts._
6+
import Types._, Contexts._, Flags._
77
import Symbols._, Annotations._, Trees._, Symbols._, Constants.Constant
88
import Decorators._
99
import dotty.tools.dotc.transform.SymUtils._
@@ -187,11 +187,18 @@ class TreeTypeMap(
187187
*/
188188
def withMappedSyms(syms: List[Symbol], mapped: List[Symbol]): TreeTypeMap = {
189189
val symsChanged = syms ne mapped
190-
val substMap = withSubstitution(syms, mapped)
190+
val origTypeParams = syms.filter(_.isClass).flatMap(_.typeParams)
191+
val mappedTypeParams = mapped.filter(_.isClass).flatMap(_.typeParams)
192+
assert(origTypeParams.hasSameLengthAs(mappedTypeParams))
193+
val substMap = withSubstitution(syms ++ origTypeParams, mapped ++ mappedTypeParams)
191194
val fullMap = mapped.filter(_.isClass).foldLeft(substMap) { (tmap, cls) =>
192-
val origDcls = cls.info.decls.toList
195+
val origDcls = cls.info.decls.toList.filterNot(_.is(TypeParam))
193196
val mappedDcls = mapSymbols(origDcls, tmap)
194-
val tmap1 = tmap.withMappedSyms(origDcls, mappedDcls)
197+
// type parameters were already copied in the `mapSymbols` call which produced `mapped`.
198+
val tmap1 = tmap
199+
// .withSubstitution(origTypeParams, cls.typeParams)
200+
// type parameters were already mapped in the `mapSymbols` call which produced `mapped`.
201+
.withMappedSyms(origDcls, mappedDcls)
195202
if (symsChanged)
196203
origDcls.lazyZip(mappedDcls).foreach(cls.asClass.replace)
197204
tmap1

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

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -811,22 +811,38 @@ object Symbols {
811811
val ttmap1 = ttmap.withSubstitution(originals, copies)
812812
originals.lazyZip(copies) foreach { (original, copy) =>
813813
val odenot = original.denot
814-
val oinfo = original.info match {
815-
case ClassInfo(pre, _, parents, decls, selfInfo) =>
816-
assert(original.isClass)
817-
ClassInfo(pre, copy.asClass, parents, decls.cloneScope, selfInfo)
818-
case oinfo => oinfo
819-
}
814+
val completer = new LazyType:
815+
816+
def complete(denot: SymDenotation)(using Context): Unit =
817+
818+
val oinfo = original.info match
819+
case ClassInfo(pre, _, parents, decls, selfInfo) =>
820+
assert(original.isClass)
821+
val otypeParams = original.typeParams
822+
if otypeParams.isEmpty then
823+
ClassInfo(pre, copy.asClass, parents, decls.cloneScope, selfInfo)
824+
else
825+
// copy type params, enter other definitions unchanged
826+
// type parameters need to be copied early, since other type
827+
// computations depend on them.
828+
val decls1 = newScope
829+
val newTypeParams = mapSymbols(original.typeParams, ttmap1, mapAlways = true)
830+
newTypeParams.foreach(decls1.enter)
831+
for sym <- decls do if !sym.is(TypeParam) then decls1.enter(sym)
832+
val parents1 = parents.map(_.substSym(otypeParams, newTypeParams))
833+
val selfInfo1 = selfInfo match
834+
case selfInfo: Type => selfInfo.substSym(otypeParams, newTypeParams)
835+
case _ => selfInfo
836+
ClassInfo(pre, copy.asClass, parents1, decls1, selfInfo1)
837+
case oinfo => oinfo
820838

821-
val completer = new LazyType {
822-
def complete(denot: SymDenotation)(using Context): Unit = {
823839
denot.info = oinfo // needed as otherwise we won't be able to go from Sym -> parents & etc
824840
// Note that this is a hack, but hack commonly used in Dotty
825841
// The same thing is done by other completers all the time
826842
denot.info = ttmap1.mapType(oinfo)
827843
denot.annotations = odenot.annotations.mapConserve(ttmap1.apply)
828-
}
829-
}
844+
845+
end completer
830846

831847
copy.denot = odenot.copySymDenotation(
832848
symbol = copy,

tests/pos/i9965.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class D[T]
2+
3+
class C {
4+
def f() = {
5+
locally {
6+
class dd[U] extends D[U] {
7+
val xx = 1
8+
}
9+
class ee[V] extends dd[(V, V)]
10+
def d[V]: dd[V] = new dd[V]
11+
g[D[Int]](d[Int])
12+
g[D[(Int, Int)]](new ee[Int])
13+
}
14+
}
15+
16+
inline def locally[T](inline body: T): T = body
17+
18+
def g[T](x: T): T = x
19+
}

0 commit comments

Comments
 (0)