Skip to content

Commit edd518f

Browse files
committed
Make ParamRefs unique types.
They were case classes before, but not uniquely hashed. This meant that the hash cons sepcialization for AppliedTypes failed to work in many cases. since ParamRef arguments were not `eq` to each other. Consequently, we got timeouts for compiling stdlib.
1 parent 659177f commit edd518f

File tree

3 files changed

+36
-14
lines changed

3 files changed

+36
-14
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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 TypeParamRef.uncached(poly, 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(TypeParamRef.uncached(poly, i))) return false
472472
}
473473
true
474474
}

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

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2626,7 +2626,7 @@ object Types {
26262626
def paramNames: List[ThisName]
26272627
def paramInfos: List[PInfo]
26282628
def resType: Type
2629-
def newParamRef(n: Int): ParamRefType
2629+
def newParamRef(n: Int)(implicit ctx: Context): ParamRefType
26302630

26312631
override def resultType(implicit ctx: Context) = resType
26322632

@@ -2640,7 +2640,12 @@ object Types {
26402640
final def isTypeLambda = isInstanceOf[TypeLambda]
26412641
final def isHigherKinded = isInstanceOf[TypeProxy]
26422642

2643-
lazy val paramRefs: List[ParamRefType] = paramNames.indices.toList.map(newParamRef)
2643+
private var myParamRefs: List[ParamRefType] = null
2644+
2645+
def paramRefs(implicit ctx: Context): List[ParamRefType] = {
2646+
if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef)
2647+
myParamRefs
2648+
}
26442649

26452650
protected def computeSignature(implicit ctx: Context) = resultSignature
26462651

@@ -2801,7 +2806,7 @@ object Types {
28012806
*/
28022807
def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps
28032808

2804-
def newParamRef(n: Int) = TermParamRef(this, n)
2809+
def newParamRef(n: Int)(implicit ctx: Context) = TermParamRef(this, n)
28052810
}
28062811

28072812
abstract case class MethodType(paramNames: List[TermName])(
@@ -2956,7 +2961,7 @@ object Types {
29562961
def isDependent(implicit ctx: Context): Boolean = true
29572962
def isParamDependent(implicit ctx: Context): Boolean = true
29582963

2959-
def newParamRef(n: Int) = TypeParamRef(this, n)
2964+
def newParamRef(n: Int)(implicit ctx: Context) = TypeParamRef(this, n)
29602965

29612966
lazy val typeParams: List[LambdaParam] =
29622967
paramNames.indices.toList.map(new LambdaParam(this, _))
@@ -3114,7 +3119,7 @@ object Types {
31143119
def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo
31153120
def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo
31163121
def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance
3117-
def toArg: Type = TypeParamRef(tl, n)
3122+
def toArg(implicit ctx: Context): Type = TypeParamRef(tl, n)
31183123
def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n)
31193124
}
31203125

@@ -3328,7 +3333,7 @@ object Types {
33283333
abstract class BoundType extends CachedProxyType with ValueType {
33293334
type BT <: Type
33303335
val binder: BT
3331-
def copyBoundType(bt: BT): Type
3336+
def copyBoundType(bt: BT)(implicit ctx: Context): Type
33323337
}
33333338

33343339
abstract class ParamRef extends BoundType {
@@ -3357,14 +3362,21 @@ object Types {
33573362
}
33583363
}
33593364

3360-
case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef {
3365+
abstract case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef {
33613366
type BT = TermLambda
3362-
def copyBoundType(bt: BT) = TermParamRef(bt, paramNum)
3367+
def copyBoundType(bt: BT)(implicit ctx: Context) = TermParamRef(bt, paramNum)
3368+
}
3369+
3370+
class CachedTermParamRef(binder: TermLambda, paramNum: Int) extends TermParamRef(binder, paramNum)
3371+
3372+
object TermParamRef {
3373+
def apply(binder: TermLambda, paramNum: Int)(implicit ctx: Context) =
3374+
unique(new CachedTermParamRef(binder, paramNum))
33633375
}
33643376

3365-
case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef {
3377+
abstract case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef {
33663378
type BT = TypeLambda
3367-
def copyBoundType(bt: BT) = TypeParamRef(bt, paramNum)
3379+
def copyBoundType(bt: BT)(implicit ctx: Context) = TypeParamRef(bt, paramNum)
33683380

33693381
/** Looking only at the structure of `bound`, is one of the following true?
33703382
* - fromBelow and param <:< bound
@@ -3380,11 +3392,21 @@ object Types {
33803392
}
33813393
}
33823394

3395+
class ConcreteTypeParamRef(binder: TypeLambda, paramNum: Int) extends TypeParamRef(binder, paramNum)
3396+
3397+
object TypeParamRef {
3398+
def apply(binder: TypeLambda, paramNum: Int)(implicit ctx: Context) =
3399+
unique(new ConcreteTypeParamRef(binder, paramNum))
3400+
3401+
def uncached(binder: TypeLambda, paramNum: Int) =
3402+
new ConcreteTypeParamRef(binder: TypeLambda, paramNum: Int)
3403+
}
3404+
33833405
/** a self-reference to an enclosing recursive type. */
33843406
case class RecThis(binder: RecType) extends BoundType with SingletonType {
33853407
type BT = RecType
33863408
override def underlying(implicit ctx: Context) = binder
3387-
def copyBoundType(bt: BT) = RecThis(bt)
3409+
def copyBoundType(bt: BT)(implicit ctx: Context) = RecThis(bt)
33883410

33893411
// need to customize hashCode and equals to prevent infinite recursion
33903412
// between RecTypes and RecRefs.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
405405
def addTyped(arg: Arg, formal: Type): Type => Type = {
406406
addArg(typedArg(arg, formal), formal)
407407
if (methodType.isParamDependent)
408-
safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg))
408+
safeSubstParam(_, methodType.paramRefs.apply(n), typeOfArg(arg))
409409
else identity
410410
}
411411

0 commit comments

Comments
 (0)