Skip to content

Commit 4ad6460

Browse files
committed
Better packaging of nesting level checking
Encapsulate nesting level computation and make it more efficient.
1 parent 57c4982 commit 4ad6460

File tree

4 files changed

+37
-18
lines changed

4 files changed

+37
-18
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ final class ProperGadtConstraint private(
116116
)
117117

118118
val tvars = params.lazyZip(poly1.paramRefs).map { (sym, paramRef) =>
119-
val tv = new TypeVar(paramRef, creatorState = null, ctx.owner.ownersIterator.length)
119+
val tv = TypeVar(paramRef, creatorState = null)
120120
mapping = mapping.updated(sym, tv)
121121
reverseMapping = reverseMapping.updated(tv.origin, sym)
122122
tv

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,13 @@ object SymDenotations {
14501450
else if is(Contravariant) then Contravariant
14511451
else EmptyFlags
14521452

1453+
/** The length of the owner chain of this symbol. 0 for NoSymbol, 1 for _root_ */
1454+
def nestingLevel(using Context): Int =
1455+
@tailrec def recur(d: SymDenotation, n: Int): Int = d match
1456+
case d: ClassDenotation => d.nestingLevel + n // profit from the cache in ClassDenotation
1457+
case _ => recur(d.owner, n + 1)
1458+
recur(this, 0)
1459+
14531460
/** The flags to be used for a type parameter owned by this symbol.
14541461
* Overridden by ClassDenotation.
14551462
*/
@@ -2151,6 +2158,13 @@ object SymDenotations {
21512158

21522159
override def registeredCompanion(implicit ctx: Context) = { ensureCompleted(); myCompanion }
21532160
override def registeredCompanion_=(c: Symbol) = { myCompanion = c }
2161+
2162+
private var myNestingLevel = -1
2163+
2164+
override def nestingLevel(using Context) =
2165+
if myNestingLevel == -1 then
2166+
myNestingLevel = if maybeOwner.exists then maybeOwner.nestingLevel + 1 else 0
2167+
myNestingLevel
21542168
}
21552169

21562170
/** The denotation of a package class.

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

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4111,14 +4111,16 @@ object Types {
41114111
* @param origin The parameter that's tracked by the type variable.
41124112
* @param creatorState The typer state in which the variable was created.
41134113
*/
4114-
final class TypeVar(private var _origin: TypeParamRef, creatorState: TyperState, level: Int) extends CachedProxyType with ValueType {
4114+
final class TypeVar private(initOrigin: TypeParamRef, creatorState: TyperState, nestingLevel: Int) extends CachedProxyType with ValueType {
41154115

4116-
def origin: TypeParamRef = _origin
4116+
private var currentOrigin = initOrigin
4117+
4118+
def origin: TypeParamRef = currentOrigin
41174119

41184120
/** Set origin to new parameter. Called if we merge two conflicting constraints.
41194121
* See OrderingConstraint#merge, OrderingConstraint#rename
41204122
*/
4121-
def setOrigin(p: TypeParamRef) = _origin = p
4123+
def setOrigin(p: TypeParamRef) = currentOrigin = p
41224124

41234125
/** The permanent instance type of the variable, or NoType is none is given yet */
41244126
private var myInst: Type = NoType
@@ -4147,34 +4149,34 @@ object Types {
41474149
/** Is the variable already instantiated? */
41484150
def isInstantiated(implicit ctx: Context): Boolean = instanceOpt.exists
41494151

4150-
def hygienic(tp: Type)(using Context): Type =
4152+
def avoidCaptures(tp: Type)(using Context): Type =
41514153
val problemSyms = new TypeAccumulator[Set[Symbol]]:
41524154
def apply(syms: Set[Symbol], t: Type): Set[Symbol] = t match
41534155
case ref @ TermRef(NoPrefix, _)
4154-
if ref.symbol.maybeOwner.ownersIterator.length > level =>
4156+
if ref.symbol.maybeOwner.nestingLevel > nestingLevel =>
41554157
syms + ref.symbol
41564158
case _ =>
41574159
foldOver(syms, t)
41584160
val problems = problemSyms(Set.empty, tp)
41594161
if problems.isEmpty then tp
41604162
else
4161-
val htp = ctx.typer.avoid(tp, problems.toList)
4162-
val msg = i"Inaccessible variables captured by instance for $this.\n$tp was fixed to $htp"
4163+
val atp = ctx.typer.avoid(tp, problems.toList)
4164+
val msg = i"Inaccessible variables captured in instantation of type variable $this.\n$tp was fixed to $atp"
41634165
typr.println(msg)
41644166
val bound = ctx.typeComparer.fullUpperBound(origin)
4165-
if !(htp <:< bound) then
4166-
throw new TypeError(s"$msg,\nbut this does not conform to upper bound $bound")
4167-
htp
4167+
if !(atp <:< bound) then
4168+
throw new TypeError(s"$msg,\nbut the latter type does not conform to the upper bound $bound")
4169+
atp
41684170

41694171
/** Instantiate variable with given type */
41704172
def instantiateWith(tp: Type)(implicit ctx: Context): Type = {
41714173
assert(tp ne this, s"self instantiation of ${tp.show}, constraint = ${ctx.typerState.constraint.show}")
4172-
val htp = hygienic(tp)
4173-
typr.println(s"instantiating ${this.show} with ${htp.show}")
4174+
val atp = avoidCaptures(tp)
4175+
typr.println(s"instantiating ${this.show} with ${atp.show}")
41744176
if ((ctx.typerState eq owningState.get) && !ctx.typeComparer.subtypeCheckInProgress)
4175-
inst = htp
4176-
ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, htp)
4177-
htp
4177+
inst = atp
4178+
ctx.typerState.constraint = ctx.typerState.constraint.replace(origin, atp)
4179+
atp
41784180
}
41794181

41804182
/** Instantiate variable from the constraints over its `origin`.
@@ -4217,6 +4219,9 @@ object Types {
42174219
s"TypeVar($origin$instStr)"
42184220
}
42194221
}
4222+
object TypeVar:
4223+
def apply(initOrigin: TypeParamRef, creatorState: TyperState)(using Context) =
4224+
new TypeVar(initOrigin, creatorState, ctx.owner.nestingLevel)
42204225

42214226
type TypeVars = SimpleIdentitySet[TypeVar]
42224227

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,8 @@ object ProtoTypes {
501501
def newTypeVars(tl: TypeLambda): List[TypeTree] =
502502
for (paramRef <- tl.paramRefs)
503503
yield {
504-
val tt = new TypeVarBinder().withSpan(owningTree.span)
505-
val tvar = new TypeVar(paramRef, state, ctx.owner.ownersIterator.length)
504+
val tt = TypeVarBinder().withSpan(owningTree.span)
505+
val tvar = TypeVar(paramRef, state)
506506
state.ownedVars += tvar
507507
tt.withType(tvar)
508508
}

0 commit comments

Comments
 (0)