Skip to content

Commit 23a16fe

Browse files
committed
Fix #536 again
Test case was extended and several fixes were necessary to make it pass.
1 parent b67b23f commit 23a16fe

File tree

4 files changed

+31
-17
lines changed

4 files changed

+31
-17
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,12 @@ trait ConstraintHandling {
312312
/** The current bounds of type parameter `param` */
313313
final def bounds(param: TypeParamRef): TypeBounds = {
314314
val e = constraint.entry(param)
315-
if (e.exists) e.bounds else param.binder.paramInfos(param.paramNum)
315+
if (e.exists) e.bounds
316+
else {
317+
val pinfos = param.binder.paramInfos
318+
if (pinfos != null) pinfos(param.paramNum) // pinfos == null happens in pos/i536.scala
319+
else TypeBounds.empty
320+
}
316321
}
317322

318323
/** Add type lambda `tl`, possibly with type variables `tvars`, to current constraint

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ class TypeApplications(val self: Type) extends AnyVal {
447447
typr.println(i"normalize arg $arg for $tparam in $self app $args%, %, pbounds, = $pbounds")
448448
if (v > 0) hi & pbounds.hiBound
449449
else if (v < 0) lo | pbounds.loBound
450-
else arg & pbounds
450+
else arg recoverable_& pbounds
451451
case _ => arg
452452
}
453453

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -575,19 +575,7 @@ object Types {
575575
if (rinfo.isAlias) rinfo
576576
else if (pdenot.info.isAlias) pdenot.info
577577
else if (ctx.pendingMemberSearches.contains(name)) pdenot.info safe_& rinfo
578-
else
579-
try pdenot.info & rinfo
580-
catch {
581-
case ex: CyclicReference =>
582-
// ??? can this still happen? ???
583-
// happens for tests/pos/sets.scala. findMember is called from baseTypeRef.
584-
// The & causes a subtype check which calls baseTypeRef again with the same
585-
// superclass. In the observed case, the superclass was Any, and
586-
// the special shortcut for Any in derivesFrom was as yet absent. To reproduce,
587-
// remove the special treatment of Any in derivesFrom and compile
588-
// sets.scala.
589-
pdenot.info safe_& rinfo
590-
}
578+
else pdenot.info recoverable_& rinfo
591579
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
592580
} else {
593581
pdenot & (
@@ -867,17 +855,29 @@ object Types {
867855

868856
/** Safer version of `&`.
869857
*
870-
* This version does not simplify the upper bound of the intersection of
858+
* This version does not simplify the bounds of the intersection of
871859
* two TypeBounds. The simplification done by `&` requires subtyping checks
872860
* which may end up calling `&` again, in most cases this should be safe
873861
* but because of F-bounded types, this can result in an infinite loop
874862
* (which will be masked unless `-Yno-deep-subtypes` is enabled).
863+
* pos/i536 demonstrates that the infinite loop can also invole lower bounds.wait
875864
*/
876865
def safe_& (that: Type)(implicit ctx: Context): Type = (this, that) match {
877-
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(lo1 | lo2, AndType(hi1, hi2))
866+
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(OrType(lo1, lo2), AndType(hi1, hi2))
878867
case _ => this & that
879868
}
880869

870+
/** `this & that`, but handle CyclicReferences by falling back to `safe_&`.
871+
*/
872+
def recoverable_&(that: Type)(implicit ctx: Context): Type =
873+
try this & that
874+
catch {
875+
case ex: CyclicReference => this safe_& that
876+
// A test case where this happens is tests/pos/i536.scala.
877+
// The & causes a subtype check which calls baseTypeRef again with the same
878+
// superclass.
879+
}
880+
881881
def | (that: Type)(implicit ctx: Context): Type = track("|") {
882882
ctx.typeComparer.lub(this, that)
883883
}

tests/pos/i536.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
trait Comp[T]
2+
trait Coll[T]
3+
class C extends Comp[C]
14
object Max {
5+
def max[M <: Comp[_ >: M]](x: Coll[_ <: M]): M = ???
6+
def max[M](x: Coll[_ <: M], cmp: Object): M = ???
7+
val xs: Coll[C] = ???
8+
val m1 = max(xs)
9+
val m2 = max(null)
10+
211
java.util.Collections.max(null)
312
}

0 commit comments

Comments
 (0)