diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index f468a573f7ca..592f2c5de725 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -199,7 +199,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } compareWild case tp2: LazyRef => - isSubType(tp1, tp2.ref) + !tp2.evaluating && isSubType(tp1, tp2.ref) case tp2: AnnotatedType => isSubType(tp1, tp2.tpe) // todo: refine? case tp2: ThisType => @@ -299,7 +299,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } compareWild case tp1: LazyRef => - isSubType(tp1.ref, tp2) + // If `tp1` is in train of being evaluated, don't force it + // because that would cause an assertionError. Return false instead. + // See i859.scala for an example where we hit this case. + !tp1.evaluating && isSubType(tp1.ref, tp2) case tp1: AnnotatedType => isSubType(tp1.tpe, tp2) case AndType(tp11, tp12) => diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index e266bab6f482..d76f57ba6f30 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1972,7 +1972,7 @@ object Types { case class LazyRef(refFn: () => Type) extends UncachedProxyType with ValueType { private var myRef: Type = null private var computed = false - lazy val ref = { + def ref = { if (computed) assert(myRef != null) else { computed = true @@ -1980,6 +1980,7 @@ object Types { } myRef } + def evaluating = computed && myRef == null override def underlying(implicit ctx: Context) = ref override def toString = s"LazyRef($ref)" override def equals(other: Any) = other match { diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 618e3ceeac43..abf31a006abb 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -101,10 +101,12 @@ object Scala2Unpickler { case cinfo => (Nil, cinfo) } val ost = - if ((selfInfo eq NoType) && (denot is ModuleClass)) + if ((selfInfo eq NoType) && (denot is ModuleClass) && denot.sourceModule.exists) + // it seems sometimes the source module does not exist for a module class. + // An example is `scala.reflect.internal.Trees.Template$. Without the + // `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 var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls) if (parentRefs.isEmpty) parentRefs = defn.ObjectType :: Nil diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 2944d69e90c2..16917742d811 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -103,6 +103,7 @@ class tests extends CompilerTest { @Test def pos_i871 = compileFile(posSpecialDir, "i871", scala2mode) @Test def pos_variancesConstr = compileFile(posSpecialDir, "variances-constr", scala2mode) + @Test def pos_859 = compileFile(posSpecialDir, "i859", scala2mode)(allowDeepSubtypes) @Test def new_all = compileFiles(newDir, twice) diff --git a/tests/pos-special/i859.scala b/tests/pos-special/i859.scala new file mode 100644 index 000000000000..a9f6b51c9c4b --- /dev/null +++ b/tests/pos-special/i859.scala @@ -0,0 +1,3 @@ +class Analyzer { + def foo: scala.tools.nsc.Global = ??? +}