diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala index f53bfd762363..7eb06b447065 100644 --- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala +++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala @@ -148,21 +148,24 @@ class CheckRealizable(using Context) { */ private def boundsRealizability(tp: Type) = { - val memberProblems = + val memberProblems = withMode(Mode.CheckBounds) { for { mbr <- tp.nonClassTypeMembers if !(mbr.info.loBound <:< mbr.info.hiBound) } yield new HasProblemBounds(mbr.name, mbr.info) + } - val refinementProblems = + val refinementProblems = withMode(Mode.CheckBounds) { for { name <- refinedNames(tp) if (name.isTypeName) mbr <- tp.member(name).alternatives if !(mbr.info.loBound <:< mbr.info.hiBound) } - yield new HasProblemBounds(name, mbr.info) + yield + new HasProblemBounds(name, mbr.info) + } def baseTypeProblems(base: Type) = base match { case AndType(base1, base2) => diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index f6a6c97c25e1..d236513b7caa 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -72,6 +72,11 @@ object Mode { /** We are currently unpickling Scala2 info */ val Scala2Unpickling: Mode = newMode(13, "Scala2Unpickling") + /** We are currently checking bounds to be non-empty, so we should not + * do any widening when computing members of refined types. + */ + val CheckBounds: Mode = newMode(14, "CheckBounds") + /** Use Scala2 scheme for overloading and implicit resolution */ val OldOverloadingResolution: Mode = newMode(15, "OldOverloadingResolution") diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 3eca986a973b..d702aa939112 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -508,7 +508,7 @@ object TypeOps: boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type, app: Type)( - using Context): List[BoundsViolation] = { + using Context): List[BoundsViolation] = withMode(Mode.CheckBounds) { val argTypes = args.tpes /** Replace all wildcards in `tps` with `#` where `` is the diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6757e3170f91..67b2f2eb00a3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -671,8 +671,16 @@ object Types { val rinfo = tp.refinedInfo if (name.isTypeName && !pinfo.isInstanceOf[ClassInfo]) { // simplified case that runs more efficiently val jointInfo = - if (ctx.base.pendingMemberSearches.contains(name)) pinfo safe_& rinfo - else pinfo recoverable_& rinfo + if rinfo.isInstanceOf[TypeAlias] && !ctx.mode.is(Mode.CheckBounds) then + // In normal situations, the only way to "improve" on rinfo is to return an empty type bounds + // So, we do not lose anything essential in "widening" to rinfo. + // We need to compute the precise info only when checking for empty bounds + // which is communicated by the CheckBounds mode. + rinfo + else if ctx.base.pendingMemberSearches.contains(name) then + pinfo safe_& rinfo + else + pinfo recoverable_& rinfo pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo) } else diff --git a/tests/pos-deep-subtype/i9346.scala b/tests/pos-deep-subtype/i9346.scala new file mode 100644 index 000000000000..83ce56d91225 --- /dev/null +++ b/tests/pos-deep-subtype/i9346.scala @@ -0,0 +1,7 @@ +trait Foo { + type Repr[+O] <: Foo { + type Repr[+OO] = Foo.this.Repr[OO] + } + + def foo[T](f: Repr[T]): f.Repr[T] = ??? +} \ No newline at end of file