diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 2d02546a6d5e..ca0b3b45f072 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5856,7 +5856,7 @@ object Types { tp.derivedAppliedType(tycon, args.map(rangeToBounds)) match case tp1: AppliedType if tp1.isUnreducibleWild => // don't infer a type that would trigger an error later in - // Checling.checkAppliedType; fall through to default handling instead + // Checking.checkAppliedType; fall through to default handling instead case tp1 => return tp1 end if @@ -5865,7 +5865,7 @@ object Types { // non-range arguments L1, ..., Ln and H1, ..., Hn such that // C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of // ranges that appear in as co- or contravariant arguments. - // Fail for non-variant argument ranges. + // Fail for non-variant argument ranges (see use-site else branch below). // If successful, the L-arguments are in loBut, the H-arguments in hiBuf. // @return operation succeeded for all arguments. def distributeArgs(args: List[Type], tparams: List[ParamInfo]): Boolean = args match { @@ -5886,11 +5886,18 @@ object Types { if (distributeArgs(args, tp.tyconTypeParams)) range(tp.derivedAppliedType(tycon, loBuf.toList), tp.derivedAppliedType(tycon, hiBuf.toList)) - else range(defn.NothingType, defn.AnyType) - // TODO: can we give a better bound than `topType`? + else if tycon.isLambdaSub || args.exists(isRangeOfNonTermTypes) then + range(defn.NothingType, defn.AnyType) + else + // See lampepfl/dotty#14152 + range(defn.NothingType, tp.derivedAppliedType(tycon, args.map(rangeToBounds))) else tp.derivedAppliedType(tycon, args) } + private def isRangeOfNonTermTypes(tp: Type): Boolean = tp match + case Range(lo, hi) => !lo.isInstanceOf[TermType] || !hi.isInstanceOf[TermType] + case _ => false + override protected def derivedAndType(tp: AndType, tp1: Type, tp2: Type): Type = if (isRange(tp1) || isRange(tp2)) range(lower(tp1) & lower(tp2), upper(tp1) & upper(tp2)) else tp.derivedAndType(tp1, tp2) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 85eba072f7a8..be38221ef167 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -885,12 +885,13 @@ trait Checking { * that is concurrently compiled in another source file. */ def checkNoModuleClash(sym: Symbol)(using Context): Unit = - if sym.effectiveOwner.is(Package) - && sym.owner.info.member(sym.name.moduleClassName).symbol.isAbsent() + val effectiveOwner = sym.effectiveOwner + if effectiveOwner.is(Package) + && effectiveOwner.info.member(sym.name.moduleClassName).symbol.isAbsent() then - val conflicting = sym.owner.info.member(sym.name.toTypeName).symbol + val conflicting = effectiveOwner.info.member(sym.name.toTypeName).symbol if conflicting.exists then - report.error(AlreadyDefined(sym.name, sym.owner, conflicting), sym.srcPos) + report.error(AlreadyDefined(sym.name, effectiveOwner, conflicting), sym.srcPos) /** Check that `tp` is a class type. * Also, if `traitReq` is true, check that `tp` is a trait. diff --git a/tests/pos/i14152.scala b/tests/pos/i14152.scala new file mode 100644 index 000000000000..2377d5ffeae3 --- /dev/null +++ b/tests/pos/i14152.scala @@ -0,0 +1,30 @@ +val a1 = { + object O1 extends AnyRef + Array(O1) +} +val a2: Array[_ <: AnyRef] = aa1 + +val aa1 = { + object O1 extends AnyRef + Array(Array(O1)) +} +val aa2: Array[_ <: Array[_ <: AnyRef]] = aa1 + +val aaa1 = { + object O1 extends AnyRef + Array(Array(Array(O1))) +} +val aaa2: Array[_ <: Array[_ <: Array[_ <: AnyRef]]] = aaa1 + + +// Let's make sure avoidance still does the right thing given abstract type constructors + +class Inv[T](x: T) + +def foo[F[_]](fn: [A] => Inv[A] => F[A]) = + object O1 extends AnyRef + val res0 = fn(new Inv(fn(new Inv[O1.type](O1)))) + val res1: F[F[O1.type]] = res0 + res1 // checked with -Xprint:typer that this widens to Any + // instead of the original F[F[O1.type]] + // or the incorrectly avoided F[? <: F[? <: Object]]