From 9aec96dd81af2b7823b8306c5400610da1e24720 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 10 Jun 2024 18:22:19 +0200 Subject: [PATCH 1/2] Fall back to direct subtype comparison at the end of dropIfSuper and dropIfSub --- .../dotty/tools/dotc/core/TypeComparer.scala | 16 +- tests/pos/i20516.scala | 205 ++++++++++++++++++ 2 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 tests/pos/i20516.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 6e360faa322d..d248d2e00b0d 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2535,36 +2535,24 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling /** If some (&-operand of) `tp` is a supertype of `sub` replace it with `NoType`. */ private def dropIfSuper(tp: Type, sub: Type): Type = - - def isSuperOf(sub: Type): Boolean = sub match - case AndType(sub1, sub2) => isSuperOf(sub1) || isSuperOf(sub2) - case sub: TypeVar if sub.isInstantiated => isSuperOf(sub.instanceOpt) - case _ => isSubTypeWhenFrozen(sub, tp) - tp match case tp @ AndType(tp1, tp2) => recombine(dropIfSuper(tp1, sub), dropIfSuper(tp2, sub), tp) case tp: TypeVar if tp.isInstantiated => dropIfSuper(tp.instanceOpt, sub) case _ => - if isSuperOf(sub) then NoType else tp + if isSubTypeWhenFrozen(sub, tp) then NoType else tp end dropIfSuper /** If some (|-operand of) `tp` is a subtype of `sup` replace it with `NoType`. */ private def dropIfSub(tp: Type, sup: Type, canConstrain: Boolean): Type = - - def isSubOf(sup: Type): Boolean = sup match - case OrType(sup1, sup2) => isSubOf(sup1) || isSubOf(sup2) - case sup: TypeVar if sup.isInstantiated => isSubOf(sup.instanceOpt) - case _ => isSubType(tp, sup, whenFrozen = !canConstrain) - tp match case tp @ OrType(tp1, tp2) => recombine(dropIfSub(tp1, sup, canConstrain), dropIfSub(tp2, sup, canConstrain), tp) case tp: TypeVar if tp.isInstantiated => dropIfSub(tp.instanceOpt, sup, canConstrain) case _ => - if isSubOf(sup) then NoType else tp + if isSubType(tp, sup, whenFrozen = !canConstrain) then NoType else tp end dropIfSub /** There's a window of vulnerability between ElimByName and Erasure where some diff --git a/tests/pos/i20516.scala b/tests/pos/i20516.scala new file mode 100644 index 000000000000..ff755177bda8 --- /dev/null +++ b/tests/pos/i20516.scala @@ -0,0 +1,205 @@ +object Main { + trait A {} + trait B {} + trait C {} + trait D {} + trait E {} + trait F {} + trait G {} + trait H {} + trait I {} + trait J {} + trait K {} + trait L {} + trait M {} + trait N {} + trait O {} + trait P {} + trait Q {} + trait R {} + trait S {} + trait T {} + trait U {} + trait V {} + trait W {} + trait X {} + trait Y {} + trait Z {} + + type AlphabeticServices = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + + type EnvOutA = B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutB = A & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutC = A & B & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutD = A & B & C & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutE = A & B & C & D & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutF = A & B & C & D & E & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutG = A & B & C & D & E & F & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutH = A & B & C & D & E & F & G & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutI = A & B & C & D & E & F & G & H & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutJ = A & B & C & D & E & F & G & H & I & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutK = A & B & C & D & E & F & G & H & I & J & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutL = A & B & C & D & E & F & G & H & I & J & K & M & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutM = A & B & C & D & E & F & G & H & I & J & K & L & N & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutN = A & B & C & D & E & F & G & H & I & J & K & L & M & O & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutO = A & B & C & D & E & F & G & H & I & J & K & L & M & N & P & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutP = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & Q & R & S & T & U & V & W & X & Y & Z + type EnvOutQ = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & R & S & T & U & V & W & X & Y & Z + type EnvOutR = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & S & T & U & V & W & X & Y & Z + type EnvOutS = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & T & U & V & W & X & Y & Z + type EnvOutT = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & U & V & W & X & Y & Z + type EnvOutU = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & V & W & X & Y & Z + type EnvOutV = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & W & X & Y & Z + type EnvOutW = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & X & Y & Z + type EnvOutX = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & Y & Z + type EnvOutY = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Z + type EnvOutZ = A & B & C & D & E & F & G & H & I & J & K & L & M & N & O & P & Q & R & S & T & U & V & W & X & Y + + trait Reader[-E, A] { + def map[B](f: A => B): Reader[E, B] = ??? + def flatMap[E2 <: E, B](f: A => Reader[E2, B]): Reader[E2, B] = ??? + } + + def e1: Reader[EnvOutA, Unit] = ??? + def e2: Reader[EnvOutB, Unit] = ??? + def e3: Reader[EnvOutC, Unit] = ??? + def e4: Reader[EnvOutD, Unit] = ??? + def e5: Reader[EnvOutE, Unit] = ??? + def e6: Reader[EnvOutF, Unit] = ??? + def e7: Reader[EnvOutG, Unit] = ??? + def e8: Reader[EnvOutH, Unit] = ??? + def e9: Reader[EnvOutI, Unit] = ??? + def e10: Reader[EnvOutJ, Unit] = ??? + def e11: Reader[EnvOutK, Unit] = ??? + def e12: Reader[EnvOutL, Unit] = ??? + def e13: Reader[EnvOutM, Unit] = ??? + def e14: Reader[EnvOutN, Unit] = ??? + def e15: Reader[EnvOutO, Unit] = ??? + def e16: Reader[EnvOutP, Unit] = ??? + def e17: Reader[EnvOutQ, Unit] = ??? + def e18: Reader[EnvOutR, Unit] = ??? + def e19: Reader[EnvOutS, Unit] = ??? + def e20: Reader[EnvOutT, Unit] = ??? + def e21: Reader[EnvOutU, Unit] = ??? + def e22: Reader[EnvOutV, Unit] = ??? + def e23: Reader[EnvOutW, Unit] = ??? + def e24: Reader[EnvOutX, Unit] = ??? + def e25: Reader[EnvOutY, Unit] = ??? + def e26: Reader[EnvOutZ, Unit] = ??? + + def program: Reader[AlphabeticServices, Unit] = for { + //1 + _ <- e1 + _ <- e2 + _ <- e3 + _ <- e4 + _ <- e5 + _ <- e6 + _ <- e7 + _ <- e8 + _ <- e8 + _ <- e9 + _ <- e10 + _ <- e11 + _ <- e12 + _ <- e13 + _ <- e14 + _ <- e15 + _ <- e16 + _ <- e17 + _ <- e18 + _ <- e19 + _ <- e20 + _ <- e21 + _ <- e22 + _ <- e23 + _ <- e24 + _ <- e25 + _ <- e26 + // 2 + _ <- e1 + _ <- e2 + _ <- e3 + _ <- e4 + _ <- e5 + _ <- e6 + _ <- e7 + _ <- e8 + _ <- e8 + _ <- e9 + _ <- e10 + _ <- e11 + _ <- e12 + _ <- e13 + _ <- e14 + _ <- e15 + _ <- e16 + _ <- e17 + _ <- e18 + _ <- e19 + _ <- e20 + _ <- e21 + _ <- e22 + _ <- e23 + _ <- e24 + _ <- e25 + _ <- e26 + // TODO: optimize the subtype checking for large intersection types further + //3 + // _ <- e1 + // _ <- e2 + // _ <- e3 + // _ <- e4 + // _ <- e5 + // _ <- e6 + // _ <- e7 + // _ <- e8 + // _ <- e8 + // _ <- e9 + // _ <- e10 + // _ <- e11 + // _ <- e12 + // _ <- e13 + // _ <- e14 + // _ <- e15 + // _ <- e16 + // _ <- e17 + // _ <- e18 + // _ <- e19 + // _ <- e20 + // _ <- e21 + // _ <- e22 + // _ <- e23 + // _ <- e24 + // _ <- e25 + // _ <- e26 + // 4 + // _ <- e1 + // _ <- e2 + // _ <- e3 + // _ <- e4 + // _ <- e5 + // _ <- e6 + // _ <- e7 + // _ <- e8 + // _ <- e8 + // _ <- e9 + // _ <- e10 + // _ <- e11 + // _ <- e12 + // _ <- e13 + // _ <- e14 + // _ <- e15 + // _ <- e16 + // _ <- e17 + // _ <- e18 + // _ <- e19 + // _ <- e20 + // _ <- e21 + // _ <- e22 + // _ <- e23 + // _ <- e24 + // _ <- e25 + // _ <- e26 + } yield () +} \ No newline at end of file From ba82f73ab30c820751ebc87e7b10b87f6fda6b18 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Mon, 10 Jun 2024 18:41:15 +0200 Subject: [PATCH 2/2] Move test to deep subtype --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 4 ++++ tests/{pos => pos-deep-subtype}/i20516.scala | 0 2 files changed, 4 insertions(+) rename tests/{pos => pos-deep-subtype}/i20516.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index d248d2e00b0d..1cd737909822 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -2535,6 +2535,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling /** If some (&-operand of) `tp` is a supertype of `sub` replace it with `NoType`. */ private def dropIfSuper(tp: Type, sub: Type): Type = + // We need to be careful to check branches of AndTypes and OrTypes in correct order, + // see discussion in issue #20516. tp match case tp @ AndType(tp1, tp2) => recombine(dropIfSuper(tp1, sub), dropIfSuper(tp2, sub), tp) @@ -2546,6 +2548,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling /** If some (|-operand of) `tp` is a subtype of `sup` replace it with `NoType`. */ private def dropIfSub(tp: Type, sup: Type, canConstrain: Boolean): Type = + // We need to be careful to check branches of AndTypes and OrTypes in correct order, + // see discussion in issue #20516. tp match case tp @ OrType(tp1, tp2) => recombine(dropIfSub(tp1, sup, canConstrain), dropIfSub(tp2, sup, canConstrain), tp) diff --git a/tests/pos/i20516.scala b/tests/pos-deep-subtype/i20516.scala similarity index 100% rename from tests/pos/i20516.scala rename to tests/pos-deep-subtype/i20516.scala