Skip to content

Commit 8b430a2

Browse files
Merge pull request #10915 from dotty-staging/fix-#9965
Fix #9965: Properly handle class type parameters when copying symbols
2 parents b7e907a + 1687717 commit 8b430a2

File tree

3 files changed

+61
-26
lines changed

3 files changed

+61
-26
lines changed

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

Lines changed: 16 additions & 16 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._
@@ -178,25 +178,25 @@ class TreeTypeMap(
178178
* and return a treemap that contains the substitution
179179
* between original and mapped symbols.
180180
*/
181-
def withMappedSyms(syms: List[Symbol], mapAlways: Boolean = false): TreeTypeMap =
182-
withMappedSyms(syms, mapSymbols(syms, this, mapAlways))
181+
def withMappedSyms(syms: List[Symbol]): TreeTypeMap =
182+
withMappedSyms(syms, mapSymbols(syms, this))
183183

184184
/** The tree map with the substitution between originals `syms`
185185
* and mapped symbols `mapped`. Also goes into mapped classes
186186
* and substitutes their declarations.
187187
*/
188-
def withMappedSyms(syms: List[Symbol], mapped: List[Symbol]): TreeTypeMap = {
189-
val symsChanged = syms ne mapped
190-
val substMap = withSubstitution(syms, mapped)
191-
val fullMap = mapped.filter(_.isClass).foldLeft(substMap) { (tmap, cls) =>
192-
val origDcls = cls.info.decls.toList
193-
val mappedDcls = mapSymbols(origDcls, tmap)
194-
val tmap1 = tmap.withMappedSyms(origDcls, mappedDcls)
195-
if (symsChanged)
188+
def withMappedSyms(syms: List[Symbol], mapped: List[Symbol]): TreeTypeMap =
189+
if syms eq mapped then this
190+
else
191+
val substMap = withSubstitution(syms, mapped)
192+
lazy val origCls = mapped.zip(syms).filter(_._1.isClass).toMap
193+
mapped.filter(_.isClass).foldLeft(substMap) { (tmap, cls) =>
194+
val origDcls = cls.info.decls.toList.filterNot(_.is(TypeParam))
195+
val mappedDcls = mapSymbols(origDcls, tmap, mapAlways = true)
196+
val tmap1 = tmap.withMappedSyms(
197+
origCls(cls).typeParams ::: origDcls,
198+
cls.typeParams ::: mappedDcls)
196199
origDcls.lazyZip(mappedDcls).foreach(cls.asClass.replace)
197-
tmap1
198-
}
199-
if (symsChanged || (fullMap eq substMap)) fullMap
200-
else withMappedSyms(syms, mapAlways = true)
201-
}
200+
tmap1
201+
}
202202
}

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)