diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 40fbc80f85f0..15d1f675205b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3713,8 +3713,19 @@ object Types { tp match { case tp: NamedType => if (stopAtStatic && tp.symbol.isStatic) tp - else derivedSelect(tp, this(tp.prefix)) - + else { + val saved = variance + variance = variance max 0 + // A prefix is never contravariant. Even if say `p.A` is used in a contravariant + // context, we cannot assume contravariance for `p` because `p`'s lower + // bound might not have a binding for `A` (e.g. the lower bound could be `Nothing`). + // By contrast, covariance does translate to the prefix, since we have that + // if `p <: q` then `p.A <: q.A`, and well-formedness requires that `A` is a member + // of `p`'s upper bound. + val prefix1 = this(tp.prefix) + variance = saved + derivedSelect(tp, prefix1) + } case _: ThisType | _: BoundType | NoPrefix => tp @@ -3913,9 +3924,9 @@ object Types { protected var variance = 1 - protected def applyToPrefix(x: T, tp: NamedType) = { + protected final def applyToPrefix(x: T, tp: NamedType) = { val saved = variance - variance = 0 + variance = variance max 0 // see remark on NamedType case in TypeMap val result = this(x, tp.prefix) variance = saved result diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index b2c8fd0595a0..99a6e5373fa9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -319,8 +319,6 @@ object Inferencing { case _ => foldOver(vmap, t) } - override def applyToPrefix(vmap: VarianceMap, t: NamedType) = - apply(vmap, t.prefix) } /** Include in `vmap` type variables occurring in the constraints of type variables diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 76bc9360f6aa..a389cf77e98c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -268,7 +268,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (qualifies(defDenot)) { val found = if (isSelfDenot(defDenot)) curOwner.enclosingClass.thisType - else curOwner.thisType.select(name, defDenot) + else { + val effectiveOwner = + if (curOwner.isTerm && defDenot.symbol.isType) + // Don't mix NoPrefix and thisType prefixes, since type comparer + // would not detect types to be compatible. Note: If we replace the + // 2nd condition by `defDenot.symbol.maybeOwner.isType` we get lots + // of failures in the `tastyBootstrap` test. Trying to compile these + // files in isolation works though. + // TODO: Investigate why that happens. + defDenot.symbol.owner + else + curOwner + effectiveOwner.thisType.select(name, defDenot) + } if (!(curOwner is Package) || isDefinedInCurrentUnit(defDenot)) result = checkNewOrShadowed(found, definition) // no need to go further out, we found highest prec entry else {