Skip to content

Commit 4c76d89

Browse files
authored
Merge pull request #9617 from dotty-staging/various-opts
Some smaller optimizations and refactorings
2 parents ff0d485 + cc8a73e commit 4c76d89

8 files changed

+88
-78
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ abstract class Constraint extends Showable {
121121
/** A new constraint with entry `tl` renamed to a fresh type lambda */
122122
def rename(tl: TypeLambda)(using Context): This
123123

124+
/** Gives for each instantiated type var that does not yet have its `inst` field
125+
* set, the instance value stored in the constraint. Storing instances in constraints
126+
* is done only in a temporary way for contexts that may be retracted
127+
* without also retracting the type var as a whole.
128+
*/
129+
def instType(tvar: TypeVar): Type
130+
124131
/** The given `tl` in case it is not contained in this constraint,
125132
* a fresh copy of `tl` otherwise.
126133
*/

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

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,6 @@ trait ConstraintHandling {
6161
assert(homogenizeArgs == false)
6262
assert(comparedTypeLambdas == Set.empty)
6363

64-
/** Gives for each instantiated type var that does not yet have its `inst` field
65-
* set, the instance value stored in the constraint. Storing instances in constraints
66-
* is done only in a temporary way for contexts that may be retracted
67-
* without also retracting the type var as a whole.
68-
*/
69-
def instType(tvar: TypeVar): Type = constraint.entry(tvar.origin) match {
70-
case _: TypeBounds => NoType
71-
case tp: TypeParamRef =>
72-
var tvar1 = constraint.typeVarOfParam(tp)
73-
if (tvar1.exists) tvar1 else tp
74-
case tp => tp
75-
}
76-
7764
def nonParamBounds(param: TypeParamRef)(using Context): TypeBounds = constraint.nonParamBounds(param)
7865

7966
def fullLowerBound(param: TypeParamRef)(using Context): Type =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ final class ProperGadtConstraint private(
131131
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(using Context): Boolean = {
132132
@annotation.tailrec def stripInternalTypeVar(tp: Type): Type = tp match {
133133
case tv: TypeVar =>
134-
val inst = instType(tv)
134+
val inst = constraint.instType(tv)
135135
if (inst.exists) stripInternalTypeVar(inst) else tv
136136
case _ => tp
137137
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,11 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
530530
current.checkNonCyclic()
531531
}
532532

533+
def instType(tvar: TypeVar): Type = entry(tvar.origin) match
534+
case _: TypeBounds => NoType
535+
case tp: TypeParamRef => typeVarOfParam(tp).orElse(tp)
536+
case tp => tp
537+
533538
def ensureFresh(tl: TypeLambda)(using Context): TypeLambda =
534539
if (contains(tl)) {
535540
var paramInfos = tl.paramInfos

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2589,9 +2589,6 @@ object TypeComparer {
25892589
def subtypeCheckInProgress(using Context): Boolean =
25902590
comparing(_.subtypeCheckInProgress)
25912591

2592-
def instType(tvar: TypeVar)(using Context): Type =
2593-
comparing(_.instType(tvar))
2594-
25952592
def instanceType(param: TypeParamRef, fromBelow: Boolean)(using Context): Type =
25962593
comparing(_.instanceType(param, fromBelow))
25972594

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

Lines changed: 63 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -529,74 +529,79 @@ object TypeOps:
529529
val skolemizedArgTypes = skolemizeWildcardArgs(argTypes, app)
530530
val violations = new mutable.ListBuffer[BoundsViolation]
531531

532-
for ((arg, bounds) <- args zip boundss) {
533-
def checkOverlapsBounds(lo: Type, hi: Type): Unit = {
534-
//println(i" = ${instantiate(bounds.hi, argTypes)}")
535-
536-
var checkCtx = ctx // the context to be used for bounds checking
537-
if (argTypes ne skolemizedArgTypes) { // some of the arguments are wildcards
538-
539-
/** Is there a `LazyRef(TypeRef(_, sym))` reference in `tp`? */
540-
def isLazyIn(sym: Symbol, tp: Type): Boolean = {
541-
def isReference(tp: Type) = tp match {
542-
case tp: LazyRef => tp.ref.isInstanceOf[TypeRef] && tp.ref.typeSymbol == sym
543-
case _ => false
544-
}
545-
tp.existsPart(isReference, forceLazy = false)
546-
}
532+
def checkOverlapsBounds(lo: Type, hi: Type, arg: Tree, bounds: TypeBounds): Unit = {
533+
//println(i" = ${instantiate(bounds.hi, argTypes)}")
547534

548-
/** The argument types of the form `TypeRef(_, sym)` which appear as a LazyRef in `bounds`.
549-
* This indicates that the application is used as an F-bound for the symbol referred to in the LazyRef.
550-
*/
551-
val lazyRefs = skolemizedArgTypes collect {
552-
case tp: TypeRef if isLazyIn(tp.symbol, bounds) => tp.symbol
553-
}
535+
var checkCtx = ctx // the context to be used for bounds checking
536+
if (argTypes ne skolemizedArgTypes) { // some of the arguments are wildcards
554537

555-
for (sym <- lazyRefs) {
556-
557-
// If symbol `S` has an F-bound such as `C[?, S]` that contains wildcards,
558-
// add a modifieed bound where wildcards are skolemized as a GADT bound for `S`.
559-
// E.g. for `C[?, S]` we would add `C[C[?, S]#T0, S]` where `T0` is the first
560-
// type parameter of `C`. The new bound is added as a GADT bound for `S` in
561-
// `checkCtx`.
562-
// This mirrors what we do for the bounds that are checked and allows us thus
563-
// to bounds-check F-bounds with wildcards. A test case is pos/i6146.scala.
564-
565-
def massage(tp: Type): Type = tp match {
566-
case tp @ AppliedType(tycon, args) =>
567-
tp.derivedAppliedType(tycon, skolemizeWildcardArgs(args, tp))
568-
case tp: AndOrType =>
569-
tp.derivedAndOrType(massage(tp.tp1), massage(tp.tp2))
570-
case _ => tp
571-
}
572-
def narrowBound(bound: Type, fromBelow: Boolean): Unit = {
573-
val bound1 = massage(bound)
574-
if (bound1 ne bound) {
575-
if (checkCtx eq ctx) checkCtx = ctx.fresh.setFreshGADTBounds
576-
if (!checkCtx.gadt.contains(sym)) checkCtx.gadt.addToConstraint(sym)
577-
checkCtx.gadt.addBound(sym, bound1, fromBelow)
578-
typr.println("install GADT bound $bound1 for when checking F-bounded $sym")
579-
}
580-
}
581-
narrowBound(sym.info.loBound, fromBelow = true)
582-
narrowBound(sym.info.hiBound, fromBelow = false)
538+
/** Is there a `LazyRef(TypeRef(_, sym))` reference in `tp`? */
539+
def isLazyIn(sym: Symbol, tp: Type): Boolean = {
540+
def isReference(tp: Type) = tp match {
541+
case tp: LazyRef => tp.ref.isInstanceOf[TypeRef] && tp.ref.typeSymbol == sym
542+
case _ => false
583543
}
544+
tp.existsPart(isReference, forceLazy = false)
584545
}
585546

586-
val hiBound = instantiate(bounds.hi, skolemizedArgTypes)
587-
val loBound = instantiate(bounds.lo, skolemizedArgTypes)
547+
/** The argument types of the form `TypeRef(_, sym)` which appear as a LazyRef in `bounds`.
548+
* This indicates that the application is used as an F-bound for the symbol referred to in the LazyRef.
549+
*/
550+
val lazyRefs = skolemizedArgTypes collect {
551+
case tp: TypeRef if isLazyIn(tp.symbol, bounds) => tp.symbol
552+
}
588553

589-
def check(using Context) = {
590-
if (!(lo <:< hiBound)) violations += ((arg, "upper", hiBound))
591-
if (!(loBound <:< hi)) violations += ((arg, "lower", loBound))
554+
for (sym <- lazyRefs) {
555+
556+
// If symbol `S` has an F-bound such as `C[?, S]` that contains wildcards,
557+
// add a modifieed bound where wildcards are skolemized as a GADT bound for `S`.
558+
// E.g. for `C[?, S]` we would add `C[C[?, S]#T0, S]` where `T0` is the first
559+
// type parameter of `C`. The new bound is added as a GADT bound for `S` in
560+
// `checkCtx`.
561+
// This mirrors what we do for the bounds that are checked and allows us thus
562+
// to bounds-check F-bounds with wildcards. A test case is pos/i6146.scala.
563+
564+
def massage(tp: Type): Type = tp match {
565+
case tp @ AppliedType(tycon, args) =>
566+
tp.derivedAppliedType(tycon, skolemizeWildcardArgs(args, tp))
567+
case tp: AndOrType =>
568+
tp.derivedAndOrType(massage(tp.tp1), massage(tp.tp2))
569+
case _ => tp
570+
}
571+
def narrowBound(bound: Type, fromBelow: Boolean): Unit = {
572+
val bound1 = massage(bound)
573+
if (bound1 ne bound) {
574+
if (checkCtx eq ctx) checkCtx = ctx.fresh.setFreshGADTBounds
575+
if (!checkCtx.gadt.contains(sym)) checkCtx.gadt.addToConstraint(sym)
576+
checkCtx.gadt.addBound(sym, bound1, fromBelow)
577+
typr.println("install GADT bound $bound1 for when checking F-bounded $sym")
578+
}
579+
}
580+
narrowBound(sym.info.loBound, fromBelow = true)
581+
narrowBound(sym.info.hiBound, fromBelow = false)
592582
}
593-
check(using checkCtx)
594583
}
595-
arg.tpe match {
596-
case TypeBounds(lo, hi) => checkOverlapsBounds(lo, hi)
597-
case tp => checkOverlapsBounds(tp, tp)
584+
val hiBound = instantiate(bounds.hi, skolemizedArgTypes)
585+
val loBound = instantiate(bounds.lo, skolemizedArgTypes)
586+
587+
def check(using Context) = {
588+
if (!(lo <:< hiBound)) violations += ((arg, "upper", hiBound))
589+
if (!(loBound <:< hi)) violations += ((arg, "lower", loBound))
598590
}
591+
check(using checkCtx)
599592
}
593+
594+
def loop(args: List[Tree], boundss: List[TypeBounds]): Unit = args match
595+
case arg :: args1 => boundss match
596+
case bounds :: boundss1 =>
597+
arg.tpe match
598+
case TypeBounds(lo, hi) => checkOverlapsBounds(lo, hi, arg, bounds)
599+
case tp => checkOverlapsBounds(tp, tp, arg, bounds)
600+
loop(args1, boundss1)
601+
case _ =>
602+
case _ =>
603+
604+
loop(args, boundss)
600605
violations.toList
601606
}
602607

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,11 @@ class TyperState() {
138138
* no-longer needed constraint entries.
139139
*/
140140
def gc()(using Context): Unit = {
141+
Stats.record("typerState.gc")
141142
val toCollect = new mutable.ListBuffer[TypeLambda]
142143
constraint foreachTypeVar { tvar =>
143144
if (!tvar.inst.exists) {
144-
val inst = TypeComparer.instType(tvar)
145+
val inst = constraint.instType(tvar)
145146
if (inst.exists && (tvar.owningState.get eq this)) {
146147
tvar.inst = inst
147148
val lam = tvar.origin.binder

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,8 +3213,16 @@ object Types {
32133213
else newLikeThis(paramNames, paramInfos, resType)
32143214

32153215
def newLikeThis(paramNames: List[ThisName], paramInfos: List[PInfo], resType: Type)(using Context): This =
3216+
def substParams(pinfos: List[PInfo], to: This): List[PInfo] = pinfos match
3217+
case pinfo :: rest =>
3218+
val pinfo1 = pinfo.subst(this, to).asInstanceOf[PInfo]
3219+
val rest1 = substParams(rest, to)
3220+
if (pinfo1 eq pinfo) && (rest1 eq rest) then pinfos
3221+
else pinfo1 :: rest1
3222+
case nil =>
3223+
nil
32163224
companion(paramNames)(
3217-
x => paramInfos.mapConserve(_.subst(this, x).asInstanceOf[PInfo]),
3225+
x => substParams(paramInfos, x),
32183226
x => resType.subst(this, x))
32193227

32203228
protected def prefixString: String
@@ -4186,7 +4194,7 @@ object Types {
41864194
* uninstantiated
41874195
*/
41884196
def instanceOpt(using Context): Type =
4189-
if (inst.exists) inst else TypeComparer.instType(this)
4197+
if (inst.exists) inst else ctx.typerState.constraint.instType(this)
41904198

41914199
/** Is the variable already instantiated? */
41924200
def isInstantiated(using Context): Boolean = instanceOpt.exists

0 commit comments

Comments
 (0)