Skip to content

Commit 11f06fe

Browse files
authored
Merge pull request #1407 from dotty-staging/fix-#1401
Fix #1401: Make sure all references are forwarded
2 parents 80a65f4 + 1a3aeb1 commit 11f06fe

File tree

8 files changed

+71
-15
lines changed

8 files changed

+71
-15
lines changed

src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class ScalaSettings extends Settings.SettingGroup {
3737
val usejavacp = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.")
3838
val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing.")
3939
val version = BooleanSetting("-version", "Print product version and exit.")
40-
val pageWidth = IntSetting("-pagewidth", "Set page width", 80)
40+
val pageWidth = IntSetting("-pagewidth", "Set page width", 120)
4141

4242
val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.")
4343
val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.")

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -361,13 +361,23 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
361361
* to the current scope, provided (1) variances of both aliases are the same, and
362362
* (2) X is not yet defined in current scope. This "short-circuiting" prevents
363363
* long chains of aliases which would have to be traversed in type comparers.
364+
*
365+
* Note: Test i1401.scala shows that `forwardRefs` is also necessary
366+
* for typechecking in the case where self types refer to type parameters
367+
* that are upper-bounded by subclass instances.
364368
*/
365369
def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match {
366370
case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 =>
367-
for (pref <- prefs)
368-
for (argSym <- pref.decls)
369-
if (argSym is BaseTypeArg)
370-
forwardRef(argSym, from, to, cls, decls)
371+
for (pref <- prefs) {
372+
def forward(): Unit =
373+
for (argSym <- pref.decls)
374+
if (argSym is BaseTypeArg)
375+
forwardRef(argSym, from, to, cls, decls)
376+
pref.info match {
377+
case info: TempClassInfo => info.addSuspension(forward)
378+
case _ => forward()
379+
}
380+
}
371381
case _ =>
372382
}
373383

@@ -419,9 +429,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
419429
s"redefinition of ${decls.lookup(name).debugString} in ${cls.showLocated}")
420430
enterArgBinding(formals(name), refinedInfo, cls, decls)
421431
}
422-
// Forward definitions in super classes that have one of the refined paramters
432+
// Forward definitions in super classes that have one of the refined parameters
423433
// as aliases directly to the refined info.
424-
// Note that this cannot be fused bwith the previous loop because we now
434+
// Note that this cannot be fused with the previous loop because we now
425435
// assume that all arguments have been entered in `decls`.
426436
refinements foreachBinding { (name, refinedInfo) =>
427437
forwardRefs(formals(name), refinedInfo, parentRefs)

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3043,9 +3043,28 @@ object Types {
30433043
override def toString = s"ClassInfo($prefix, $cls)"
30443044
}
30453045

3046-
final class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[TypeRef], decls: Scope, selfInfo: DotClass)
3046+
class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[TypeRef], decls: Scope, selfInfo: DotClass)
30473047
extends ClassInfo(prefix, cls, classParents, decls, selfInfo)
30483048

3049+
/** A class for temporary class infos where `parents` are not yet known. */
3050+
final class TempClassInfo(prefix: Type, cls: ClassSymbol, decls: Scope, selfInfo: DotClass)
3051+
extends CachedClassInfo(prefix, cls, Nil, decls, selfInfo) {
3052+
3053+
/** A list of actions that were because they rely on the class info of `cls` to
3054+
* be no longer temporary. These actions will be performed once `cls` gets a real
3055+
* ClassInfo.
3056+
*/
3057+
private var suspensions: List[() => Unit] = Nil
3058+
3059+
def addSuspension(suspension: () => Unit): Unit = suspensions ::= suspension
3060+
3061+
/** Install classinfo with known parents in `denot` and resume all suspensions */
3062+
def finalize(denot: SymDenotation, parents: List[TypeRef])(implicit ctx: Context) = {
3063+
denot.info = derivedClassInfo(classParents = parents)
3064+
suspensions.foreach(_())
3065+
}
3066+
}
3067+
30493068
object ClassInfo {
30503069
def apply(prefix: Type, cls: ClassSymbol, classParents: List[TypeRef], decls: Scope, selfInfo: DotClass = NoType)(implicit ctx: Context) =
30513070
unique(new CachedClassInfo(prefix, cls, classParents, decls, selfInfo))

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ object Scala2Unpickler {
106106
// `denot.sourceModule.exists` provision i859.scala crashes in the backend.
107107
denot.owner.thisType select denot.sourceModule
108108
else selfInfo
109-
denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, Nil, decls, ost) // first rough info to avoid CyclicReferences
109+
val tempInfo = new TempClassInfo(denot.owner.thisType, denot.classSymbol, decls, ost)
110+
denot.info = tempInfo // first rough info to avoid CyclicReferences
110111
var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls)
111112
if (parentRefs.isEmpty) parentRefs = defn.ObjectType :: Nil
112113
for (tparam <- tparams) {
@@ -132,8 +133,7 @@ object Scala2Unpickler {
132133
registerCompanionPair(scalacCompanion, denot.classSymbol)
133134
}
134135

135-
denot.info = ClassInfo( // final info, except possibly for typeparams ordering
136-
denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost)
136+
tempInfo.finalize(denot, parentRefs) // install final info, except possibly for typeparams ordering
137137
denot.ensureTypeParamsInCorrectOrder()
138138
}
139139
}

