Skip to content

Commit c99f6ca

Browse files
authored
Merge pull request #14274 from dwijnand/arrays-crash
Fix checkNoModuleClash & avoid types with less precision loss
2 parents c49a1cf + 3c9a2ff commit c99f6ca

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5847,7 +5847,7 @@ object Types {
58475847
tp.derivedAppliedType(tycon, args.map(rangeToBounds)) match
58485848
case tp1: AppliedType if tp1.isUnreducibleWild =>
58495849
// don't infer a type that would trigger an error later in
5850-
// Checling.checkAppliedType; fall through to default handling instead
5850+
// Checking.checkAppliedType; fall through to default handling instead
58515851
case tp1 =>
58525852
return tp1
58535853
end if
@@ -5856,7 +5856,7 @@ object Types {
58565856
// non-range arguments L1, ..., Ln and H1, ..., Hn such that
58575857
// C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of
58585858
// ranges that appear in as co- or contravariant arguments.
5859-
// Fail for non-variant argument ranges.
5859+
// Fail for non-variant argument ranges (see use-site else branch below).
58605860
// If successful, the L-arguments are in loBut, the H-arguments in hiBuf.
58615861
// @return operation succeeded for all arguments.
58625862
def distributeArgs(args: List[Type], tparams: List[ParamInfo]): Boolean = args match {
@@ -5877,11 +5877,18 @@ object Types {
58775877
if (distributeArgs(args, tp.tyconTypeParams))
58785878
range(tp.derivedAppliedType(tycon, loBuf.toList),
58795879
tp.derivedAppliedType(tycon, hiBuf.toList))
5880-
else range(defn.NothingType, defn.AnyType)
5881-
// TODO: can we give a better bound than `topType`?
5880+
else if tycon.isLambdaSub || args.exists(isRangeOfNonTermTypes) then
5881+
range(defn.NothingType, defn.AnyType)
5882+
else
5883+
// See lampepfl/dotty#14152
5884+
range(defn.NothingType, tp.derivedAppliedType(tycon, args.map(rangeToBounds)))
58825885
else tp.derivedAppliedType(tycon, args)
58835886
}
58845887

5888+
private def isRangeOfNonTermTypes(tp: Type): Boolean = tp match
5889+
case Range(lo, hi) => !lo.isInstanceOf[TermType] || !hi.isInstanceOf[TermType]
5890+
case _ => false
5891+
58855892
override protected def derivedAndType(tp: AndType, tp1: Type, tp2: Type): Type =
58865893
if (isRange(tp1) || isRange(tp2)) range(lower(tp1) & lower(tp2), upper(tp1) & upper(tp2))
58875894
else tp.derivedAndType(tp1, tp2)

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -885,12 +885,13 @@ trait Checking {
885885
* that is concurrently compiled in another source file.
886886
*/
887887
def checkNoModuleClash(sym: Symbol)(using Context): Unit =
888-
if sym.effectiveOwner.is(Package)
889-
&& sym.owner.info.member(sym.name.moduleClassName).symbol.isAbsent()
888+
val effectiveOwner = sym.effectiveOwner
889+
if effectiveOwner.is(Package)
890+
&& effectiveOwner.info.member(sym.name.moduleClassName).symbol.isAbsent()
890891
then
891-
val conflicting = sym.owner.info.member(sym.name.toTypeName).symbol
892+
val conflicting = effectiveOwner.info.member(sym.name.toTypeName).symbol
892893
if conflicting.exists then
893-
report.error(AlreadyDefined(sym.name, sym.owner, conflicting), sym.srcPos)
894+
report.error(AlreadyDefined(sym.name, effectiveOwner, conflicting), sym.srcPos)
894895

895896
/** Check that `tp` is a class type.
896897
* Also, if `traitReq` is true, check that `tp` is a trait.

tests/pos/i14152.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
val a1 = {
2+
object O1 extends AnyRef
3+
Array(O1)
4+
}
5+
val a2: Array[_ <: AnyRef] = aa1
6+
7+
val aa1 = {
8+
object O1 extends AnyRef
9+
Array(Array(O1))
10+
}
11+
val aa2: Array[_ <: Array[_ <: AnyRef]] = aa1
12+
13+
val aaa1 = {
14+
object O1 extends AnyRef
15+
Array(Array(Array(O1)))
16+
}
17+
val aaa2: Array[_ <: Array[_ <: Array[_ <: AnyRef]]] = aaa1
18+
19+
20+
// Let's make sure avoidance still does the right thing given abstract type constructors
21+
22+
class Inv[T](x: T)
23+
24+
def foo[F[_]](fn: [A] => Inv[A] => F[A]) =
25+
object O1 extends AnyRef
26+
val res0 = fn(new Inv(fn(new Inv[O1.type](O1))))
27+
val res1: F[F[O1.type]] = res0
28+
res1 // checked with -Xprint:typer that this widens to Any
29+
// instead of the original F[F[O1.type]]
30+
// or the incorrectly avoided F[? <: F[? <: Object]]

0 commit comments

Comments
 (0)