Skip to content

Commit a505b6a

Browse files
committed
Move GADT constraint code to a separate file
Also rename the classes to better reflect their role, and document and reorder definitions to make more sense.
1 parent bc46312 commit a505b6a

File tree

5 files changed

+267
-227
lines changed

5 files changed

+267
-227
lines changed

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

Lines changed: 5 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ object Contexts {
139139
final def importInfo: ImportInfo = _importInfo
140140

141141
/** The current bounds in force for type parameters appearing in a GADT */
142-
private[this] var _gadt: GADTMap = _
143-
protected def gadt_=(gadt: GADTMap): Unit = _gadt = gadt
144-
final def gadt: GADTMap = _gadt
142+
private[this] var _gadt: GadtConstraint = _
143+
protected def gadt_=(gadt: GadtConstraint): Unit = _gadt = gadt
144+
final def gadt: GadtConstraint = _gadt
145145

146146
/** The history of implicit searches that are currently active */
147147
private[this] var _searchHistory: SearchHistory = null
@@ -534,7 +534,7 @@ object Contexts {
534534
def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
535535
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
536536
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
537-
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
537+
def setGadt(gadt: GadtConstraint): this.type = { this.gadt = gadt; this }
538538
def setFreshGADTBounds: this.type = setGadt(gadt.fresh)
539539
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
540540
def setSource(source: SourceFile): this.type = { this.source = source; this }
@@ -617,7 +617,7 @@ object Contexts {
617617
store = initialStore.updated(settingsStateLoc, settingsGroup.defaultState)
618618
typeComparer = new TypeComparer(this)
619619
searchHistory = new SearchRoot
620-
gadt = EmptyGADTMap
620+
gadt = EmptyGadtConstraint
621621
}
622622

623623
@sharable object NoContext extends Context(null) {
@@ -774,221 +774,4 @@ object Contexts {
774774
if (thread == null) thread = Thread.currentThread()
775775
else assert(thread == Thread.currentThread(), "illegal multithreaded access to ContextBase")
776776
}
777-
778-
sealed abstract class GADTMap extends Showable {
779-
def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit
780-
def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean
781-
def isLess(sym1: Symbol, sym2: Symbol)(implicit ctx: Context): Boolean
782-
def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds
783-
784-
/** Full bounds of `sym`, including TypeRefs to other lower/upper symbols.
785-
*
786-
* Note that underlying operations perform subtype checks - for this reason, recursing on `fullBounds`
787-
* of some symbol when comparing types might lead to infinite recursion. Consider `bounds` instead.
788-
*/
789-
def fullBounds(sym: Symbol)(implicit ctx: Context): TypeBounds
790-
def contains(sym: Symbol)(implicit ctx: Context): Boolean
791-
def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type
792-
def debugBoundsDescription(implicit ctx: Context): String
793-
def fresh: GADTMap
794-
def restore(other: GADTMap): Unit
795-
def isEmpty: Boolean
796-
}
797-
798-
final class SmartGADTMap private (
799-
private var myConstraint: Constraint,
800-
private var mapping: SimpleIdentityMap[Symbol, TypeVar],
801-
private var reverseMapping: SimpleIdentityMap[TypeParamRef, Symbol],
802-
) extends GADTMap with ConstraintHandling[Context] {
803-
import dotty.tools.dotc.config.Printers.{gadts, gadtsConstr}
804-
805-
def subsumes(left: GADTMap, right: GADTMap, pre: GADTMap)(implicit ctx: Context): Boolean = {
806-
def extractConstraint(g: GADTMap) = g match {
807-
case s: SmartGADTMap => s.constraint
808-
case EmptyGADTMap => OrderingConstraint.empty
809-
}
810-
subsumes(extractConstraint(left), extractConstraint(right), extractConstraint(pre))
811-
}
812-
813-
def this() = this(
814-
myConstraint = new OrderingConstraint(SimpleIdentityMap.Empty, SimpleIdentityMap.Empty, SimpleIdentityMap.Empty),
815-
mapping = SimpleIdentityMap.Empty,
816-
reverseMapping = SimpleIdentityMap.Empty
817-
)
818-
819-
implicit override def ctx(implicit ctx: Context): Context = ctx
820-
821-
override protected def constraint = myConstraint
822-
override protected def constraint_=(c: Constraint) = myConstraint = c
823-
824-
override protected def externalize(param: TypeParamRef)(implicit ctx: Context): Type =
825-
reverseMapping(param) match {
826-
case sym: Symbol => sym.typeRef
827-
case null => param
828-
}
829-
830-
override def isSubType(tp1: Type, tp2: Type)(implicit ctx: Context): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
831-
override def isSameType(tp1: Type, tp2: Type)(implicit ctx: Context): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
832-
833-
override protected def typeLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
834-
ctx.typeComparer.lub(tp1, tp2, admitSingletons = true)
835-
}
836-
837-
override def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit = tvar(sym)
838-
839-
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = {
840-
@annotation.tailrec def stripInternalTypeVar(tp: Type): Type = tp match {
841-
case tv: TypeVar =>
842-
val inst = instType(tv)
843-
if (inst.exists) stripInternalTypeVar(inst) else tv
844-
case _ => tp
845-
}
846-
847-
val symTvar: TypeVar = stripInternalTypeVar(tvar(sym)) match {
848-
case tv: TypeVar => tv
849-
case inst =>
850-
gadts.println(i"instantiated: $sym -> $inst")
851-
return if (isUpper) isSubType(inst , bound) else isSubType(bound, inst)
852-
}
853-
854-
val internalizedBound = bound match {
855-
case nt: NamedType if contains(nt.symbol) =>
856-
stripInternalTypeVar(tvar(nt.symbol))
857-
case _ => bound
858-
}
859-
(
860-
internalizedBound match {
861-
case boundTvar: TypeVar =>
862-
if (boundTvar eq symTvar) true
863-
else if (isUpper) addLess(symTvar.origin, boundTvar.origin)
864-
else addLess(boundTvar.origin, symTvar.origin)
865-
case bound =>
866-
val oldUpperBound = bounds(symTvar.origin)
867-
// If we already have bounds `F >: [t] => List[t] <: [t] => Any`
868-
// and we want to record that `F <: [+A] => List[A]`, we need to adapt
869-
// type parameter variances of the bound. Consider that the following is valid:
870-
//
871-
// class Foo[F[t] >: List[t]]
872-
// type T = Foo[List]
873-
//
874-
// precisely because `Foo[List]` is desugared to `Foo[[A] => List[A]]`.
875-
val bound1 = bound.adaptHkVariances(oldUpperBound)
876-
if (isUpper) addUpperBound(symTvar.origin, bound1)
877-
else addLowerBound(symTvar.origin, bound1)
878-
}
879-
).reporting({ res =>
880-
val descr = if (isUpper) "upper" else "lower"
881-
val op = if (isUpper) "<:" else ">:"
882-
i"adding $descr bound $sym $op $bound = $res\t( $symTvar $op $internalizedBound )"
883-
}, gadts)
884-
}
885-
886-
override def isLess(sym1: Symbol, sym2: Symbol)(implicit ctx: Context): Boolean =
887-
constraint.isLess(tvar(sym1).origin, tvar(sym2).origin)
888-
889-
override def fullBounds(sym: Symbol)(implicit ctx: Context): TypeBounds =
890-
mapping(sym) match {
891-
case null => null
892-
case tv => fullBounds(tv.origin)
893-
}
894-
895-
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = {
896-
mapping(sym) match {
897-
case null => null
898-
case tv =>
899-
def retrieveBounds: TypeBounds =
900-
bounds(tv.origin) match {
901-
case TypeAlias(tpr: TypeParamRef) if reverseMapping.contains(tpr) =>
902-
TypeAlias(reverseMapping(tpr).typeRef)
903-
case tb => tb
904-
}
905-
retrieveBounds//.reporting({ res => i"gadt bounds $sym: $res" }, gadts)
906-
}
907-
}
908-
909-
override def contains(sym: Symbol)(implicit ctx: Context): Boolean = mapping(sym) ne null
910-
911-
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = {
912-
val res = approximation(tvar(sym).origin, fromBelow = fromBelow)
913-
gadts.println(i"approximating $sym ~> $res")
914-
res
915-
}
916-
917-
override def fresh: GADTMap = new SmartGADTMap(
918-
myConstraint,
919-
mapping,
920-
reverseMapping
921-
)
922-
923-
def restore(other: GADTMap): Unit = other match {
924-
case other: SmartGADTMap =>
925-
this.myConstraint = other.myConstraint
926-
this.mapping = other.mapping
927-
this.reverseMapping = other.reverseMapping
928-
case _ => ;
929-
}
930-
931-
override def isEmpty: Boolean = mapping.size == 0
932-
933-
// ---- Private ----------------------------------------------------------
934-
935-
private[this] def tvar(sym: Symbol)(implicit ctx: Context): TypeVar = {
936-
mapping(sym) match {
937-
case tv: TypeVar =>
938-
tv
939-
case null =>
940-
val res = {
941-
import NameKinds.DepParamName
942-
// avoid registering the TypeVar with TyperState / TyperState#constraint
943-
// - we don't want TyperState instantiating these TypeVars
944-
// - we don't want TypeComparer constraining these TypeVars
945-
val poly = PolyType(DepParamName.fresh(sym.name.toTypeName) :: Nil)(
946-
pt => (sym.info match {
947-
case tb @ TypeBounds(_, hi) if hi.isLambdaSub => tb
948-
case _ => TypeBounds.empty
949-
}) :: Nil,
950-
pt => defn.AnyType)
951-
new TypeVar(poly.paramRefs.head, creatorState = null)
952-
}
953-
gadts.println(i"GADTMap: created tvar $sym -> $res")
954-
constraint = constraint.add(res.origin.binder, res :: Nil)
955-
mapping = mapping.updated(sym, res)
956-
reverseMapping = reverseMapping.updated(res.origin, sym)
957-
res
958-
}
959-
}
960-
961-
// ---- Debug ------------------------------------------------------------
962-
963-
override def constr_println(msg: => String): Unit = gadtsConstr.println(msg)
964-
965-
override def toText(printer: Printer): Texts.Text = constraint.toText(printer)
966-
967-
override def debugBoundsDescription(implicit ctx: Context): String = {
968-
val sb = new mutable.StringBuilder
969-
sb ++= constraint.show
970-
sb += '\n'
971-
mapping.foreachBinding { case (sym, _) =>
972-
sb ++= i"$sym: ${fullBounds(sym)}\n"
973-
}
974-
sb.result
975-
}
976-
}
977-
978-
@sharable object EmptyGADTMap extends GADTMap {
979-
override def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit = unsupported("EmptyGADTMap.addEmptyBounds")
980-
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = unsupported("EmptyGADTMap.addBound")
981-
override def isLess(sym1: Symbol, sym2: Symbol)(implicit ctx: Context): Boolean = unsupported("EmptyGADTMap.isLess")
982-
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = null
983-
override def fullBounds(sym: Symbol)(implicit ctx: Context): TypeBounds = null
984-
override def contains(sym: Symbol)(implicit ctx: Context) = false
985-
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = unsupported("EmptyGADTMap.approximation")
986-
override def toText(printer: Printer): Texts.Text = "EmptyGADTMap"
987-
override def debugBoundsDescription(implicit ctx: Context): String = "EmptyGADTMap"
988-
override def fresh = new SmartGADTMap
989-
override def restore(other: GADTMap): Unit = {
990-
if (!other.isEmpty) sys.error("cannot restore a non-empty GADTMap")
991-
}
992-
override def isEmpty: Boolean = true
993-
}
994777
}

0 commit comments

Comments
 (0)