Skip to content

Commit ef5c50a

Browse files
committed
Merge pull request #1031 from dotty-staging/change-early-typeparams3
Change early typeparams, take 3
2 parents 2503291 + 17dcd7c commit ef5c50a

14 files changed

+89
-27
lines changed

project/Build.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import scala.reflect.io.Path
66

77
object DottyBuild extends Build {
88

9-
val travisMemLimit = List("-Xmx1g", "-Xss2m")
9+
// Currently, this cannot be increased without hitting the maximum amount of memory
10+
// available on the Jenkins VMs
11+
val travisMemLimit = List("-Xmx1100m")
1012

1113
val JENKINS_BUILD = "dotty.jenkins.build"
1214

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/core/Types.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,11 +2506,11 @@ object Types {
25062506
// ----- Skolem types -----------------------------------------------
25072507

25082508
/** A skolem type reference with underlying type `binder`. */
2509-
abstract case class SkolemType(info: Type) extends CachedProxyType with ValueType with SingletonType {
2509+
abstract case class SkolemType(info: Type) extends UncachedProxyType with ValueType with SingletonType {
25102510
override def underlying(implicit ctx: Context) = info
25112511
def derivedSkolemType(info: Type)(implicit ctx: Context) =
25122512
if (info eq this.info) this else SkolemType(info)
2513-
override def computeHash: Int = identityHash
2513+
override def hashCode: Int = identityHash
25142514
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
25152515
override def toString = s"Skolem($info)"
25162516
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,20 +138,20 @@ object Checking {
138138
case SuperType(thistp, _) => isInteresting(thistp)
139139
case AndType(tp1, tp2) => isInteresting(tp1) || isInteresting(tp2)
140140
case OrType(tp1, tp2) => isInteresting(tp1) && isInteresting(tp2)
141-
case _: RefinedType => false
142-
// Note: it's important not to visit parents of RefinedTypes,
143-
// since otherwise spurious #Apply projections might be inserted.
141+
case _: RefinedType => true
144142
case _ => false
145143
}
146144
// If prefix is interesting, check info of typeref recursively, marking the referred symbol
147145
// with NoCompleter. This provokes a CyclicReference when the symbol
148146
// is hit again. Without this precaution we could stackoverflow here.
149147
if (isInteresting(pre)) {
150148
val info = tp.info
151-
val symInfo = tp.symbol.info
152-
if (tp.symbol.exists) tp.symbol.info = SymDenotations.NoCompleter
149+
val sym = tp.symbol
150+
if (sym.infoOrCompleter == SymDenotations.NoCompleter) throw CyclicReference(sym)
151+
val symInfo = sym.info
152+
if (sym.exists) sym.info = SymDenotations.NoCompleter
153153
try checkInfo(info)
154-
finally if (tp.symbol.exists) tp.symbol.info = symInfo
154+
finally if (sym.exists) sym.info = symInfo
155155
}
156156
tp
157157
} catch {

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
882882
else
883883
(arg, WildcardType)
884884
val arg1 = typed(desugaredArg, argPt)
885-
adaptTypeArg(arg1, if (tparam.isCompleted) tparam.info else WildcardType)
885+
adaptTypeArg(arg1, tparam.info)
886886
}
887887
val args1 = args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]]
888888
// check that arguments conform to bounds is done in phase PostTyper

test/dotc/scala-collections.whitelist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@
266266
./scala-scala/src/library/scala/collection/generic/ParFactory.scala
267267

268268
# https://github.com/lampepfl/dotty/issues/974 -> @smarter
269-
#./scala-scala/src/library/scala/collection/generic/MutableSortedSetFactory.scala
269+
./scala-scala/src/library/scala/collection/generic/MutableSortedSetFactory.scala
270270

271271
# cyclic reference, maybe related to #974 -> @smarter
272272
#./scala-scala/src/library/scala/collection/generic/ParSetFactory.scala

test/dotc/tests.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class tests extends CompilerTest {
158158
@Test def neg_finalSealed = compileFile(negDir, "final-sealed", xerrors = 2)
159159
@Test def neg_i705 = compileFile(negDir, "i705-inner-value-class", xerrors = 7)
160160
@Test def neg_i866 = compileFile(negDir, "i866", xerrors = 2)
161+
@Test def neg_i974 = compileFile(negDir, "i974", xerrors = 2)
161162
@Test def neg_moduleSubtyping = compileFile(negDir, "moduleSubtyping", xerrors = 4)
162163
@Test def neg_escapingRefs = compileFile(negDir, "escapingRefs", xerrors = 2)
163164
@Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8)
@@ -185,6 +186,15 @@ class tests extends CompilerTest {
185186
.toList
186187

187188
@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)
196+
@Test def compileIndexedSeq = compileLine("./scala-scala/src/library/scala/collection/immutable/IndexedSeq.scala")
197+
188198
@Test def dotty = compileDir(dottyDir, ".", List("-deep", "-Ycheck-reentrant"))(allowDeepSubtypes) // note the -deep argument
189199

190200
@Test def dotc_ast = compileDir(dotcDir, "ast")

test/test/CompilerTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ abstract class CompilerTest extends DottyTest {
221221
case ExistsSame => // nothing else to do
222222
case ExistsDifferent =>
223223
val nextDest = dest.parent / (dest match {
224-
case f: SFile => SFile(replaceVersion(f.stripExtension, nr)).addExtension(f.extension)
225224
case d: Directory => Directory(replaceVersion(d.name, nr))
225+
case f => SFile(replaceVersion(f.stripExtension, nr)).addExtension(f.extension)
226226
})
227227
computeDestAndCopyFiles(source, nextDest, kind, flags, nerr, nr + 1, partestOutput)
228228
}

tests/neg/i974.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Foo[T <: Bar[T]#Elem] // error: illegal cyclic reference
2+
trait Bar[T] {
3+
type Elem = T
4+
}
5+
trait Foo2[T <: Bar2[T]#Elem] // error: illegal cyclic reference
6+
trait Bar2[T] {
7+
type Elem = T
8+
}

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+
}

tests/pos/i974.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class Foo[A]
2+
class Bar[CC[X] <: Foo[CC[X]]]

0 commit comments

Comments
 (0)