Skip to content

Commit 48f78cd

Browse files
committed
Simpler cycle detection
Turns out that the last commit was a red herring. None of the hoops it jumped though was necessary. Instead there was a bug in isRef which caused `&` to erroneously compute T & Int as Int. The bug was that we always approximated alias types by their high bound. But in the present case, this leads to errors because U gets 'bounds >: Nothing <: Any', but it was still an alias type (i.e. its Deferred flag is not set). The fix dereferences aliases only if their info is a TypeAlias.
1 parent 642c5e4 commit 48f78cd

File tree

4 files changed

+20
-23
lines changed

4 files changed

+20
-23
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,6 @@ object StdNames {
304304
val ArrayAnnotArg: N = "ArrayAnnotArg"
305305
val Constant: N = "Constant"
306306
val ConstantType: N = "ConstantType"
307-
val DummyHi: N = "DummyHi"
308-
val DummyLo: N = "DummyLo"
309307
val ExistentialTypeTree: N = "ExistentialTypeTree"
310308
val Flag : N = "Flag"
311309
val Ident: N = "Ident"

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ object Types {
104104
*/
105105
def isRef(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match {
106106
case this1: TypeRef =>
107-
val thissym = this1.symbol
108-
if (thissym.isAliasType) this1.info.bounds.hi.isRef(sym)
109-
else thissym eq sym
107+
this1.info match { // see comment in Namers/typeDefSig
108+
case TypeBounds(lo, hi) if lo eq hi => hi.isRef(sym)
109+
case _ => this1.symbol eq sym
110+
}
110111
case this1: RefinedType =>
111112
// make sure all refinements are type arguments
112113
this1.parent.isRef(sym) && this.argInfos.nonEmpty

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

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,17 @@ class Namer { typer: Typer =>
673673

674674
def typeDefSig(tdef: TypeDef, sym: Symbol)(implicit ctx: Context): Type = {
675675
completeParams(tdef.tparams)
676-
setDummyInfo(sym)
676+
sym.info = TypeBounds.empty
677+
// Temporarily set info of defined type T to ` >: Nothing <: Any.
678+
// This is done to avoid cyclic reference errors for F-bounds.
679+
// This is subtle: `sym` has now an empty TypeBounds, but is not automatically
680+
// made an abstract type. If it had been made an abstract type, it would count as an
681+
// abstract type of its enclosing class, which might make that class an invalid
682+
// prefix. I verified this would lead to an error when compiling io.ClassPath.
683+
// A distilled version is in pos/prefix.scala.
684+
//
685+
// The scheme critically relies on an implementation detail of isRef, which
686+
// inspects a TypeRef's info, instead of simply dealiasing alias types.
677687
val tparamSyms = tdef.tparams map symbolOfTree
678688
val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree]
679689
val toParameterize = tparamSyms.nonEmpty && !isDerived
@@ -690,21 +700,4 @@ class Namer { typer: Typer =>
690700
sym.info = NoCompleter
691701
checkNonCyclic(sym, unsafeInfo, reportErrors = true)
692702
}
693-
694-
/** Temporarily set info of defined type T to
695-
*
696-
* T >: dummyLo <: dummyHi
697-
* type dummyLo, dummyHi
698-
*
699-
* This is done to avoid cyclic reference errors for F-bounds.
700-
* The type is intentionally chosen so that it cannot possibly be
701-
* elided when taking a union or intersection.
702-
*/
703-
private def setDummyInfo(sym: Symbol)(implicit ctx: Context): Unit = {
704-
def dummyBound(name: TypeName) =
705-
ctx.newSymbol(sym.owner, name, Synthetic | Deferred, TypeBounds.empty)
706-
val dummyLo = dummyBound(tpnme.DummyLo)
707-
val dummyHi = dummyBound(tpnme.DummyHi)
708-
sym.info = TypeBounds(TypeRef(NoPrefix, dummyLo), TypeRef(NoPrefix, dummyHi))
709-
}
710703
}

tests/pos/prefix.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
abstract class ClassPath {
3+
type AnyClassRep = ClassPath#ClassRep
4+
type ClassRep
5+
}

0 commit comments

Comments
 (0)