Skip to content

Commit f07d964

Browse files
committed
Make bound types be uniquely created by their binders
That way, we don't have to hash cons them.
1 parent 0075cf4 commit f07d964

File tree

11 files changed

+59
-40
lines changed

11 files changed

+59
-40
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ trait ConstraintHandling {
329329
checkPropagated(i"initialized $tl") {
330330
constraint = constraint.add(tl, tvars)
331331
tl.paramNames.indices.forall { i =>
332-
val param = TypeParamRef(tl, i)
332+
val param = tl.paramRefs(i)
333333
val bounds = constraint.nonParamBounds(param)
334334
val lower = constraint.lower(param)
335335
val upper = constraint.upper(param)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ class Definitions {
250250
lazy val Any_## = enterMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final)
251251
lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final)
252252
lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
253-
lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, TypeParamRef(_, 0), Final)
253+
lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, _.paramRefs(0), Final)
254254
lazy val Any_typeTest = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final | Synthetic)
255255
// generated by pattern matcher, eliminated by erasure
256256

@@ -278,7 +278,7 @@ class Definitions {
278278
lazy val Object_eq = enterMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
279279
lazy val Object_ne = enterMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
280280
lazy val Object_synchronized = enterPolyMethod(ObjectClass, nme.synchronized_, 1,
281-
pt => MethodType(List(TypeParamRef(pt, 0)), TypeParamRef(pt, 0)), Final)
281+
pt => MethodType(List(pt.paramRefs(0)), pt.paramRefs(0)), Final)
282282
lazy val Object_clone = enterMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected)
283283
lazy val Object_finalize = enterMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected)
284284
lazy val Object_notify = enterMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType))
@@ -295,7 +295,7 @@ class Definitions {
295295
*/
296296
lazy val cbnArg = enterPolyMethod(
297297
OpsPackageClass, nme.cbnArg, 1,
298-
pt => MethodType(List(FunctionOf(Nil, TypeParamRef(pt, 0))), TypeParamRef(pt, 0)))
298+
pt => MethodType(List(FunctionOf(Nil, pt.paramRefs(0))), pt.paramRefs(0)))
299299

300300
/** Method representing a throw */
301301
lazy val throwMethod = enterMethod(OpsPackageClass, nme.THROWkw,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
298298
val loBuf, hiBuf = new mutable.ListBuffer[TypeParamRef]
299299
var i = 0
300300
while (i < poly.paramNames.length) {
301-
val param = TypeParamRef(poly, i)
301+
val param = poly.paramRefs(i)
302302
val bounds = nonParamBounds(param)
303303
val lo = normalizedType(bounds.lo, loBuf, isUpper = false)
304304
val hi = normalizedType(bounds.hi, hiBuf, isUpper = true)
@@ -463,12 +463,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
463463
(poly, entries) <- boundsMap.toList
464464
n <- 0 until paramCount(entries)
465465
if entries(n).exists
466-
} yield TypeParamRef(poly, n)
466+
} yield poly.paramRefs(n)
467467

