From 2c2d8f82fc01282a9c12d0e6099b712de2cb3581 Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 15 Nov 2022 10:47:05 +0100 Subject: [PATCH] Fix calculation to drop transparent classes Two fixes: 1. Don't forget about refinements 2. Don't dealias Fixes #16342 The first fix is essential for $16342. The second fix is just to keep types tidy and not open aliases needlessly. The previous incorrect version hid errors in previous regressions #15365 and #16311 which will need to be re-opened now. --- .../tools/dotc/core/ConstraintHandling.scala | 15 ++++++++------- .../pos}/i15365.scala | 0 .../pos}/i16311.scala | 0 tests/pos/i16342.scala | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) rename tests/{pos-deep-subtype => pending/pos}/i15365.scala (100%) rename tests/{pos-deep-subtype => pending/pos}/i16311.scala (100%) create mode 100644 tests/pos/i16342.scala diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 69fc29c9318c..142648a3ae5c 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -557,8 +557,10 @@ trait ConstraintHandling { end approximation private def isTransparent(tp: Type)(using Context): Boolean = tp match - case AndType(tp1, tp2) => isTransparent(tp1) && isTransparent(tp2) - case _ => tp.typeSymbol.isTransparentClass && !tp.isLambdaSub + case AndType(tp1, tp2) => + isTransparent(tp1) && isTransparent(tp2) + case _ => + tp.underlyingClassRef(refinementOK = false).typeSymbol.isTransparentClass /** If `tp` is an intersection such that some operands are transparent trait instances * and others are not, replace as many transparent trait instances as possible with Any @@ -572,18 +574,17 @@ trait ConstraintHandling { var dropped: List[Type] = List() // the types dropped so far, last one on top def dropOneTransparentClass(tp: Type): Type = - val tpd = tp.dealias - if isTransparent(tpd) && !kept.contains(tpd) then - dropped = tpd :: dropped + if isTransparent(tp) && !kept.contains(tp) then + dropped = tp :: dropped defn.AnyType - else tpd match + else tp match case AndType(tp1, tp2) => val tp1w = dropOneTransparentClass(tp1) if tp1w ne tp1 then tp1w & tp2 else val tp2w = dropOneTransparentClass(tp2) if tp2w ne tp2 then tp1 & tp2w - else tpd + else tp case _ => tp diff --git a/tests/pos-deep-subtype/i15365.scala b/tests/pending/pos/i15365.scala similarity index 100% rename from tests/pos-deep-subtype/i15365.scala rename to tests/pending/pos/i15365.scala diff --git a/tests/pos-deep-subtype/i16311.scala b/tests/pending/pos/i16311.scala similarity index 100% rename from tests/pos-deep-subtype/i16311.scala rename to tests/pending/pos/i16311.scala diff --git a/tests/pos/i16342.scala b/tests/pos/i16342.scala new file mode 100644 index 000000000000..912790c459c2 --- /dev/null +++ b/tests/pos/i16342.scala @@ -0,0 +1,18 @@ +type Opaque = Base with Tag + +type Base = Any { + type Hack +} + +trait Tag + +object Opaque { + def apply(value: String): Opaque = value.asInstanceOf[Opaque] + + def unapply(userId: Opaque): Option[String] = Option(userId).map(_.value) + def unappy2(userId: Base with Tag): Option[String] = Option(userId).map(_.value) +} + +final implicit class Ops(private val userId: Opaque) extends AnyVal { + def value: String = userId.asInstanceOf[String] +} \ No newline at end of file