Skip to content

Commit f8363e3

Browse files
authored
Merge pull request #3941 from dotty-staging/fix-#3816
Fix #3816: Protect against cycles when unpickling hk types
2 parents cbaa827 + 311a654 commit f8363e3

File tree

7 files changed

+29
-10
lines changed

7 files changed

+29
-10
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package core
55
import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._
66
import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._, Comments._
77
import NameOps._, NameKinds._, Phases._
8+
import TypeApplications.TypeParamInfo
89
import Scopes.Scope
910
import collection.mutable
1011
import collection.BitSet
@@ -1915,6 +1916,11 @@ object SymDenotations {
19151916
override def complete(denot: SymDenotation)(implicit ctx: Context) = self.complete(denot)
19161917
}
19171918

1919+
/** The type parameters computed by the completer before completion has finished */
1920+
def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeParamInfo] =
1921+
if (sym is Touched) Nil // return `Nil` instead of throwing a cyclic reference
1922+
else sym.info.typeParams
1923+
19181924
def decls: Scope = myDecls
19191925
def sourceModule(implicit ctx: Context): Symbol = mySourceModuleFn(ctx)
19201926
def moduleClass(implicit ctx: Context): Symbol = myModuleClassFn(ctx)
@@ -1924,12 +1930,12 @@ object SymDenotations {
19241930
def withModuleClass(moduleClassFn: Context => Symbol): this.type = { myModuleClassFn = moduleClassFn; this }
19251931
}
19261932

1927-
/** A subclass of LazyTypes where type parameters can be completed independently of
1928-
* the info.
1933+
/** A subtrait of LazyTypes where completerTypeParams yields a List[TypeSymbol], which
1934+
* should be completed independently of the info.
19291935
*/
19301936
trait TypeParamsCompleter extends LazyType {
1931-
/** The type parameters computed by the completer before completion has finished */
1932-
def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol]
1937+
override def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] =
1938+
unsupported("completerTypeParams") // should be abstract, but Scala-2 will then compute the wrong type for it
19331939
}
19341940

19351941
val NoSymbolFn = (ctx: Context) => NoSymbol

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,10 @@ class TypeApplications(val self: Type) extends AnyVal {
173173
val tsym = self.symbol
174174
if (tsym.isClass) tsym.typeParams
175175
else if (!tsym.exists) self.info.typeParams
176-
else if (!tsym.isCompleting) tsym.info.typeParams
177-
else Nil
176+
else tsym.infoOrCompleter match {
177+
case info: LazyType => info.completerTypeParams(tsym)
178+
case info => info.typeParams
179+
}
178180
case self: AppliedType =>
179181
if (self.tycon.typeSymbol.isClass) Nil
180182
else self.superType.typeParams

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,12 +745,18 @@ class TreeUnpickler(reader: TastyReader,
745745
}
746746
TypeDef(readTemplate(localCtx))
747747
} else {
748+
sym.info = TypeBounds.empty // needed to avoid cyclic references when unpicklin rhs, see i3816.scala
749+
sym.setFlag(Provisional)
748750
val rhs = readTpt()(localCtx)
749-
sym.info = NoCompleter
751+
sym.info = new NoCompleter {
752+
override def completerTypeParams(sym: Symbol)(implicit ctx: Context) =
753+
rhs.tpe.typeParams
754+
}
750755
sym.info = rhs.tpe match {
751756
case _: TypeBounds | _: ClassInfo => checkNonCyclic(sym, rhs.tpe, reportErrors = false)
752757
case _ => TypeAlias(rhs.tpe)
753758
}
759+
sym.resetFlag(Provisional)
754760
TypeDef(rhs)
755761
}
756762
case PARAM =>

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
614614
/** Force reading type params early, we need them in setClassInfo of subclasses. */
615615
def init()(implicit ctx: Context) = loadTypeParams
616616

617-
def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] =
617+
override def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] =
618618
loadTypeParams
619619
}
620620

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ object Checking {
239239
}
240240
if (isInteresting(pre)) {
241241
val pre1 = this(pre, false, false)
242-
if (locked.contains(tp) || tp.symbol.infoOrCompleter == NoCompleter)
242+
if (locked.contains(tp) || tp.symbol.infoOrCompleter.isInstanceOf[NoCompleter])
243243
throw CyclicReference(tp.symbol)
244244
locked += tp
245245
try checkInfo(tp.info)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ class Namer { typer: Typer =>
824824
private[this] var nestedCtx: Context = null
825825
assert(!original.isClassDef)
826826

827-
def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] = {
827+
override def completerTypeParams(sym: Symbol)(implicit ctx: Context): List[TypeSymbol] = {
828828
if (myTypeParams == null) {
829829
//println(i"completing type params of $sym in ${sym.owner}")
830830
nestedCtx = localContext(sym).setNewScope
@@ -1229,6 +1229,7 @@ class Namer { typer: Typer =>
12291229
sym.info = NoCompleter
12301230
sym.info = checkNonCyclic(sym, unsafeInfo, reportErrors = true)
12311231
}
1232+
sym.resetFlag(Provisional)
12321233

12331234
// Here we pay the price for the cavalier setting info to TypeBounds.empty above.
12341235
// We need to compensate by reloading the denotation of references that might

tests/pickling/i3816.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
trait Iterable { self =>
2+
//type CC <: Iterable { type CC = self.CC }
3+
type DD[X] <: Iterable { type DD[Y] = self.DD[Y] }
4+
}

0 commit comments

Comments
 (0)