Skip to content

Commit 02a8644

Browse files
committed
safe_&: handle higher-kinded arguments like regular &
Unfortunately, i9346.scala has to be put in pending because it still crashes (due to a cycle involving a LazyRef) after this fix, and because `safe_&` is only called from `recoverable_&` when there is some sort of cycle in the first place, I haven't been able to make another testcase that exercises this codepath. It would be good if we could figure out how to get i9346.scala to compile. It is is a minimization of a pattern heavily used in akka-stream, similar to the use of the `CC` type parameter in the scala-library collections but using a type member instead. Unfortunately, it seems that Dotty is not really prepared to handle F-bounds in type members currently. I was able to get the testcase as well as akka-stream to compile by tweaking `findMember` to not compute an intersection when the refinement is an alias: ```diff --- compiler/src/dotty/tools/dotc/core/Types.scala +++ compiler/src/dotty/tools/dotc/core/Types.scala @@ -671,7 +671,8 @@ object Types { val rinfo = tp.refinedInfo if (name.isTypeName && !pinfo.isInstanceOf[ClassInfo]) { // simplified case that runs more efficiently val jointInfo = - if (ctx.base.pendingMemberSearches.contains(name)) pinfo safe_& rinfo + if (rinfo.isInstanceOf[TypeAlias]) rinfo + else if (ctx.base.pendingMemberSearches.contains(name)) pinfo safe_& rinfo else pinfo recoverable_& rinfo pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo) } ``` This seems to work, but to be sound it means that we need to check for invalid bounds in PostTyper (see tests/neg/i5556.scala for an example where this matters), like we do for type parameters in `checkAppliedType`.
1 parent 63b84cb commit 02a8644

File tree

3 files changed

+18
-3
lines changed

3 files changed

+18
-3
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -2078,7 +2078,7 @@ class TypeComparer(using val comparerCtx: Context) extends ConstraintHandling wi
20782078
*
20792079
* [X1, ..., Xn] -> op(tp1[X1, ..., Xn], tp2[X1, ..., Xn])
20802080
*/
2081-
private def liftIfHK(tp1: Type, tp2: Type,
2081+
def liftIfHK(tp1: Type, tp2: Type,
20822082
op: (Type, Type) => Type, original: (Type, Type) => Type, combineVariance: (Variance, Variance) => Variance) = {
20832083
val tparams1 = tp1.typeParams
20842084
val tparams2 = tp2.typeParams

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -1018,8 +1018,14 @@ object Types {
10181018
*/
10191019
def safe_& (that: Type)(using Context): Type = (this, that) match {
10201020
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
1021-
TypeBounds(OrType(lo1.stripLazyRef, lo2.stripLazyRef), AndType(hi1.stripLazyRef, hi2.stripLazyRef))
1022-
case _ => this & that
1021+
def safeOrType(tp1: Type, tp2: Type): Type =
1022+
ctx.typeComparer.liftIfHK(tp1, tp2, OrType(_, _), safeOrType, _ & _)
1023+
def safeAndType(tp1: Type, tp2: Type): Type =
1024+
ctx.typeComparer.liftIfHK(tp1, tp2, AndType(_, _), safeAndType, _ | _)
1025+
1026+
TypeBounds(safeOrType(lo1.stripLazyRef, lo2.stripLazyRef), safeAndType(hi1.stripLazyRef, hi2.stripLazyRef))
1027+
case _ =>
1028+
this & that
10231029
}
10241030

10251031
/** `this & that`, but handle CyclicReferences by falling back to `safe_&`.

tests/pending/pos/i9346.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
trait Foo[A] {
2+
type Repr[+O] <: Foo[O] {
3+
type Repr[+OO] = Foo.this.Repr[OO]
4+
}
5+
6+
def foo: Repr[A]
7+
8+
def bar: Repr[A] = this.foo.foo
9+
}

0 commit comments

Comments
 (0)