@@ -709,20 +709,19 @@ object Contexts {
709709 }
710710
711711 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
713714 def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds
714715 def contains (sym : Symbol )(implicit ctx : Context ): Boolean
715716 def derived : GADTMap
716717 }
717718
718- class SmartGADTMap (
719+ final class SmartGADTMap (
719720 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
721723 ) 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
726725
727726 // TODO: dirty kludge - should this class be an inner class of TyperState instead?
728727 private [this ] var myCtx : Context = null
@@ -739,56 +738,120 @@ object Contexts {
739738 override def isSubType (tp1 : Type , tp2 : Type ): Boolean = ctx.typeComparer.isSubType(tp1, tp2)
740739 override def isSameType (tp1 : Type , tp2 : Type ): Boolean = ctx.typeComparer.isSameType(tp1, tp2)
741740
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) {
743742 val res = mapping(sym) match {
744743 case tv : TypeVar => tv
745744 case null =>
746- log(i " creating tvar for: $sym" )
747745 val res = {
748746 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 )(
754751 pt => TypeBounds .empty :: Nil ,
755752 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
757754 new TypeVar (poly.paramRefs.head, creatorState = null )
758755 }
756+ gadts.println(i " GADTMap: created tvar $sym -> $res" )
759757 constraint = constraint.add(res.origin.binder, res :: Nil )
760758 mapping = mapping.updated(sym, res)
759+ reverseMapping = reverseMapping.updated(res, sym)
761760 res
762761 }
763- log(i " tvar: $sym -> $res" )
764762 res
765763 }
766764
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
772797 }
773798
774799 override def bounds (sym : Symbol )(implicit ctx : Context ): TypeBounds = inCtx(ctx) {
775800 mapping(sym) match {
776801 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
778810 }
779811 }
780812
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
782814
783815 override def derived : GADTMap = new SmartGADTMap (
784816 this .myConstraint,
785- this .mapping
817+ this .mapping,
818+ this .reverseMapping
786819 )
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+ }
787849 }
788850
789851 @ 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
792855 override def contains (sym : Symbol )(implicit ctx : Context ) = false
793856 override def derived = new SmartGADTMap
794857 }
0 commit comments