Skip to content

Commit cb153a0

Browse files
authored
Merge pull request #10972 from dotty-staging/fix-#10967
2 parents 234cb00 + 78ef3ec commit cb153a0

File tree

5 files changed

+69
-25
lines changed

5 files changed

+69
-25
lines changed

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

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,30 +141,31 @@ object SymDenotations {
141141
}
142142

143143
final def completeFrom(completer: LazyType)(using Context): Unit =
144-
if (Config.showCompletions) {
145-
println(i"${" " * indent}completing ${if (isType) "type" else "val"} $name")
146-
indent += 1
147-
148-
if (myFlags.is(Touched)) throw CyclicReference(this)
149-
myFlags |= Touched
150-
151-
// completions.println(s"completing ${this.debugString}")
152-
try atPhase(validFor.firstPhaseId)(completer.complete(this))
153-
catch {
154-
case ex: CyclicReference =>
155-
println(s"error while completing ${this.debugString}")
156-
throw ex
144+
if completer.needsCompletion(this) then
145+
if (Config.showCompletions) {
146+
println(i"${" " * indent}completing ${if (isType) "type" else "val"} $name")
147+
indent += 1
148+
149+
if (myFlags.is(Touched)) throw CyclicReference(this)
150+
myFlags |= Touched
151+
152+
// completions.println(s"completing ${this.debugString}")
153+
try atPhase(validFor.firstPhaseId)(completer.complete(this))
154+
catch {
155+
case ex: CyclicReference =>
156+
println(s"error while completing ${this.debugString}")
157+
throw ex
158+
}
159+
finally {
160+
indent -= 1
161+
println(i"${" " * indent}completed $name in $owner")
162+
}
157163
}
158-
finally {
159-
indent -= 1
160-
println(i"${" " * indent}completed $name in $owner")
164+
else {
165+
if (myFlags.is(Touched)) throw CyclicReference(this)
166+
myFlags |= Touched
167+
atPhase(validFor.firstPhaseId)(completer.complete(this))
161168
}
162-
}
163-
else {
164-
if (myFlags.is(Touched)) throw CyclicReference(this)
165-
myFlags |= Touched
166-
atPhase(validFor.firstPhaseId)(completer.complete(this))
167-
}
168169

169170
protected[dotc] def info_=(tp: Type): Unit = {
170171
/* // DEBUG
@@ -2517,6 +2518,13 @@ object SymDenotations {
25172518
def withModuleClass(moduleClassFn: Context ?=> Symbol): this.type = { myModuleClassFn = moduleClassFn; this }
25182519

25192520
override def toString: String = getClass.toString
2521+
2522+
/** A hook that is called before trying to complete a symbol with its
2523+
* associated cycle detection via the Touched flag. This is overridden
2524+
* for Type definitions in Namer, where we make sure that owners are
2525+
* completed before nested types.
2526+
*/
2527+
def needsCompletion(symd: SymDenotation)(using Context): Boolean = true
25202528
}
25212529

25222530
object LazyType:

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,13 @@ class TypeApplications(val self: Type) extends AnyVal {
211211

212212
/** If `self` is a generic class, its type parameter symbols, otherwise Nil */
213213
final def typeParamSymbols(using Context): List[TypeSymbol] = typeParams match {
214-
case (_: Symbol) :: _ =>
215-
assert(typeParams.forall(_.isInstanceOf[Symbol]))
216-
typeParams.asInstanceOf[List[TypeSymbol]]
214+
case tparams @ (_: Symbol) :: _ =>
215+
assert(tparams.forall(_.isInstanceOf[Symbol]))
216+
tparams.asInstanceOf[List[TypeSymbol]]
217+
// Note: Two successive calls to typeParams can yield different results here because
218+
// of different completion status. I.e. the first call might produce some symbols,
219+
// whereas the second call gives some LambdaParams. This was observed
220+
// for ticket0137.scala
217221
case _ => Nil
218222
}
219223

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,20 @@ class Namer { typer: Typer =>
840840
private var nestedCtx: Context = null
841841
assert(!original.isClassDef)
842842

843+
/** If completion of the owner of the to be completed symbol has not yet started,
844+
* complete the owner first and check again. This prevents cyclic references
845+
* where we need to copmplete a type parameter that has an owner that is not
846+
* yet completed. Test case is pos/i10967.scala.
847+
*/
848+
override def needsCompletion(symd: SymDenotation)(using Context): Boolean =
849+
val owner = symd.owner
850+
!owner.exists
851+
|| owner.is(Touched)
852+
|| {
853+
owner.ensureCompleted()
854+
!symd.isCompleted
855+
}
856+
843857
override def completerTypeParams(sym: Symbol)(using Context): List[TypeSymbol] =
844858
if myTypeParams == null then
845859
//println(i"completing type params of $sym in ${sym.owner}")

tests/pos/i10638.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package woes
2+
3+
trait Txn[T <: Txn[T]]
4+
5+
trait Impl[Repr[~ <: Txn[~]]] {
6+
final type Ext = Extension[Repr] // Huh!
7+
}
8+
9+
trait Extension[Repr[~ <: Txn[~]]]

tests/pos/i10967.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
trait SomeTrait
2+
3+
trait CollBase[A <: SomeTrait, +CC1[A2 <: SomeTrait]] {
4+
val companion: CollCompanion[CC1]
5+
}
6+
7+
trait Coll[A <: SomeTrait] extends CollBase[A, Coll]
8+
9+
trait CollCompanion[+CC2[A <: SomeTrait]]

0 commit comments

Comments
 (0)