@@ -146,12 +146,13 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
146146 */
147147 private [this ] var leftRoot : Type = _
148148
149- /** Are we forbidden from recording GADT constraints?
150- *
151- * This flag is set when we're already in [[Mode.GadtConstraintInference ]],
152- * to signify that we temporarily cannot record any GADT constraints.
153- */
149+ /** Are we forbidden from recording GADT constraints? */
154150 private var frozenGadt = false
151+ private inline def inFrozenGadt [T ](op : => T ): T = {
152+ val savedFrozenGadt = frozenGadt
153+ frozenGadt = true
154+ try op finally frozenGadt = savedFrozenGadt
155+ }
155156
156157 protected def isSubType (tp1 : Type , tp2 : Type , a : ApproxState ): Boolean = {
157158 val savedApprox = approx
@@ -839,30 +840,40 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
839840 val tycon2sym = tycon2.symbol
840841
841842 var touchedGADTs = false
842- def gadtBoundsContain (sym : Symbol , tp : Type ): Boolean = {
843+ var gadtIsInstantiated = false
844+ def byGadtBounds (sym : Symbol , tp : Type , fromAbove : Boolean ): Boolean = {
843845 touchedGADTs = true
844846 val b = gadtBounds(sym)
845- b != null && inFrozenConstraint {
846- (b.lo =:= tp) && (b.hi =:= tp)
847+ def boundsDescr = if b == null then " null" else b.show
848+ b != null && inFrozenGadt {
849+ if fromAbove then isSubType(b.hi, tp) else isSubType(tp, b.lo)
850+ } && {
851+ gadtIsInstantiated = b.isInstanceOf [TypeAlias ]
852+ true
847853 }
848854 }
849855
850856 val res = (
851- tycon1sym == tycon2sym ||
852- gadtBoundsContain(tycon1sym, tycon2) ||
853- gadtBoundsContain(tycon2sym, tycon1)
854- ) &&
855- isSubType(tycon1.prefix, tycon2.prefix) && {
856- // check both tycons to deal with the case when they are equal b/c of GADT constraint
857- val tyconIsInjective = tycon1sym.isClass || tycon2sym.isClass
857+ tycon1sym == tycon2sym
858+ && isSubType(tycon1.prefix, tycon2.prefix)
859+ || byGadtBounds(tycon1sym, tycon2, fromAbove = true )
860+ || byGadtBounds(tycon2sym, tycon1, fromAbove = false )
861+ ) && {
862+ // There are two cases in which we can assume injectivity.
863+ // First we check if either sym is a class.
864+ // Then:
865+ // 1) if we didn't touch GADTs, then both symbols are the same
866+ // (b/c of an earlier condition) and both are the same class
867+ // 2) if we touched GADTs, then the _other_ symbol (class syms
868+ // cannot have GADT constraints), the one w/ GADT cstrs,
869+ // must be instantiated, making the two tycons equal
870+ val tyconIsInjective =
871+ (tycon1sym.isClass || tycon2sym.isClass)
872+ && (if touchedGADTs then gadtIsInstantiated else true )
858873 def checkSubArgs () = isSubArgs(args1, args2, tp1, tparams)
859- // we only record GADT constraints if tycon is guaranteed to be injective
874+ // we only record GADT constraints if *both* tycons are effectively injective
860875 if (tyconIsInjective) checkSubArgs()
861- else {
862- val savedFrozenGadt = frozenGadt
863- frozenGadt = true
864- try checkSubArgs() finally frozenGadt = savedFrozenGadt
865- }
876+ else inFrozenGadt { checkSubArgs() }
866877 }
867878 if (res && touchedGADTs) GADTused = true
868879 res
0 commit comments