468468
def forallParams(p: TypeParamRef => Boolean): Boolean = {
469469
boundsMap.foreachBinding { (poly, entries) =>
470470
for (i <- 0 until paramCount(entries))
471-
if (isBounds(entries(i)) && !p(TypeParamRef(poly, i))) return false
471+
if (isBounds(entries(i)) && !p(poly.paramRefs(i))) return false
472472
}
473473
true
474474
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ object TypeApplications {
6464
}
6565

6666
def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match {
67-
case tp @ HKTypeLambda(tparams, AnyAppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn)
67+
case tp @ HKTypeLambda(tparams, AnyAppliedType(fn: TypeRef, args)) if (args == tparams.map(_.paramRef)) => Some(fn)
6868
case _ => None
6969
}
7070
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
434434
case tp2: RecType =>
435435
def compareRec = tp1.safeDealias match {
436436
case tp1: RecType =>
437-
val rthis1 = RecThis(tp1)
437+
val rthis1 = tp1.recThis
438438
isSubType(tp1.parent, tp2.parent.substRecThis(tp2, rthis1))
439439
case _ =>
440440
val tp1stable = ensureStableSingleton(tp1)
@@ -729,7 +729,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
729729
tycon1b = HKTypeLambda(tparams1.map(_.paramName))(
730730
tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds),
731731
tl => tycon1a.appliedTo(args1.take(lengthDiff) ++
732-
tparams1.indices.toList.map(TypeParamRef(tl, _))))
732+
tparams1.indices.toList.map(tl.paramRefs(_))))
733733
(ctx.mode.is(Mode.TypevarsMissContext) ||
734734
tryInstantiate(tycon2, tycon1b.ensureHK)) &&
735735
isSubType(tp1, tycon1b.appliedTo(args2))
@@ -885,7 +885,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
885885
tycon1 = HKTypeLambda(tparams1.map(_.paramName))(
886886
tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds),
887887
tl => tp1base.tycon.appliedTo(args1.take(lengthDiff) ++
888-
tparams1.indices.toList.map(TypeParamRef(tl, _))))
888+
tparams1.indices.toList.map(tl.paramRefs(_))))
889889
(ctx.mode.is(Mode.TypevarsMissContext) ||
890890
tryInstantiate(tycon2, tycon1.ensureHK)) &&
891891
isSubType(tp1, tycon1.appliedTo(args2))

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

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ object Types {
568568
val rt =
569569
if (tp.opened) { // defensive copy
570570
tp.openedTwice = true
571-
RecType(rt => tp.parent.substRecThis(tp, RecThis(rt)))
571+
RecType(rt => tp.parent.substRecThis(tp, rt.recThis))
572572
} else tp
573573
rt.opened = true
574574
try go(rt.parent).mapInfo(_.substRecThis(rt, pre))
@@ -2368,15 +2368,22 @@ object Types {
23682368

23692369
val parent = parentExp(this)
23702370

2371+
private[this] var myRecThis: RecThis = null
2372+
2373+
def recThis: RecThis = {
2374+
if (myRecThis == null) myRecThis = new RecThis(this) {}
2375+
myRecThis
2376+
}
2377+
23712378
override def underlying(implicit ctx: Context): Type = parent
23722379

23732380
def derivedRecType(parent: Type)(implicit ctx: Context): RecType =
23742381
if (parent eq this.parent) this
2375-
else RecType(rt => parent.substRecThis(this, RecThis(rt)))
2382+
else RecType(rt => parent.substRecThis(this, rt.recThis))
23762383

23772384
def rebind(parent: Type)(implicit ctx: Context): Type =
23782385
if (parent eq this.parent) this
2379-
else RecType.closeOver(rt => parent.substRecThis(this, RecThis(rt)))
2386+
else RecType.closeOver(rt => parent.substRecThis(this, rt.recThis))
23802387

23812388
override def equals(other: Any) = other match {
23822389
case other: RecType => other.parent == this.parent
@@ -2419,7 +2426,7 @@ object Types {
24192426
val rt = new RecType(parentExp)
24202427
def normalize(tp: Type): Type = tp.stripTypeVar match {
24212428
case tp: RecType =>
2422-
normalize(tp.parent.substRecThis(tp, RecThis(rt)))
2429+
normalize(tp.parent.substRecThis(tp, rt.recThis))
24232430
case tp @ RefinedType(parent, rname, rinfo) =>
24242431
val rinfo1 = rinfo match {
24252432
case TypeAlias(TypeRef(RecThis(`rt`), `rname`)) => TypeBounds.empty
@@ -2634,7 +2641,7 @@ object Types {
26342641
def paramNames: List[ThisName]
26352642
def paramInfos: List[PInfo]
26362643
def resType: Type
2637-
def newParamRef(n: Int): ParamRefType
2644+
protected def newParamRef(n: Int): ParamRefType
26382645

26392646
override def resultType(implicit ctx: Context) = resType
26402647

@@ -2648,7 +2655,12 @@ object Types {
26482655
final def isTypeLambda = isInstanceOf[TypeLambda]
26492656
final def isHigherKinded = isInstanceOf[TypeProxy]
26502657

2651-
lazy val paramRefs: List[ParamRefType] = paramNames.indices.toList.map(newParamRef)
2658+
private var myParamRefs: List[ParamRefType] = null
2659+
2660+
def paramRefs: List[ParamRefType] = {
2661+
if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef)
2662+
myParamRefs
2663+
}
26522664

26532665
protected def computeSignature(implicit ctx: Context) = resultSignature
26542666

@@ -2809,7 +2821,7 @@ object Types {
28092821
*/
28102822
def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps
28112823

2812-
def newParamRef(n: Int) = TermParamRef(this, n)
2824+
def newParamRef(n: Int) = new TermParamRef(this, n) {}
28132825
}
28142826

28152827
abstract case class MethodType(paramNames: List[TermName])(
@@ -2964,7 +2976,7 @@ object Types {
29642976
def isDependent(implicit ctx: Context): Boolean = true
29652977
def isParamDependent(implicit ctx: Context): Boolean = true
29662978

2967-
def newParamRef(n: Int) = TypeParamRef(this, n)
2979+
def newParamRef(n: Int) = new TypeParamRef(this, n) {}
29682980

29692981
lazy val typeParams: List[LambdaParam] =
29702982
paramNames.indices.toList.map(new LambdaParam(this, _))
@@ -3033,16 +3045,16 @@ object Types {
30333045
*/
30343046
def flatten(implicit ctx: Context): PolyType = resType match {
30353047
case that: PolyType =>
3036-
val shift = new TypeMap {
3048+
val shiftedSubst = (x: PolyType) => new TypeMap {
30373049
def apply(t: Type) = t match {
3038-
case TypeParamRef(`that`, n) => TypeParamRef(that, n + paramNames.length)
3050+
case TypeParamRef(`that`, n) => x.paramRefs(n + paramNames.length)
30393051
case t => mapOver(t)
30403052
}
30413053
}
30423054
PolyType(paramNames ++ that.paramNames)(
30433055
x => this.paramInfos.mapConserve(_.subst(this, x).bounds) ++
3044-
that.paramInfos.mapConserve(shift(_).subst(that, x).bounds),
3045-
x => shift(that.resultType).subst(that, x).subst(this, x))
3056+
that.paramInfos.mapConserve(shiftedSubst(x)(_).bounds),
3057+
x => shiftedSubst(x)(that.resultType).subst(this, x))
30463058
case _ => this
30473059
}
30483060

@@ -3122,8 +3134,7 @@ object Types {
31223134
def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo
31233135
def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo
31243136
def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance
3125-
def toArg: Type = TypeParamRef(tl, n)
3126-
def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n)
3137+
def paramRef(implicit ctx: Context): Type = tl.paramRefs(n)
31273138
}
31283139

31293140
/** A type application `C[T_1, ..., T_n]` */
@@ -3365,14 +3376,20 @@ object Types {
33653376
}
33663377
}
33673378

3368-
case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef {
3379+
/** Only created in `binder.paramRefs`. Use `binder.paramRefs(paramNum)` to
3380+
* refer to `TermParamRef(binder, paramNum)`.
3381+
*/
3382+
abstract case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef {
33693383
type BT = TermLambda
3370-
def copyBoundType(bt: BT) = TermParamRef(bt, paramNum)
3384+
def copyBoundType(bt: BT) = bt.paramRefs(paramNum)
33713385
}
33723386

3373-
case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef {
3387+
/** Only created in `binder.paramRefs`. Use `binder.paramRefs(paramNum)` to
3388+
* refer to `TypeParamRef(binder, paramNum)`.
3389+
*/
3390+
abstract case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef {
33743391
type BT = TypeLambda
3375-
def copyBoundType(bt: BT) = TypeParamRef(bt, paramNum)
3392+
def copyBoundType(bt: BT) = bt.paramRefs(paramNum)
33763393

33773394
/** Looking only at the structure of `bound`, is one of the following true?
33783395
* - fromBelow and param <:< bound
@@ -3388,11 +3405,13 @@ object Types {
33883405
}
33893406
}
33903407

3391-
/** a self-reference to an enclosing recursive type. */
3392-
case class RecThis(binder: RecType) extends BoundType with SingletonType {
3408+
/** a self-reference to an enclosing recursive type. The only creation method is
3409+
* `binder.recThis`, returning `RecThis(binder)`.
3410+
*/
3411+
abstract case class RecThis(binder: RecType) extends BoundType with SingletonType {
33933412
type BT = RecType
33943413
override def underlying(implicit ctx: Context) = binder
3395-
def copyBoundType(bt: BT) = RecThis(bt)
3414+
def copyBoundType(bt: BT) = bt.recThis
33963415

33973416
// need to customize hashCode and equals to prevent infinite recursion
33983417
// between RecTypes and RecRefs.

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
262262
readMethodic(HKTypeLambda, _.toTypeName)
263263
case PARAMtype =>
264264
readTypeRef() match {
265-
case binder: LambdaType => binder.newParamRef(readNat())
265+
case binder: LambdaType => binder.paramRefs(readNat())
266266
}
267267
case CLASSconst =>
268268
ConstantType(Constant(readType()))
@@ -295,7 +295,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
295295
case RECtype =>
296296
RecType(rt => registeringType(rt, readType()))
297297
case RECthis =>
298-
RecThis(readTypeRef().asInstanceOf[RecType])
298+
readTypeRef().asInstanceOf[RecType].recThis
299299
case SHARED =>
300300
val ref = readAddr()
301301
typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType())

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
767767
if (decls.isEmpty) parent
768768
else {
769769
def subst(info: Type, rt: RecType) =
770-
if (clazz.isClass) info.substThis(clazz.asClass, RecThis(rt))
770+
if (clazz.isClass) info.substThis(clazz.asClass, rt.recThis)
771771
else info // turns out some symbols read into `clazz` are not classes, not sure why this is the case.
772772
def addRefinement(tp: Type, sym: Symbol) = RefinedType(tp, sym.name, sym.info)
773773
val refined = (parent /: decls.toList)(addRefinement)

compiler/src/dotty/tools/dotc/transform/FullParameterization.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ trait FullParameterization {
113113
/** Replace class type parameters by the added type parameters of the polytype `pt` */
114114
def mapClassParams(tp: Type, pt: PolyType): Type = {
115115
val classParamsRange = (mtparamCount until mtparamCount + ctparams.length).toList
116-
tp.substDealias(ctparams, classParamsRange map (TypeParamRef(pt, _)))
116+
tp.substDealias(ctparams, classParamsRange map (pt.paramRefs(_)))
117117
}
118118

119119
/** The bounds for the added type parameters of the polytype `pt` */

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ object ProtoTypes {
391391
for (n <- (0 until tl.paramNames.length).toList)
392392
yield {
393393
val tt = new TypeTree().withPos(owningTree.pos)
394-
tt.withType(new TypeVar(TypeParamRef(tl, n), state, tt, ctx.owner))
394+
tt.withType(new TypeVar(tl.paramRefs(n), state, tt, ctx.owner))
395395
}
396396

397397
val added =

compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ trait TypeAssigner {
6363
parent
6464
}
6565

66-
def close(tp: Type) = RecType.closeOver(rt => tp.substThis(cls, RecThis(rt)))
66+
def close(tp: Type) = RecType.closeOver(rt => tp.substThis(cls, rt.recThis))
6767

6868
val refinableDecls = info.decls.filter(
6969
sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor))
@@ -381,7 +381,7 @@ trait TypeAssigner {
381381
val newIndex = gapBuf.length
382382
gapBuf += idx
383383
// Re-index unassigned type arguments that remain after transformation
384-
TypeParamRef(pt, newIndex)
384+
pt.paramRefs(newIndex)
385385
}
386386

387387
// Type parameters after naming assignment, conserving paramNames order
@@ -485,7 +485,7 @@ trait TypeAssigner {
485485
else RefinedType(parent, rsym.name, rinfo)
486486
}
487487
val refined = (parent.tpe /: refinements)(addRefinement)
488-
tree.withType(RecType.closeOver(rt => refined.substThis(refineCls, RecThis(rt))))
488+
tree.withType(RecType.closeOver(rt => refined.substThis(refineCls, rt.recThis)))
489489
}
490490

491491
def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = {

0 commit comments

Comments
 (0)