src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
403403
case impl: Template =>
404404
modText(tree.mods, if ((tree).mods is Trait) "trait" else "class") ~~
405405
nameIdText(tree) ~ withEnclosingDef(tree) { toTextTemplate(impl) } ~
406-
(if (tree.hasType && ctx.settings.verbose.value) s"[decls = ${tree.symbol.info.decls}]" else "")
406+
(if (tree.hasType && ctx.settings.verbose.value) i"[decls = ${tree.symbol.info.decls}]" else "")
407407
case rhs: TypeBoundsTree =>
408408
typeDefText(toText(rhs))
409409
case _ =>

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,8 @@ class Namer { typer: Typer =>
688688
else createSymbol(self)
689689

690690
// pre-set info, so that parent types can refer to type params
691-
denot.info = ClassInfo(cls.owner.thisType, cls, Nil, decls, selfInfo)
691+
val tempInfo = new TempClassInfo(cls.owner.thisType, cls, decls, selfInfo)
692+
denot.info = tempInfo
692693

693694
// Ensure constructor is completed so that any parameter accessors
694695
// which have type trees deriving from its parameters can be
@@ -704,7 +705,8 @@ class Namer { typer: Typer =>
704705
typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs")
705706

706707
index(rest)(inClassContext(selfInfo))
707-
denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo)
708+
tempInfo.finalize(denot, parentRefs)
709+
708710
Checking.checkWellFormed(cls)
709711
if (isDerivedValueClass(cls)) cls.setFlag(Final)
710712
cls.setApplicableFlags(

test/dotc/scala-collections.whitelist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
./scala-scala/src/library/scala/collection/immutable/Seq.scala
8484
./scala-scala/src/library/scala/collection/mutable/IndexedSeq.scala
8585
./scala-scala/src/library/scala/collection/mutable/ListBuffer.scala
86-
#./scala-scala/src/library/scala/collection/mutable/BufferLike.scala // works under junit, fails under partest, but can't see more info on the cause
86+
./scala-scala/src/library/scala/collection/mutable/BufferLike.scala
8787

8888
./scala-scala/src/library/scala/collection/mutable/ArrayBuilder.scala
8989

tests/pos/i1401.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package i1401
2+
3+
trait Subtractable[A, +Repr <: Subtractable[A, Repr]] {
4+
def -(elem: A): Repr
5+
}
6+
7+
trait BufferLike[BA, +This <: BufferLike[BA, This] with Buffer[BA]]
8+
extends Subtractable[BA, This]
9+
{ self : This =>
10+
11+
/* Without fix-#1401:
12+
*
13+
error: overriding method - in trait Subtractable of type (elem: A)This & i1401.Buffer[A];
14+
method - of type (elem: BA)This has incompatible type
15+
def -(elem: BA): This
16+
^
17+
one error found
18+
*/
19+
def -(elem: BA): This
20+
}
21+
22+
trait Buffer[A] extends BufferLike[A, Buffer[A]]
23+
24+
25+

0 commit comments

Comments
 (0)