diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index cfe3b80a2422..9568698893b7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -3,7 +3,7 @@ package dotc package core import Contexts._, Types._, Symbols._, Names._, Flags._ -import SymDenotations._ +import Denotations._, SymDenotations._ import util.Spans._ import util.Stats import NameKinds.DepParamName @@ -438,6 +438,8 @@ object TypeOps: tp.origin, fromBelow = variance > 0 || variance == 0 && tp.hasLowerBound)(using mapCtx) val lo1 = apply(lo) if (lo1 ne lo) lo1 else tp + case tp: LazyRef if isExpandingBounds => + emptyRange case _ => mapOver(tp) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 782a92624fe5..59f8c37cbf55 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5328,8 +5328,23 @@ object Types { case _ => tp } + private var expandingBounds: Boolean = false + + /** Whether it is currently expanding bounds + * + * It is used to avoid following LazyRef in F-Bounds + */ + def isExpandingBounds: Boolean = expandingBounds + protected def expandBounds(tp: TypeBounds): Type = - range(atVariance(-variance)(reapply(tp.lo)), reapply(tp.hi)) + if expandingBounds then tp + else { + val saved = expandingBounds + expandingBounds = true + val res = range(atVariance(-variance)(reapply(tp.lo)), reapply(tp.hi)) + expandingBounds = saved + res + } /** Try to widen a named type to its info relative to given prefix `pre`, where possible. * The possible cases are listed inline in the code. diff --git a/tests/pos/i11078.scala b/tests/pos/i11078.scala new file mode 100644 index 000000000000..f4b6669d30f4 --- /dev/null +++ b/tests/pos/i11078.scala @@ -0,0 +1,29 @@ +trait Foo[A <: Foo[A]] +trait FooCreator[A <: Foo[A]] { + def createFoo(): A +} + +trait FooWrapper { + type A <: Foo[A] + def foo: A +} +object FooWrapper { + def apply[A0 <: Foo[A0]](toWrap: A0): FooWrapper { type A = A0 } = new FooWrapper { + type A = A0 + def foo: A0 = toWrap + } +} + +trait FooCreatorWrapper { + type A <: Foo[A] + def fooCreator: FooCreator[A] +} + +sealed trait Bar +object Bar { + case class Baz(wrapper: FooCreatorWrapper) extends Bar +} + +def process(bar: Bar): FooWrapper = bar match { + case Bar.Baz(wrapper) => FooWrapper(wrapper.fooCreator.createFoo()) +} \ No newline at end of file diff --git a/tests/pos/i11078b.scala b/tests/pos/i11078b.scala new file mode 100644 index 000000000000..e14453dc5a7c --- /dev/null +++ b/tests/pos/i11078b.scala @@ -0,0 +1,11 @@ +class Test { + trait Foo[A <: Foo[A]] + + trait FooWrapper with self => + type A <: Foo[A] + def doThing(foo: FooWrapper): FooWrapper { type A = self.A } = ??? + end FooWrapper + + val foos: scala.Seq[FooWrapper] = ??? + val newFoo = foos.foldLeft(??? : FooWrapper)((topFoo, foo) => topFoo.doThing(foo)) +}