Skip to content

Commit 6c91684

Browse files
committed
Fix tricky bug coming up when compiling TraversableViewLike.
1 parent 4900abc commit 6c91684

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,36 @@ class Namer { typer: Typer =>
789789
/** The type signature of a DefDef with given symbol */
790790
def defDefSig(ddef: DefDef, sym: Symbol)(implicit ctx: Context) = {
791791
val DefDef(name, tparams, vparamss, _, _) = ddef
792-
completeParams(tparams)
793-
vparamss foreach completeParams
794792
val isConstructor = name == nme.CONSTRUCTOR
793+
794+
// The following 3 lines replace what was previously just completeParams(tparams).
795+
// But that can cause bad bounds being computed, as witnessed by
796+
// tests/pos/paramcycle.scala. The problematic sequence is this:
797+
// 0. Class constructor gets completed.
798+
// 1. Type parameter CP of constructor gets completed
799+
// 2. As a first step CP's bounds are set to Nothing..Any.
800+
// 3. CP's real type bound demands the completion of corresponding type parameter DP
801+
// of enclosing class.
802+
// 4. Type parameter DP has a rhs a DerivedFromParam tree, as installed by
803+
// desugar.classDef
804+
// 5. The completion of DP then copies the current bounds of CP, which are still Nothing..Any.
805+
// 6. The completion of CP finishes installing the real type bounds.
806+
// Consequence: CP ends up with the wrong bounds!
807+
// To avoid this we always complete type parameters of a class before the type parameters
808+
// of the class constructor, but after having indexed the constructor parameters (because
809+
// indexing is needed to provide a symbol to copy for DP's completion.
810+
// With the patch, we get instead the following sequence:
811+
// 0. Class constructor gets completed.
812+
// 1. Class constructor parameter CP is indexed.
813+
// 2. Class parameter DP starts completion.
814+
// 3. Info of CP is computed (to be copied to DP).
815+
// 4. CP is completed.
816+
// 5. Info of CP is copied to DP and DP is completed.
817+
index(tparams)
818+
if (isConstructor) sym.owner.typeParams.foreach(_.ensureCompleted())
819+
for (tparam <- tparams) typedAheadExpr(tparam)
820+
821+
vparamss foreach completeParams
795822
def typeParams = tparams map symbolOfTree
796823
val paramSymss = ctx.normalizeIfConstructor(vparamss.nestedMap(symbolOfTree), isConstructor)
797824
def wrapMethType(restpe: Type): Type = {
@@ -834,8 +861,11 @@ class Namer { typer: Typer =>
834861
case bounds: TypeBounds => bounds
835862
case alias => TypeAlias(alias, if (sym is Local) sym.variance else 0)
836863
}
837-
sym.info = NoCompleter
838-
sym.info = checkNonCyclic(sym, unsafeInfo, reportErrors = true)
864+
if (isDerived) sym.info = unsafeInfo
865+
else {
866+
sym.info = NoCompleter
867+
sym.info = checkNonCyclic(sym, unsafeInfo, reportErrors = true)
868+
}
839869
etaExpandArgs.apply(sym.info)
840870
}
841871

tests/pos/paramcycle.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import scala.collection._
2+
import scala.collection.generic._
3+
4+
trait ViewMkString[+A]
5+
6+
trait TraversableViewLike[+A,
7+
+Coll,
8+
+This <: TraversableView[A, Coll] with TraversableViewLike[A, Coll, This]]
9+
extends Traversable[A] with TraversableLike[A, This] with ViewMkString[A] { self =>
10+
11+
def f[B](pf: PartialFunction[A, B]) =
12+
filter(pf.isDefinedAt).map(pf)
13+
14+
}
15+
16+
trait TraversableView[+A, +Coll] extends TraversableViewLike[A, Coll, TraversableView[A, Coll]] { }
17+
18+

0 commit comments

Comments
 (0)