Skip to content

Commit

Permalink
Fix #9346: Shortcut type aliases in refinements
Browse files Browse the repository at this point in the history
  • Loading branch information
odersky committed Aug 14, 2020
1 parent a5ae258 commit 9aa1308
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 6 deletions.
9 changes: 6 additions & 3 deletions compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Mode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<app>#<tparam>` where `<tparam>` is the
Expand Down
12 changes: 10 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions tests/pos-deep-subtype/i9346.scala
Original file line number Diff line number Diff line change
@@ -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] = ???
}

0 comments on commit 9aa1308

Please sign in to comment.