Skip to content

Commit d65148b

Browse files
author
Aleksander Boruch-Gruszecki
committed
TVar based implementation
1 parent bd650dc commit d65148b

File tree

6 files changed

+95
-19
lines changed

6 files changed

+95
-19
lines changed

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ import config.Printers.{constr, typr}
2020
*/
2121
trait ConstraintHandling {
2222

23-
implicit val ctx: Context
23+
implicit def ctx: Context
2424

2525
protected def isSubType(tp1: Type, tp2: Type): Boolean
2626
protected def isSameType(tp1: Type, tp2: Type): Boolean
2727

28-
val state: TyperState
29-
import state.constraint
28+
// val state: TyperState
29+
protected def constraint: Constraint
30+
protected def constraint_=(c: Constraint): Unit
3031

3132
private[this] var addConstraintInvocations = 0
3233

@@ -98,7 +99,7 @@ trait ConstraintHandling {
9899
}
99100
}
100101

101-
private def location(implicit ctx: Context) = "" // i"in ${ctx.typerState.stateChainStr}" // use for debugging
102+
private def location(implicit ctx: Context) = i"in ${ctx.typerState.stateChainStr}" // use for debugging
102103

103104
protected def addUpperBound(param: TypeParamRef, bound: Type): Boolean = {
104105
def description = i"constraint $param <: $bound to\n$constraint"

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

+82-8
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ object Contexts {
480480
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
481481
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
482482
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
483-
def setFreshGADTBounds: this.type = setGadt(new GADTMap(gadt.bounds))
483+
def setFreshGADTBounds: this.type = setGadt(gadt.derived)
484484
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
485485
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
486486
private def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type = { this.moreProperties = moreProperties; this }
@@ -708,14 +708,88 @@ object Contexts {
708708
else assert(thread == Thread.currentThread(), "illegal multithreaded access to ContextBase")
709709
}
710710

711-
class GADTMap(initBounds: SimpleIdentityMap[Symbol, TypeBounds]) {
712-
private[this] var myBounds = initBounds
713-
def setBounds(sym: Symbol, b: TypeBounds): Unit =
714-
myBounds = myBounds.updated(sym, b)
715-
def bounds: SimpleIdentityMap[Symbol, TypeBounds] = myBounds
711+
sealed abstract class GADTMap {
712+
def setBounds(sym: Symbol, b: TypeBounds)(implicit ctx: Context): Unit
713+
def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds
714+
def contains(sym: Symbol)(implicit ctx: Context): Boolean
715+
def derived: GADTMap
716716
}
717717

718-
@sharable object EmptyGADTMap extends GADTMap(SimpleIdentityMap.Empty) {
719-
override def setBounds(sym: Symbol, b: TypeBounds): Unit = unsupported("EmptyGADTMap.setBounds")
718+
class SmartGADTMap(
719+
private[this] var myConstraint: Constraint = new OrderingConstraint(SimpleIdentityMap.Empty, SimpleIdentityMap.Empty, SimpleIdentityMap.Empty),
720+
private[this] var mapping: SimpleIdentityMap[Symbol, TypeVar] = SimpleIdentityMap.Empty
721+
) extends GADTMap with ConstraintHandling {
722+
def log(str: String): Unit = {
723+
import dotty.tools.dotc.config.Printers.gadts
724+
gadts.println(s"GADTMap: $str")
725+
}
726+
727+
// TODO: dirty kludge - should this class be an inner class of TyperState instead?
728+
private[this] var myCtx: Context = null
729+
implicit override def ctx = myCtx
730+
@forceInline private[this] final def inCtx[T](_ctx: Context)(op: => T) = {
731+
val savedCtx = myCtx
732+
myCtx = _ctx
733+
try op finally myCtx = savedCtx
734+
}
735+
736+
override protected def constraint = myConstraint
737+
override protected def constraint_=(c: Constraint) = myConstraint = c
738+
739+
override def isSubType(tp1: Type, tp2: Type): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
740+
override def isSameType(tp1: Type, tp2: Type): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
741+
742+
private[this] def tvar(sym: Symbol)(implicit ctx: Context) = inCtx(ctx) {
743+
val res = mapping(sym) match {
744+
case tv: TypeVar => tv
745+
case null =>
746+
log(i"creating tvar for: $sym")
747+
val res = {
748+
import NameKinds.DepParamName
749+
// do not use newTypeVar:
750+
// it registers the TypeVar with TyperState, we don't want that since it instantiates them (TODO: when?)
751+
// (see pos/i3500.scala)
752+
// it registers the TypeVar with TyperState Constraint, which we don't care for but it's needless
753+
val poly = PolyType(DepParamName.fresh().toTypeName :: Nil)(
754+
pt => TypeBounds.empty :: Nil,
755+
pt => defn.AnyType)
756+
// null out creatorState, we don't need it anyway (and TypeVar can null it too)
757+
new TypeVar(poly.paramRefs.head, creatorState = null)
758+
}
759+
constraint = constraint.add(res.origin.binder, res :: Nil)
760+
mapping = mapping.updated(sym, res)
761+
res
762+
}
763+
log(i"tvar: $sym -> $res")
764+
res
765+
}
766+
767+
override def setBounds(sym: Symbol, b: TypeBounds)(implicit ctx: Context): Unit = inCtx(ctx) {
768+
val tv = tvar(sym)
769+
log(i"setBounds `$sym` `$tv`: `$b`")
770+
addUpperBound(tv.origin, b.hi)
771+
addLowerBound(tv.origin, b.lo)
772+
}
773+
774+
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = inCtx(ctx) {
775+
mapping(sym) match {
776+
case null => null
777+
case tv => constraint.fullBounds(tv.origin)
778+
}
779+
}
780+
781+
override def contains(sym: Symbol)(implicit ctx: Context) = mapping(sym) ne null
782+
783+
override def derived: GADTMap = new SmartGADTMap(
784+
this.myConstraint,
785+
this.mapping
786+
)
787+
}
788+
789+
@sharable object EmptyGADTMap extends GADTMap {
790+
override def setBounds(sym: Symbol, b: TypeBounds)(implicit ctx: Context) = unsupported("EmptyGADTMap.setBounds")
791+
override def bounds(sym: Symbol)(implicit ctx: Context) = null
792+
override def contains(sym: Symbol)(implicit ctx: Context) = false
793+
override def derived = new SmartGADTMap
720794
}
721795
}

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ class TypeComparer(initctx: Context) extends ConstraintHandling {
2323
import TypeComparer._
2424
implicit val ctx: Context = initctx
2525

26-
val state: TyperState = ctx.typerState
27-
import state.constraint
26+
val state = ctx.typerState
27+
def constraint: Constraint = state.constraint
28+
def constraint_=(c: Constraint): Unit = state.constraint = c
2829

2930
private[this] var pendingSubTypes: mutable.Set[(Type, Type)] = null
3031
private[this] var recCount = 0
@@ -136,7 +137,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling {
136137
finally this.approx = saved
137138
}
138139

139-
protected def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, NoApprox)
140+
def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, NoApprox)
140141

141142
protected def recur(tp1: Type, tp2: Type): Boolean = trace(s"isSubType ${traceInfo(tp1, tp2)} $approx", subtyping) {
142143

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -3661,7 +3661,7 @@ object Types {
36613661

36623662
def isBounded(tp: Type) = tp match {
36633663
case tp: TypeParamRef =>
3664-
case tp: TypeRef => ctx.gadt.bounds.contains(tp.symbol)
3664+
case tp: TypeRef => ctx.gadt.contains(tp.symbol)
36653665
}
36663666

36673667
def contextInfo(tp: Type): Type = tp match {

compiler/src/dotty/tools/dotc/printing/Formatting.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ object Formatting {
168168
s"is a reference to a value parameter"
169169
case sym: Symbol =>
170170
val info =
171-
if (ctx.gadt.bounds.contains(sym))
171+
if (ctx.gadt.contains(sym))
172172
sym.info & ctx.gadt.bounds(sym)
173173
else
174174
sym.info
@@ -189,7 +189,7 @@ object Formatting {
189189
case param: TermParamRef => false
190190
case skolem: SkolemType => true
191191
case sym: Symbol =>
192-
ctx.gadt.bounds.contains(sym) && ctx.gadt.bounds(sym) != TypeBounds.empty
192+
ctx.gadt.contains(sym) && ctx.gadt.bounds(sym) != TypeBounds.empty
193193
case _ =>
194194
assert(false, "unreachable")
195195
false

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1007,7 +1007,7 @@ class Typer extends Namer
10071007
def gadtContext(gadtSyms: Set[Symbol])(implicit ctx: Context): Context = {
10081008
val gadtCtx = ctx.fresh.setFreshGADTBounds
10091009
for (sym <- gadtSyms)
1010-
if (!gadtCtx.gadt.bounds.contains(sym))
1010+
if (!gadtCtx.gadt.contains(sym))
10111011
gadtCtx.gadt.setBounds(sym, TypeBounds.empty)
10121012
gadtCtx
10131013
}

0 commit comments

Comments
 (0)