Skip to content

Commit d0b1d74

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

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
@@ -567,19 +567,7 @@ object Types {
567567
if (rinfo.isAlias) rinfo
568568
else if (pdenot.info.isAlias) pdenot.info
569569
else if (ctx.pendingMemberSearches.contains(name)) pdenot.info safe_& rinfo
570-
else
571-
try pdenot.info & rinfo
572-
catch {
573-
case ex: CyclicReference =>
574-
// ??? can this still happen? ???
575-
// happens for tests/pos/sets.scala. findMember is called from baseTypeRef.
576-
// The & causes a subtype check which calls baseTypeRef again with the same
577-
// superclass. In the observed case, the superclass was Any, and
578-
// the special shortcut for Any in derivesFrom was as yet absent. To reproduce,
579-
// remove the special treatment of Any in derivesFrom and compile
580-
// sets.scala.
581-
pdenot.info safe_& rinfo
582-
}
570+
else pdenot.info recoverable_& rinfo
583571
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
584572
} else {
585573
pdenot & (
@@ -859,17 +847,29 @@ object Types {
859847

860848
/** Safer version of `&`.
861849
*
862-
* This version does not simplify the upper bound of the intersection of
850+
* This version does not simplify the bounds of the intersection of
863851
* two TypeBounds. The simplification done by `&` requires subtyping checks
864852
* which may end up calling `&` again, in most cases this should be safe
865853
* but because of F-bounded types, this can result in an infinite loop
866854
* (which will be masked unless `-Yno-deep-subtypes` is enabled).
855+
* pos/i536 demonstrates that the infinite loop can also invole lower bounds.wait
867856
*/
868857
def safe_& (that: Type)(implicit ctx: Context): Type = (this, that) match {
869-
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(lo1 | lo2, AndType(hi1, hi2))
858+
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(OrType(lo1, lo2), AndType(hi1, hi2))
870859
case _ => this & that
871860
}
872861

862+
/** `this & that`, but handle CyclicReferences by falling back to `safe_&`.
863+
*/
864+
def recoverable_&(that: Type)(implicit ctx: Context): Type =
865+
try this & that
866+
catch {
867+
case ex: CyclicReference => this safe_& that
868+
// A test case where this happens is tests/pos/i536.scala.
869+
// The & causes a subtype check which calls baseTypeRef again with the same
870+
// superclass.
871+
}
872+
873873
def | (that: Type)(implicit ctx: Context): Type = track("|") {
874874
ctx.typeComparer.lub(this, that)
875875
}

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)