@@ -480,7 +480,7 @@ object Contexts {
480
480
def setTyper (typer : Typer ): this .type = { this .scope = typer.scope; setTypeAssigner(typer) }
481
481
def setImportInfo (importInfo : ImportInfo ): this .type = { this .importInfo = importInfo; this }
482
482
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 )
484
484
def setSearchHistory (searchHistory : SearchHistory ): this .type = { this .searchHistory = searchHistory; this }
485
485
def setTypeComparerFn (tcfn : Context => TypeComparer ): this .type = { this .typeComparer = tcfn(this ); this }
486
486
private def setMoreProperties (moreProperties : Map [Key [Any ], Any ]): this .type = { this .moreProperties = moreProperties; this }
@@ -708,14 +708,201 @@ object Contexts {
708
708
else assert(thread == Thread .currentThread(), " illegal multithreaded access to ContextBase" )
709
709
}
710
710
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
716
718
}
717
719
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
720
907
}
721
908
}
0 commit comments