Skip to content

Commit b54e2a1

Browse files
committed
Compute type params in namer without completing the whole info
Type params should be computed before computing the whole info of a type. Without the patch we get a cyclic reference in the compileMixed test.
1 parent 00fb3a2 commit b54e2a1

File tree

6 files changed

+62
-15
lines changed

6 files changed

+62
-15
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,14 @@ object SymDenotations {
18021802
def withModuleClass(moduleClassFn: Context => Symbol): this.type = { myModuleClassFn = moduleClassFn; this }
18031803
}
18041804

1805+
/** A subclass of LazyTypes where type parameters can be completed independently of
1806+
* the info.
1807+
*/
1808+
abstract class TypeParamsCompleter extends LazyType {
1809+
/** The type parameters computed by the completer before completion has finished */
1810+
def completerTypeParams(sym: Symbol): List[TypeSymbol]
1811+
}
1812+
18051813
val NoSymbolFn = (ctx: Context) => NoSymbol
18061814

18071815
/** A missing completer */

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package core
44
import Types._
55
import Contexts._
66
import Symbols._
7+
import SymDenotations.TypeParamsCompleter
78
import Decorators._
89
import util.Stats._
910
import util.common._
@@ -240,15 +241,21 @@ class TypeApplications(val self: Type) extends AnyVal {
240241
case self: TypeRef =>
241242
val tsym = self.symbol
242243
if (tsym.isClass) tsym.typeParams
243-
else if (tsym.isAliasType) self.underlying.typeParams
244-
else if (tsym.isCompleting)
245-
// We are facing a problem when computing the type parameters of an uncompleted
246-
// abstract type. We can't access the bounds of the symbol yet because that
247-
// would cause a cause a cyclic reference. So we return `Nil` instead
248-
// and try to make up for it later. The acrobatics in Scala2Unpicker#readType
249-
// for reading a TypeRef show what's neeed.
250-
Nil
251-
else tsym.info.typeParams
244+
else tsym.infoOrCompleter match {
245+
case completer: TypeParamsCompleter =>
246+
val tparams = completer.completerTypeParams(tsym)
247+
if (tsym.isClass) tparams
248+
else defn.LambdaTrait(tparams.map(_.variance)).typeParams
249+
case _ =>
250+
if (!tsym.isCompleting || tsym.isAliasType) tsym.info.typeParams
251+
else
252+
// We are facing a problem when computing the type parameters of an uncompleted
253+
// abstract type. We can't access the bounds of the symbol yet because that
254+
// would cause a cause a cyclic reference. So we return `Nil` instead
255+
// and try to make up for it later. The acrobatics in Scala2Unpicker#readType
256+
// for reading a TypeRef show what's needed.
257+
Nil
258+
}
252259
case self: RefinedType =>
253260
// inlined and optimized version of
254261
// val sym = self.LambdaTrait

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
3535
* Instead we produce an annotated type that marks the prefix as unsafe:
3636
*
3737
* (x: (C @ UnsafeNonvariant)#T)C#T
38-
38+
3939
* We also set a global state flag `unsafeNonvariant` to the current run.
4040
* When typing a Select node, typer will check that flag, and if it
4141
* points to the current run will scan the result type of the select for

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,31 @@ class Namer { typer: Typer =>
478478
}
479479

480480
/** The completer of a symbol defined by a member def or import (except ClassSymbols) */
481-
class Completer(val original: Tree)(implicit ctx: Context) extends LazyType {
481+
class Completer(val original: Tree)(implicit ctx: Context) extends TypeParamsCompleter {
482482

483483
protected def localContext(owner: Symbol) = ctx.fresh.setOwner(owner).setTree(original)
484484

485+
private var myTypeParams: List[TypeSymbol] = null
486+
private var nestedCtx: Context = null
487+
488+
def completerTypeParams(sym: Symbol): List[TypeSymbol] = {
489+
if (myTypeParams == null) {
490+
//println(i"completing type params of $sym in ${sym.owner}")
491+
myTypeParams = original match {
492+
case tdef: TypeDef =>
493+
nestedCtx = localContext(sym).setNewScope
494+
locally {
495+
implicit val ctx: Context = nestedCtx
496+
completeParams(tdef.tparams)
497+
tdef.tparams.map(symbolOfTree(_).asType)
498+
}
499+
case _ =>
500+
Nil
501+
}
502+
}
503+
myTypeParams
504+
}
505+
485506
private def typeSig(sym: Symbol): Type = original match {
486507
case original: ValDef =>
487508
if (sym is Module) moduleValSig(sym)
@@ -492,7 +513,7 @@ class Namer { typer: Typer =>
492513
typer1.defDefSig(original, sym)(localContext(sym).setTyper(typer1))
493514
case original: TypeDef =>
494515
assert(!original.isClassDef)
495-
typeDefSig(original, sym)(localContext(sym).setNewScope)
516+
typeDefSig(original, sym, completerTypeParams(sym))(nestedCtx)
496517
case imp: Import =>
497518
try {
498519
val expr1 = typedAheadExpr(imp.expr, AnySelectionProto)
@@ -840,9 +861,7 @@ class Namer { typer: Typer =>
840861
else valOrDefDefSig(ddef, sym, typeParams, paramSymss, wrapMethType)
841862
}
842863

843-
def typeDefSig(tdef: TypeDef, sym: Symbol)(implicit ctx: Context): Type = {
844-
completeParams(tdef.tparams)
845-
val tparamSyms = tdef.tparams map symbolOfTree
864+
def typeDefSig(tdef: TypeDef, sym: Symbol, tparamSyms: List[TypeSymbol])(implicit ctx: Context): Type = {
846865
val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree]
847866
//val toParameterize = tparamSyms.nonEmpty && !isDerived
848867
//val needsLambda = sym.allOverriddenSymbols.exists(_ is HigherKinded) && !isDerived

test/dotc/tests.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ class tests extends CompilerTest {
186186
.toList
187187

188188
@Test def compileStdLib = compileList("compileStdLib", stdlibFiles, "-migration" :: scala2mode)
189+
@Test def compileMixed = compileLine(
190+
"""tests/pos/B.scala
191+
|./scala-scala/src/library/scala/collection/immutable/Seq.scala
192+
|./scala-scala/src/library/scala/package.scala
193+
|./scala-scala/src/library/scala/collection/GenSeqLike.scala
194+
|./scala-scala/src/library/scala/collection/SeqLike.scala
195+
|./scala-scala/src/library/scala/collection/generic/GenSeqFactory.scala""".stripMargin)
189196
@Test def compileIndexedSeq = compileLine("./scala-scala/src/library/scala/collection/immutable/IndexedSeq.scala")
190197

191198
@Test def dotty = compileDir(dottyDir, ".", List("-deep", "-Ycheck-reentrant"))(allowDeepSubtypes) // note the -deep argument

tests/pos/B.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object B{
2+
def main(args: Array[String]): Unit = {
3+
val s = List(1,2,3)
4+
()
5+
}
6+
}

0 commit comments

Comments
 (0)