Skip to content

Fix #1401: Make sure all references are forwarded #1407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ScalaSettings extends Settings.SettingGroup {
val usejavacp = BooleanSetting("-usejavacp", "Utilize the java.class.path in classpath resolution.")
val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing.")
val version = BooleanSetting("-version", "Print product version and exit.")
val pageWidth = IntSetting("-pagewidth", "Set page width", 80)
val pageWidth = IntSetting("-pagewidth", "Set page width", 120)

val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.")
val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.")
Expand Down
22 changes: 16 additions & 6 deletions src/dotty/tools/dotc/core/TypeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -361,13 +361,23 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
* to the current scope, provided (1) variances of both aliases are the same, and
* (2) X is not yet defined in current scope. This "short-circuiting" prevents
* long chains of aliases which would have to be traversed in type comparers.
*
* Note: Test i1401.scala shows that `forwardRefs` is also necessary
* for typechecking in the case where self types refer to type parameters
* that are upper-bounded by subclass instances.
*/
def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match {
case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 =>
for (pref <- prefs)
for (argSym <- pref.decls)
if (argSym is BaseTypeArg)
forwardRef(argSym, from, to, cls, decls)
for (pref <- prefs) {
def forward(): Unit =
for (argSym <- pref.decls)
if (argSym is BaseTypeArg)
forwardRef(argSym, from, to, cls, decls)
pref.info match {
case info: TempClassInfo => info.addSuspension(forward)
case _ => forward()
}
}
case _ =>
}

Expand Down Expand Up @@ -419,9 +429,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
s"redefinition of ${decls.lookup(name).debugString} in ${cls.showLocated}")
enterArgBinding(formals(name), refinedInfo, cls, decls)
}
// Forward definitions in super classes that have one of the refined paramters
// Forward definitions in super classes that have one of the refined parameters
// as aliases directly to the refined info.
// Note that this cannot be fused bwith the previous loop because we now
// Note that this cannot be fused with the previous loop because we now
// assume that all arguments have been entered in `decls`.
refinements foreachBinding { (name, refinedInfo) =>
forwardRefs(formals(name), refinedInfo, parentRefs)
Expand Down
21 changes: 20 additions & 1 deletion src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3043,9 +3043,28 @@ object Types {
override def toString = s"ClassInfo($prefix, $cls)"
}

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

/** A class for temporary class infos where `parents` are not yet known. */
final class TempClassInfo(prefix: Type, cls: ClassSymbol, decls: Scope, selfInfo: DotClass)
extends CachedClassInfo(prefix, cls, Nil, decls, selfInfo) {

/** A list of actions that were because they rely on the class info of `cls` to
* be no longer temporary. These actions will be performed once `cls` gets a real
* ClassInfo.
*/
private var suspensions: List[() => Unit] = Nil

def addSuspension(suspension: () => Unit): Unit = suspensions ::= suspension

/** Install classinfo with known parents in `denot` and resume all suspensions */
def finalize(denot: SymDenotation, parents: List[TypeRef])(implicit ctx: Context) = {
denot.info = derivedClassInfo(classParents = parents)
suspensions.foreach(_())
}
}

object ClassInfo {
def apply(prefix: Type, cls: ClassSymbol, classParents: List[TypeRef], decls: Scope, selfInfo: DotClass = NoType)(implicit ctx: Context) =
unique(new CachedClassInfo(prefix, cls, classParents, decls, selfInfo))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ object Scala2Unpickler {
// `denot.sourceModule.exists` provision i859.scala crashes in the backend.
denot.owner.thisType select denot.sourceModule
else selfInfo
denot.info = ClassInfo(denot.owner.thisType, denot.classSymbol, Nil, decls, ost) // first rough info to avoid CyclicReferences
val tempInfo = new TempClassInfo(denot.owner.thisType, denot.classSymbol, decls, ost)
denot.info = tempInfo // first rough info to avoid CyclicReferences
var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls)
if (parentRefs.isEmpty) parentRefs = defn.ObjectType :: Nil
for (tparam <- tparams) {
Expand All @@ -132,8 +133,7 @@ object Scala2Unpickler {
registerCompanionPair(scalacCompanion, denot.classSymbol)
}

denot.info = ClassInfo( // final info, except possibly for typeparams ordering
denot.owner.thisType, denot.classSymbol, parentRefs, decls, ost)
tempInfo.finalize(denot, parentRefs) // install final info, except possibly for typeparams ordering
denot.ensureTypeParamsInCorrectOrder()
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case impl: Template =>
modText(tree.mods, if ((tree).mods is Trait) "trait" else "class") ~~
nameIdText(tree) ~ withEnclosingDef(tree) { toTextTemplate(impl) } ~
(if (tree.hasType && ctx.settings.verbose.value) s"[decls = ${tree.symbol.info.decls}]" else "")
(if (tree.hasType && ctx.settings.verbose.value) i"[decls = ${tree.symbol.info.decls}]" else "")
case rhs: TypeBoundsTree =>
typeDefText(toText(rhs))
case _ =>
Expand Down
6 changes: 4 additions & 2 deletions src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,8 @@ class Namer { typer: Typer =>
else createSymbol(self)

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

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

index(rest)(inClassContext(selfInfo))
denot.info = ClassInfo(cls.owner.thisType, cls, parentRefs, decls, selfInfo)
tempInfo.finalize(denot, parentRefs)

Checking.checkWellFormed(cls)
if (isDerivedValueClass(cls)) cls.setFlag(Final)
cls.setApplicableFlags(
Expand Down
2 changes: 1 addition & 1 deletion test/dotc/scala-collections.whitelist
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
./scala-scala/src/library/scala/collection/immutable/Seq.scala
./scala-scala/src/library/scala/collection/mutable/IndexedSeq.scala
./scala-scala/src/library/scala/collection/mutable/ListBuffer.scala
#./scala-scala/src/library/scala/collection/mutable/BufferLike.scala // works under junit, fails under partest, but can't see more info on the cause
./scala-scala/src/library/scala/collection/mutable/BufferLike.scala

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

Expand Down
25 changes: 25 additions & 0 deletions tests/pos/i1401.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package i1401

trait Subtractable[A, +Repr <: Subtractable[A, Repr]] {
def -(elem: A): Repr
}

trait BufferLike[BA, +This <: BufferLike[BA, This] with Buffer[BA]]
extends Subtractable[BA, This]
{ self : This =>

/* Without fix-#1401:
*
error: overriding method - in trait Subtractable of type (elem: A)This & i1401.Buffer[A];
method - of type (elem: BA)This has incompatible type
def -(elem: BA): This
^
one error found
*/
def -(elem: BA): This
}

trait Buffer[A] extends BufferLike[A, Buffer[A]]