diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 15b2d5a9ac93..c93e5a8183bb 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2968,7 +2968,10 @@ object Types extends TypeUtils { if myCanDropAliasPeriod != ctx.period then myCanDropAlias = !symbol.canMatchInheritedSymbols - || !prefix.baseClasses.exists(_.info.decls.lookup(name).is(Deferred)) + || !prefix.baseClasses.exists{cls => + val decl = cls.info.decls.lookup(name) + decl.is(Deferred) && !decl.is(Opaque) + } myCanDropAliasPeriod = ctx.period myCanDropAlias diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 92cae663352a..7f79a5db070f 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -476,9 +476,18 @@ class Inliner(val call: tpd.Tree)(using Context): fixRefinedTypes(parent) case _ => fixRefinedTypes(binding.symbol.info) + val prev = binding.symbol.info binding.symbol.info = mapOpaques.typeMap(binding.symbol.info) - mapOpaques.transform(binding).asInstanceOf[ValDef] + val mapped = mapOpaques.transform(binding).asInstanceOf[ValDef] .showing(i"transformed this binding exposing opaque aliases: $result", inlining) + // val res = + // if binding.symbol.info != prev then + // binding.symbol.info = AndType(prev, binding.symbol.info) + // ValDef(binding.symbol.asTerm, mapped.rhs.cast(binding.symbol.info)) // TODO merge + // else + // mapped + // res + mapped end addProxiesForRecurrentOpaques /** If `binding` contains TermRefs that refer to objects with opaque @@ -657,7 +666,9 @@ class Inliner(val call: tpd.Tree)(using Context): if opaqueProxies.isEmpty then StopAt.Static else StopAt.Package def apply(t: Type) = t match { case t: ThisType => thisProxy.getOrElse(t.cls, t) - case t: TypeRef => paramProxy.getOrElse(t, mapOver(t)) + case t: TypeRef => + if (t.isMatch) paramProxy.getOrElse(t, mapOver(t)) // Do not map matchTypes + else paramProxy.get(t).map(mapOpaques.typeMap(_)).getOrElse(mapOver(t)) case t: SingletonType => if t.termSymbol.isAllOf(InlineParam) then apply(t.widenTermRefExpr) else paramProxy.getOrElse(t, mapOver(t)) @@ -912,7 +923,11 @@ class Inliner(val call: tpd.Tree)(using Context): sym.info = rhs.tpe untpd.cpy.ValDef(vdef)(vdef.name, untpd.TypeTree(rhs.tpe), untpd.TypedSplice(rhs)) else vdef - super.typedValDef(vdef1, sym) + if vdef.name.toString.contains("$proxy") then // TODO look for a better solution + // AndType(t1, t2) might not equal &(t1, t2), + // but when constructing proxies we have to use AndType without simplyfying the types + vdef.asInstanceOf[Tree] + else super.typedValDef(vdef1, sym) override def typedApply(tree: untpd.Apply, pt: Type)(using Context): Tree = val locked = ctx.typerState.ownedVars diff --git a/tests/pos/i22974/Maybe_1.scala b/tests/pos/i22974/Maybe_1.scala new file mode 100644 index 000000000000..bd4964b29582 --- /dev/null +++ b/tests/pos/i22974/Maybe_1.scala @@ -0,0 +1,14 @@ +package pack +import Maybe._ +opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A] +object Maybe: + sealed abstract class Absent + case object Absent extends Absent + object internal: + case class PresentAbsent(val depth: Int) + opaque type Present[+A] = A | internal.PresentAbsent + + extension [A](self: Maybe[A]) { + inline def flatten[B]: Maybe[B] = ??? + inline def isDefined: Boolean = ??? + } diff --git a/tests/pos/i22974/macro_1.scala b/tests/pos/i22974/macro_1.scala new file mode 100644 index 000000000000..61d7783bd38a --- /dev/null +++ b/tests/pos/i22974/macro_1.scala @@ -0,0 +1,6 @@ +import scala.quoted._ + +inline def passThorugh(inline condition: Boolean): Any = + ${ passThorughImpl('{condition}) } + +def passThorughImpl(condition: Expr[Boolean])(using Quotes): Expr[Any] = condition diff --git a/tests/pos/i22974/main_2.scala b/tests/pos/i22974/main_2.scala new file mode 100644 index 000000000000..a0b55aff7f52 --- /dev/null +++ b/tests/pos/i22974/main_2.scala @@ -0,0 +1,6 @@ +object Test { + def main(): Unit = + import pack.Maybe + val res: Maybe[Maybe[Int]] = ??? + passThorugh(res.flatten.isDefined) +} diff --git a/tests/pos/i22974a.scala b/tests/pos/i22974a.scala new file mode 100644 index 000000000000..4f6e23c0f97d --- /dev/null +++ b/tests/pos/i22974a.scala @@ -0,0 +1,18 @@ +object outer: + opaque type Queue = Queue.Unsafe + object Queue: + abstract class Unsafe + opaque type Unbounded = Queue + object Unbounded: + inline def initWith()(f: Unbounded => Unit): Unit = + f(Unsafe.init()) + + opaque type Unsafe <: Queue.Unsafe = Queue + object Unsafe: + def init[A](): Unsafe = ??? + +object Resource: + def run: Unit = + outer.Queue.Unbounded.initWith() { q => + ??? + } diff --git a/tests/pos/i22974b.scala b/tests/pos/i22974b.scala new file mode 100644 index 000000000000..3284a1e55ae9 --- /dev/null +++ b/tests/pos/i22974b.scala @@ -0,0 +1,24 @@ +object outer: + opaque type Queue = Queue.Unsafe + object Queue: + abstract class Unsafe + opaque type Unbounded = Queue + object Unbounded: + opaque type Unsafe <: Queue.Unsafe = Queue + object Unsafe: + def init[A](): Unsafe = ??? + +object Resource: + def run: Unit = + val $proxy2: outer.type{type Queue = outer.Queue.Unsafe} = + outer.asInstanceOf[outer.type{type Queue = outer.Queue.Unsafe}] + val $proxy1: $proxy2.Queue.type{type Unbounded = $proxy2.Queue} = + $proxy2.Queue.asInstanceOf[$proxy2.Queue.type{type Unbounded = $proxy2.Queue}] + val $proxy3: $proxy1.Unbounded.type{type Unsafe = $proxy2.Queue} = + $proxy1.Unbounded.asInstanceOf[$proxy1.Unbounded.type{type Unsafe = $proxy2.Queue}] + val Unbounded$_this: + $proxy1.Unbounded.type{type Unsafe = $proxy2.Queue} = $proxy3 + val f$proxy1: (outer.Queue.Unbounded => Unit) & ($proxy1.Unbounded => Unit) = + ((q: outer.Queue.Unbounded) => ???).asInstanceOf[(outer.Queue.Unbounded => Unit) & ($proxy1.Unbounded => Unit)] + + f$proxy1(Unbounded$_this.Unsafe.init()) diff --git a/tests/pos/i22974c.scala b/tests/pos/i22974c.scala new file mode 100644 index 000000000000..77833340de19 --- /dev/null +++ b/tests/pos/i22974c.scala @@ -0,0 +1,18 @@ +object other: + sealed abstract class Absent + case object Absent extends Absent + case class PresentAbsent(val depth: Int) + opaque type Present[+A] = A | PresentAbsent + opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A] + + extension [A](self: Maybe[A]) { + inline def flatten[B]: Maybe[B] = if self.isEmpty then Absent else ??? + def isEmpty: Boolean = self.isInstanceOf[Absent] + } + +class Test { + def main(): Unit = + import other.Maybe + val res: Maybe[Maybe[Int]] = ??? + res.flatten +}