Skip to content

Commit e1df3ae

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 3df2c0f commit e1df3ae

File tree

5 files changed

+263
-223
lines changed

5 files changed

+263
-223
lines changed

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

Lines changed: 5 additions & 218 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,217 +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 def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit = tvar(sym)
834-
835-
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = {
836-
@annotation.tailrec def stripInternalTypeVar(tp: Type): Type = tp match {
837-
case tv: TypeVar =>
838-
val inst = instType(tv)
839-
if (inst.exists) stripInternalTypeVar(inst) else tv
840-
case _ => tp
841-
}
842-
843-
val symTvar: TypeVar = stripInternalTypeVar(tvar(sym)) match {
844-
case tv: TypeVar => tv
845-
case inst =>
846-
gadts.println(i"instantiated: $sym -> $inst")
847-
return if (isUpper) isSubType(inst , bound) else isSubType(bound, inst)
848-
}
849-
850-
val internalizedBound = bound match {
851-
case nt: NamedType if contains(nt.symbol) =>
852-
stripInternalTypeVar(tvar(nt.symbol))
853-
case _ => bound
854-
}
855-
(
856-
internalizedBound match {
857-
case boundTvar: TypeVar =>
858-
if (boundTvar eq symTvar) true
859-
else if (isUpper) addLess(symTvar.origin, boundTvar.origin)
860-
else addLess(boundTvar.origin, symTvar.origin)
861-
case bound =>
862-
val oldUpperBound = bounds(symTvar.origin)
863-
// If we already have bounds `F >: [t] => List[t] <: [t] => Any`
864-
// and we want to record that `F <: [+A] => List[A]`, we need to adapt
865-
// type parameter variances of the bound. Consider that the following is valid:
866-
//
867-
// class Foo[F[t] >: List[t]]
868-
// type T = Foo[List]
869-
//
870-
// precisely because `Foo[List]` is desugared to `Foo[[A] => List[A]]`.
871-
val bound1 = bound.adaptHkVariances(oldUpperBound)
872-
if (isUpper) addUpperBound(symTvar.origin, bound1)
873-
else addLowerBound(symTvar.origin, bound1)
874-
}
875-
).reporting({ res =>
876-
val descr = if (isUpper) "upper" else "lower"
877-
val op = if (isUpper) "<:" else ">:"
878-
i"adding $descr bound $sym $op $bound = $res\t( $symTvar $op $internalizedBound )"
879-
}, gadts)
880-
}
881-
882-
override def isLess(sym1: Symbol, sym2: Symbol)(implicit ctx: Context): Boolean =
883-
constraint.isLess(tvar(sym1).origin, tvar(sym2).origin)
884-
885-
override def fullBounds(sym: Symbol)(implicit ctx: Context): TypeBounds =
886-
mapping(sym) match {
887-
case null => null
888-
case tv => fullBounds(tv.origin)
889-
}
890-
891-
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = {
892-
mapping(sym) match {
893-
case null => null
894-
case tv =>
895-
def retrieveBounds: TypeBounds =
896-
bounds(tv.origin) match {
897-
case TypeAlias(tpr: TypeParamRef) if reverseMapping.contains(tpr) =>
898-
TypeAlias(reverseMapping(tpr).typeRef)
899-
case tb => tb
900-
}
901-
retrieveBounds//.reporting({ res => i"gadt bounds $sym: $res" }, gadts)
902-
}
903-
}
904-
905-
override def contains(sym: Symbol)(implicit ctx: Context): Boolean = mapping(sym) ne null
906-
907-
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = {
908-
val res = approximation(tvar(sym).origin, fromBelow = fromBelow)
909-
gadts.println(i"approximating $sym ~> $res")
910-
res
911-
}
912-
913-
override def fresh: GADTMap = new SmartGADTMap(
914-
myConstraint,
915-
mapping,
916-
reverseMapping
917-
)
918-
919-
def restore(other: GADTMap): Unit = other match {
920-
case other: SmartGADTMap =>
921-
this.myConstraint = other.myConstraint
922-
this.mapping = other.mapping
923-
this.reverseMapping = other.reverseMapping
924-
case _ => ;
925-
}
926-
927-
override def isEmpty: Boolean = mapping.size == 0
928-
929-
// ---- Private ----------------------------------------------------------
930-
931-
private[this] def tvar(sym: Symbol)(implicit ctx: Context): TypeVar = {
932-
mapping(sym) match {
933-
case tv: TypeVar =>
934-
tv
935-
case null =>
936-
val res = {
937-
import NameKinds.DepParamName
938-
// avoid registering the TypeVar with TyperState / TyperState#constraint
939-
// - we don't want TyperState instantiating these TypeVars
940-
// - we don't want TypeComparer constraining these TypeVars
941-
val poly = PolyType(DepParamName.fresh(sym.name.toTypeName) :: Nil)(
942-
pt => (sym.info match {
943-
case tb @ TypeBounds(_, hi) if hi.isLambdaSub => tb
944-
case _ => TypeBounds.empty
945-
}) :: Nil,
946-
pt => defn.AnyType)
947-
new TypeVar(poly.paramRefs.head, creatorState = null)
948-
}
949-
gadts.println(i"GADTMap: created tvar $sym -> $res")
950-
constraint = constraint.add(res.origin.binder, res :: Nil)
951-
mapping = mapping.updated(sym, res)
952-
reverseMapping = reverseMapping.updated(res.origin, sym)
953-
res
954-
}
955-
}
956-
957-
// ---- Debug ------------------------------------------------------------
958-
959-
override def constr_println(msg: => String): Unit = gadtsConstr.println(msg)
960-
961-
override def toText(printer: Printer): Texts.Text = constraint.toText(printer)
962-
963-
override def debugBoundsDescription(implicit ctx: Context): String = {
964-
val sb = new mutable.StringBuilder
965-
sb ++= constraint.show
966-
sb += '\n'
967-
mapping.foreachBinding { case (sym, _) =>
968-
sb ++= i"$sym: ${fullBounds(sym)}\n"
969-
}
970-
sb.result
971-
}
972-
}
973-
974-
@sharable object EmptyGADTMap extends GADTMap {
975-
override def addEmptyBounds(sym: Symbol)(implicit ctx: Context): Unit = unsupported("EmptyGADTMap.addEmptyBounds")
976-
override def addBound(sym: Symbol, bound: Type, isUpper: Boolean)(implicit ctx: Context): Boolean = unsupported("EmptyGADTMap.addBound")
977-
override def isLess(sym1: Symbol, sym2: Symbol)(implicit ctx: Context): Boolean = unsupported("EmptyGADTMap.isLess")
978-
override def bounds(sym: Symbol)(implicit ctx: Context): TypeBounds = null
979-
override def fullBounds(sym: Symbol)(implicit ctx: Context): TypeBounds = null
980-
override def contains(sym: Symbol)(implicit ctx: Context) = false
981-
override def approximation(sym: Symbol, fromBelow: Boolean)(implicit ctx: Context): Type = unsupported("EmptyGADTMap.approximation")
982-
override def toText(printer: Printer): Texts.Text = "EmptyGADTMap"
983-
override def debugBoundsDescription(implicit ctx: Context): String = "EmptyGADTMap"
984-
override def fresh = new SmartGADTMap
985-
override def restore(other: GADTMap): Unit = {
986-
if (!other.isEmpty) sys.error("cannot restore a non-empty GADTMap")
987-
}
988-
override def isEmpty: Boolean = true
989-
}
990777
}

0 commit comments

Comments
 (0)