@@ -709,20 +709,19 @@ object Contexts {
709
709
}
710
710
711
711
sealed abstract class GADTMap {
712
- def setBounds (sym : Symbol , b : TypeBounds )(implicit ctx : Context ): Unit
712
+ def addEmptyBounds (sym : Symbol )(implicit ctx : Context ): Unit
713
+ def addBound (sym : Symbol , bound : Type , isUpper : Boolean )(implicit ctx : Context ): Boolean
713
714
def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds
714
715
def contains (sym : Symbol )(implicit ctx : Context ): Boolean
715
716
def derived : GADTMap
716
717
}
717
718
718
- class SmartGADTMap (
719
+ final class SmartGADTMap (
719
720
private [this ] var myConstraint : Constraint = new OrderingConstraint (SimpleIdentityMap .Empty , SimpleIdentityMap .Empty , SimpleIdentityMap .Empty ),
720
- private [this ] var mapping : SimpleIdentityMap [Symbol , TypeVar ] = SimpleIdentityMap .Empty
721
+ private [this ] var mapping : SimpleIdentityMap [Symbol , TypeVar ] = SimpleIdentityMap .Empty ,
722
+ private [this ] var reverseMapping : SimpleIdentityMap [TypeVar , Symbol ] = SimpleIdentityMap .Empty
721
723
) 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
- }
724
+ import dotty .tools .dotc .config .Printers .gadts
726
725
727
726
// TODO: dirty kludge - should this class be an inner class of TyperState instead?
728
727
private [this ] var myCtx : Context = null
@@ -739,56 +738,120 @@ object Contexts {
739
738
override def isSubType (tp1 : Type , tp2 : Type ): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
740
739
override def isSameType (tp1 : Type , tp2 : Type ): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
741
740
742
- private [this ] def tvar (sym : Symbol )(implicit ctx : Context ) = inCtx(ctx) {
741
+ private [this ] def tvar (sym : Symbol )(implicit ctx : Context ): TypeVar = inCtx(ctx) {
743
742
val res = mapping(sym) match {
744
743
case tv : TypeVar => tv
745
744
case null =>
746
- log(i " creating tvar for: $sym" )
747
745
val res = {
748
746
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 )(
747
+ // avoid registering the TypeVar with TyperState / TyperState#constraint
748
+ // TyperState TypeVars get instantiated when we don't want them to (see pos/i3500.scala)
749
+ // TyperState#constraint TypeVars can be narrowed in subtype checks - don't want that either
750
+ val poly = PolyType (DepParamName .fresh(sym.name.toTypeName) :: Nil )(
754
751
pt => TypeBounds .empty :: Nil ,
755
752
pt => defn.AnyType )
756
- // null out creatorState, we don't need it anyway (and TypeVar can null it too)
753
+ // null out creatorState as a precaution
757
754
new TypeVar (poly.paramRefs.head, creatorState = null )
758
755
}
756
+ gadts.println(i " GADTMap: created tvar $sym -> $res" )
759
757
constraint = constraint.add(res.origin.binder, res :: Nil )
760
758
mapping = mapping.updated(sym, res)
759
+ reverseMapping = reverseMapping.updated(res, sym)
761
760
res
762
761
}
763
- log(i " tvar: $sym -> $res" )
764
762
res
765
763
}
766
764
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)
765
+ override def addEmptyBounds (sym : Symbol )(implicit ctx : Context ): Unit = tvar(sym)
766
+
767
+ override def addBound (sym : Symbol , bound : Type , isUpper : Boolean )(implicit ctx : Context ): Boolean = inCtx(ctx) {
768
+ def isEmptyBounds (tp : Type ) = tp match {
769
+ case TypeBounds (lo, hi) => (lo eq defn.NothingType ) && (hi eq defn.AnyType )
770
+ case _ => false
771
+ }
772
+
773
+ val symTvar = tvar(sym)
774
+
775
+ def doAddOrdering (bound : TypeParamRef ) =
776
+ if (isUpper) addLess(symTvar.origin, bound) else addLess(bound, symTvar.origin)
777
+
778
+ def doAddBound (bound : Type ) =
779
+ if (isUpper) addUpperBound(symTvar.origin, bound) else addLowerBound(symTvar.origin, bound)
780
+
781
+ val tvarBound = (new TypeVarInsertingMap )(bound)
782
+ val res = tvarBound match {
783
+ case boundTvar : TypeVar =>
784
+ if (boundTvar eq symTvar) true else doAddOrdering(boundTvar.origin)
785
+ // hack to normalize T and T[_]
786
+ case AppliedType (boundTvar : TypeVar , args) if args forall isEmptyBounds =>
787
+ doAddOrdering(boundTvar.origin)
788
+ case tp => doAddBound(tp)
789
+ }
790
+
791
+ gadts.println {
792
+ val descr = if (isUpper) " upper" else " lower"
793
+ val op = if (isUpper) " <:" else " >:"
794
+ i " adding $descr bound $sym $op $bound = $res\t ( $symTvar $op $tvarBound ) "
795
+ }
796
+ res
772
797
}
773
798
774
799
override def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds = inCtx(ctx) {
775
800
mapping(sym) match {
776
801
case null => null
777
- case tv => constraint.fullBounds(tv.origin)
802
+ case tv =>
803
+ val tb = constraint.fullBounds(tv.origin)
804
+ val res = {
805
+ val tm = new TypeVarRemovingMap
806
+ tb.derivedTypeBounds(tm(tb.lo), tm(tb.hi))
807
+ }
808
+ gadts.println(i " gadt bounds $sym: $res\t ( $tv: $tb ) " )
809
+ res
778
810
}
779
811
}
780
812
781
- override def contains (sym : Symbol )(implicit ctx : Context ) = mapping(sym) ne null
813
+ override def contains (sym : Symbol )(implicit ctx : Context ): Boolean = mapping(sym) ne null
782
814
783
815
override def derived : GADTMap = new SmartGADTMap (
784
816
this .myConstraint,
785
- this .mapping
817
+ this .mapping,
818
+ this .reverseMapping
786
819
)
820
+
821
+ private final class TypeVarInsertingMap extends TypeMap {
822
+ override def apply (tp : Type ): Type = tp match {
823
+ case tp : TypeRef =>
824
+ val sym = tp.typeSymbol
825
+ if (contains(sym)) tvar(sym) else tp
826
+ case _ =>
827
+ mapOver(tp)
828
+ }
829
+ }
830
+
831
+ private final class TypeVarRemovingMap extends TypeMap {
832
+ override def apply (tp : Type ): Type = tp match {
833
+ case tpr : TypeParamRef =>
834
+ constraint.typeVarOfParam(tpr) match {
835
+ case tv : TypeVar =>
836
+ reverseMapping(tv).typeRef
837
+ case unexpected =>
838
+ // if we didn't get a TypeVar, it's likely to cause problems
839
+ gadts.println(i " GADTMap: unexpected typeVarOfParam( $tpr) = ` $unexpected` ${unexpected.getClass}" )
840
+ tpr
841
+ }
842
+ case tv : TypeVar =>
843
+ if (reverseMapping.contains(tv)) reverseMapping(tv).typeRef
844
+ else tv
845
+ case _ =>
846
+ mapOver(tp)
847
+ }
848
+ }
787
849
}
788
850
789
851
@ 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
852
+ override def addEmptyBounds (sym : Symbol )(implicit ctx : Context ): Unit = unsupported(" EmptyGADTMap.addEmptyBounds" )
853
+ override def addBound (sym : Symbol , bound : Type , isUpper : Boolean )(implicit ctx : Context ): Boolean = unsupported(" EmptyGADTMap.addBound" )
854
+ override def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds = null
792
855
override def contains (sym : Symbol )(implicit ctx : Context ) = false
793
856
override def derived = new SmartGADTMap
794
857
}
0 commit comments