@@ -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.fresh )
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,201 @@ 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 addEmptyBounds (sym : Symbol )(implicit ctx : Context ): Unit
713+ def addBound (sym : Symbol , bound : Type , isUpper : Boolean )(implicit ctx : Context ): Boolean
714+ def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds
715+ def contains (sym : Symbol )(implicit ctx : Context ): Boolean
716+ def debugBoundsDescription (implicit ctx : Context ): String
717+ def fresh : GADTMap
716718 }
717719
718- @ sharable object EmptyGADTMap extends GADTMap (SimpleIdentityMap .Empty ) {
719- override def setBounds (sym : Symbol , b : TypeBounds ): Unit = unsupported(" EmptyGADTMap.setBounds" )
720+ final class SmartGADTMap private (
721+ private [this ] var myConstraint : Constraint ,
722+ private [this ] var mapping : SimpleIdentityMap [Symbol , TypeVar ],
723+ private [this ] var reverseMapping : SimpleIdentityMap [TypeParamRef , Symbol ]
724+ ) extends GADTMap with ConstraintHandling {
725+ import dotty .tools .dotc .config .Printers .{gadts , gadtsConstr }
726+
727+ def this () = this (
728+ myConstraint = new OrderingConstraint (SimpleIdentityMap .Empty , SimpleIdentityMap .Empty , SimpleIdentityMap .Empty ),
729+ mapping = SimpleIdentityMap .Empty ,
730+ reverseMapping = SimpleIdentityMap .Empty
731+ )
732+
733+ // TODO: clean up this dirty kludge
734+ private [this ] var myCtx : Context = null
735+ implicit override def ctx = myCtx
736+ @ forceInline private [this ] final def inCtx [T ](_ctx : Context )(op : => T ) = {
737+ val savedCtx = myCtx
738+ myCtx = _ctx
739+ try op finally myCtx = savedCtx
740+ }
741+
742+ override protected def constraint = myConstraint
743+ override protected def constraint_= (c : Constraint ) = myConstraint = c
744+
745+ override def isSubType (tp1 : Type , tp2 : Type ): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
746+ override def isSameType (tp1 : Type , tp2 : Type ): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
747+
748+
749+ override def addEmptyBounds (sym : Symbol )(implicit ctx : Context ): Unit = tvar(sym)
750+
751+ override def addBound (sym : Symbol , bound : Type , isUpper : Boolean )(implicit ctx : Context ): Boolean = inCtx(ctx) {
752+ @ annotation.tailrec def stripInst (tp : Type ): Type = tp match {
753+ case tv : TypeVar =>
754+ val inst = instType(tv)
755+ if (inst.exists) stripInst(inst) else tv
756+ case _ => tp
757+ }
758+
759+ def cautiousSubtype (tp1 : Type , tp2 : Type , isSubtype : Boolean ): Boolean = {
760+ val externalizedTp1 = removeTypeVars(tp1)
761+ val externalizedTp2 = removeTypeVars(tp2)
762+
763+ def descr = {
764+ def op = s " frozen_ ${if (isSubtype) " <:<" else " >:>" }"
765+ i " $tp1 $op $tp2\n\t $externalizedTp1 $op $externalizedTp2"
766+ }
767+ // gadts.println(descr)
768+
769+ val res =
770+ // TypeComparer.explain[Boolean](gadts.println) { implicit ctx =>
771+ if (isSubtype) externalizedTp1 frozen_<:< externalizedTp2
772+ else externalizedTp2 frozen_<:< externalizedTp1
773+ // }
774+
775+ gadts.println(i " $descr = $res" )
776+ res
777+ }
778+
779+ def unify (tv : TypeVar , tp : Type ): Unit = {
780+ gadts.println(i " manually unifying $tv with $tp" )
781+ constraint = constraint.updateEntry(tv.origin, tp)
782+ }
783+
784+ val symTvar : TypeVar = stripInst(tvar(sym)) match {
785+ case tv : TypeVar => tv
786+ case inst =>
787+ gadts.println(i " instantiated: $sym -> $inst" )
788+ // this is wrong in general, but "correct" due to a subtype check in TypeComparer#narrowGadtBounds
789+ return true
790+ }
791+
792+ val internalizedBound = insertTypeVars(bound)
793+ val res = stripInst(internalizedBound) match {
794+ case boundTvar : TypeVar =>
795+ if (boundTvar eq symTvar) true
796+ else if (isUpper) addLess(symTvar.origin, boundTvar.origin)
797+ else addLess(boundTvar.origin, symTvar.origin)
798+ case bound =>
799+ if (cautiousSubtype(symTvar, bound, isSubtype = ! isUpper)) { unify(symTvar, bound); true }
800+ else if (isUpper) addUpperBound(symTvar.origin, bound)
801+ else addLowerBound(symTvar.origin, bound)
802+ }
803+
804+ gadts.println {
805+ val descr = if (isUpper) " upper" else " lower"
806+ val op = if (isUpper) " <:" else " >:"
807+ i " adding $descr bound $sym $op $bound = $res\t ( $symTvar $op $internalizedBound ) "
808+ }
809+ res
810+ }
811+
812+ override def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds = inCtx(ctx) {
813+ mapping(sym) match {
814+ case null => null
815+ case tv =>
816+ val tb = constraint.fullBounds(tv.origin)
817+ val res = removeTypeVars(tb).asInstanceOf [TypeBounds ]
818+ // gadts.println(i"gadt bounds $sym: $res")
819+ res
820+ }
821+ }
822+
823+ override def contains (sym : Symbol )(implicit ctx : Context ): Boolean = mapping(sym) ne null
824+
825+ override def fresh : GADTMap = new SmartGADTMap (
826+ myConstraint,
827+ mapping,
828+ reverseMapping
829+ )
830+
831+ // ---- Private ----------------------------------------------------------
832+
833+ private [this ] def tvar (sym : Symbol )(implicit ctx : Context ): TypeVar = {
834+ mapping(sym) match {
835+ case tv : TypeVar =>
836+ tv
837+ case null =>
838+ val res = {
839+ import NameKinds .DepParamName
840+ // avoid registering the TypeVar with TyperState / TyperState#constraint
841+ // - we don't want TyperState instantiating these TypeVars
842+ // - we don't want TypeComparer constraining these TypeVars
843+ val poly = PolyType (DepParamName .fresh(sym.name.toTypeName) :: Nil )(
844+ pt => TypeBounds .empty :: Nil ,
845+ pt => defn.AnyType )
846+ new TypeVar (poly.paramRefs.head, creatorState = null )
847+ }
848+ gadts.println(i " GADTMap: created tvar $sym -> $res" )
849+ constraint = constraint.add(res.origin.binder, res :: Nil )
850+ mapping = mapping.updated(sym, res)
851+ reverseMapping = reverseMapping.updated(res.origin, sym)
852+ res
853+ }
854+ }
855+
856+ private def insertTypeVars (tp : Type , map : TypeMap = null )(implicit ctx : Context ) = tp match {
857+ case tp : TypeRef =>
858+ val sym = tp.typeSymbol
859+ if (contains(sym)) tvar(sym) else tp
860+ case _ =>
861+ (if (map != null ) map else new TypeVarInsertingMap ()).mapOver(tp)
862+ }
863+ private final class TypeVarInsertingMap (implicit ctx : Context ) extends TypeMap {
864+ override def apply (tp : Type ): Type = insertTypeVars(tp, this )
865+ }
866+
867+ private def removeTypeVars (tp : Type , map : TypeMap = null )(implicit ctx : Context ) = tp match {
868+ case tpr : TypeParamRef =>
869+ reverseMapping(tpr) match {
870+ case null => tpr
871+ case sym => sym.typeRef
872+ }
873+ case tv : TypeVar =>
874+ reverseMapping(tv.origin) match {
875+ case null => tv
876+ case sym => sym.typeRef
877+ }
878+ case _ =>
879+ (if (map != null ) map else new TypeVarRemovingMap ()).mapOver(tp)
880+ }
881+ private final class TypeVarRemovingMap (implicit ctx : Context ) extends TypeMap {
882+ override def apply (tp : Type ): Type = removeTypeVars(tp, this )
883+ }
884+
885+ // ---- Debug ------------------------------------------------------------
886+
887+ override def constr_println (msg : => String ): Unit = gadtsConstr.println(msg)
888+
889+ override def debugBoundsDescription (implicit ctx : Context ): String = {
890+ val sb = new mutable.StringBuilder
891+ sb ++= constraint.show
892+ sb += '\n '
893+ mapping.foreachBinding { case (sym, _) =>
894+ sb ++= i " $sym: ${bounds(sym)}\n "
895+ }
896+ sb.result
897+ }
898+ }
899+
900+ @ sharable object EmptyGADTMap extends GADTMap {
901+ override def addEmptyBounds (sym : Symbol )(implicit ctx : Context ): Unit = unsupported(" EmptyGADTMap.addEmptyBounds" )
902+ override def addBound (sym : Symbol , bound : Type , isUpper : Boolean )(implicit ctx : Context ): Boolean = unsupported(" EmptyGADTMap.addBound" )
903+ override def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds = null
904+ override def contains (sym : Symbol )(implicit ctx : Context ) = false
905+ override def debugBoundsDescription (implicit ctx : Context ): String = " EmptyGADTMap"
906+ override def fresh = new SmartGADTMap
720907 }
721908}
0 commit comments