diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 4c051163a58b..30dad2f44847 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -645,7 +645,7 @@ object desugar { .withPos(mdef.pos.startPos) val ValDef(selfName, selfTpt, _) = impl.self val selfMods = impl.self.mods - if (!selfTpt.isEmpty || selfName != nme.WILDCARD) ctx.error(ObjectMayNotHaveSelfType(mdef), impl.self.pos) + if (!selfTpt.isEmpty) ctx.error(ObjectMayNotHaveSelfType(mdef), impl.self.pos) val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(moduleName)), impl.self.rhs) .withMods(selfMods) .withPos(impl.self.pos orElse impl.pos.startPos) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index c82b1c1e85ca..da7bf9f380c4 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -332,14 +332,20 @@ object Denotations { } /** Handle merge conflict by throwing a `MergeError` exception */ - private def mergeConflict(tp1: Type, tp2: Type)(implicit ctx: Context): Type = { + private def mergeConflict(tp1: Type, tp2: Type, that: Denotation)(implicit ctx: Context): Type = { + def showSymbol(sym: Symbol): String = if (sym.exists) sym.showLocated else "[unknown]" def showType(tp: Type) = tp match { case ClassInfo(_, cls, _, _, _) => cls.showLocated case bounds: TypeBounds => i"type bounds $bounds" case _ => tp.show } - if (true) throw new MergeError(s"cannot merge ${showType(tp1)} with ${showType(tp2)}", tp1, tp2) - else throw new Error(s"cannot merge ${showType(tp1)} with ${showType(tp2)}") // flip condition for debugging + val msg = + s"""cannot merge + | ${showSymbol(this.symbol)} of type ${showType(tp1)} and + | ${showSymbol(that.symbol)} of type ${showType(tp2)} + """ + if (true) throw new MergeError(msg, tp1, tp2) + else throw new Error(msg) // flip condition for debugging } /** Merge parameter names of lambda types. If names in corresponding positions match, keep them, @@ -389,13 +395,13 @@ object Denotations { tp2 match { case tp2: TypeBounds => if (safeIntersection) tp1 safe_& tp2 else tp1 & tp2 case tp2: ClassInfo if tp1 contains tp2 => tp2 - case _ => mergeConflict(tp1, tp2) + case _ => mergeConflict(tp1, tp2, that) } case tp1: ClassInfo => tp2 match { case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix) case tp2: TypeBounds if tp2 contains tp1 => tp1 - case _ => mergeConflict(tp1, tp2) + case _ => mergeConflict(tp1, tp2, that) } case tp1: MethodOrPoly => tp2 match { @@ -420,9 +426,9 @@ object Denotations { tp1.derivedLambdaType( mergeParamNames(tp1, tp2), tp1.paramInfos, infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) - else mergeConflict(tp1, tp2) + else mergeConflict(tp1, tp2, that) case _ => - mergeConflict(tp1, tp2) + mergeConflict(tp1, tp2, that) } case _ => tp1 & tp2 @@ -523,7 +529,12 @@ object Denotations { try infoMeet(info1, info2) catch { case ex: MergeError => - if (pre.widen.classSymbol.is(Scala2x) || ctx.scala2Mode) + // TODO: this picks one type over the other whereas it might be better + // to return a MultiDenotation instead. But doing so would affect lots of + // things, starting with the return type of this method. + if (preferSym(sym2, sym1)) info2 + else if (preferSym(sym1, sym2)) info1 + else if (pre.widen.classSymbol.is(Scala2x) || ctx.scala2Mode) info1 // follow Scala2 linearization - // compare with way merge is performed in SymDenotation#computeMembersNamed else @@ -560,13 +571,13 @@ object Denotations { tp2 match { case tp2: TypeBounds => tp1 | tp2 case tp2: ClassInfo if tp1 contains tp2 => tp1 - case _ => mergeConflict(tp1, tp2) + case _ => mergeConflict(tp1, tp2, that) } case tp1: ClassInfo => tp2 match { case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix) case tp2: TypeBounds if tp2 contains tp1 => tp2 - case _ => mergeConflict(tp1, tp2) + case _ => mergeConflict(tp1, tp2, that) } case tp1: MethodOrPoly => tp2 match { @@ -577,7 +588,7 @@ object Denotations { mergeParamNames(tp1, tp2), tp1.paramInfos, tp1.resultType | tp2.resultType.subst(tp2, tp1)) case _ => - mergeConflict(tp1, tp2) + mergeConflict(tp1, tp2, that) } case _ => tp1 | tp2 diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 24cbb051b082..bf758ac77300 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -63,7 +63,7 @@ object NameKinds { def infoString: String } - object SimpleNameKind extends NameKind(UTF8) { + object SimpleNameKind extends NameKind(UTF8) { self => type ThisInfo = Info val info = new Info def mkString(underlying: TermName, info: ThisInfo) = unsupported("mkString") diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index c7217ef7cd3f..69836719c7d3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -954,7 +954,13 @@ class Namer { typer: Typer => val selfInfo = if (self.isEmpty) NoType - else if (cls.is(Module)) cls.owner.thisType.select(sourceModule) + else if (cls.is(Module)) { + val moduleType = cls.owner.thisType select sourceModule + if (self.name == nme.WILDCARD) moduleType + else recordSym( + ctx.newSymbol(cls, self.name, self.mods.flags, moduleType, coord = self.pos), + self) + } else createSymbol(self) // pre-set info, so that parent types can refer to type params diff --git a/compiler/test/dotty/tools/dotc/FromTastyTests.scala b/compiler/test/dotty/tools/dotc/FromTastyTests.scala index 2dee6f9e7040..75f2ed603242 100644 --- a/compiler/test/dotty/tools/dotc/FromTastyTests.scala +++ b/compiler/test/dotty/tools/dotc/FromTastyTests.scala @@ -59,6 +59,9 @@ class FromTastyTests extends ParallelTesting { "spec-super.scala", "spec-sparsearray-old.scala", "collections_1.scala", + + // Infinite compilation + "t3612.scala", ) ) step1.checkCompile() // Compile all files to generate the class files with tasty diff --git a/scala2-library b/scala2-library index 723f22266db0..e588767817e4 160000 --- a/scala2-library +++ b/scala2-library @@ -1 +1 @@ -Subproject commit 723f22266db0a72e3ac19358586e3426757ac201 +Subproject commit e588767817e4985852f6547fc7cf211a8a7df3fa diff --git a/tests/neg/i831.scala b/tests/neg/i831.scala deleted file mode 100644 index 53e4185ed9a8..000000000000 --- a/tests/neg/i831.scala +++ /dev/null @@ -1,4 +0,0 @@ -object Test { self => // error: objects must not have a self type - def a = 5 - self.a // error: not found: self -} diff --git a/tests/pickling/desugar.scala b/tests/pickling/desugar.scala index 720f46d9c3e7..0d3b6d8ca624 100644 --- a/tests/pickling/desugar.scala +++ b/tests/pickling/desugar.scala @@ -11,7 +11,7 @@ object desugar { def foo1(first: Int, second: Int = 2)(third: Int = 3) = first + second def foo2(first: Int)(second: Int = 2)(third: Int = 3) = first + second - object caseClasses { + object caseClasses { self => trait List[+T] { def head: T def tail: List[T] diff --git a/tests/pos/desugar.scala b/tests/pos/desugar.scala index d5e13fb1d8c8..cc679498578f 100644 --- a/tests/pos/desugar.scala +++ b/tests/pos/desugar.scala @@ -11,7 +11,7 @@ object desugar { def foo1(first: Int, second: Int = 2)(third: Int = 3) = first + second def foo2(first: Int)(second: Int = 2)(third: Int = 3) = first + second - object caseClasses { + object caseClasses { self => trait List[+T] { def head: T def tail: List[T] diff --git a/tests/pos/i831.scala b/tests/pos/i831.scala new file mode 100644 index 000000000000..629853b9ca6b --- /dev/null +++ b/tests/pos/i831.scala @@ -0,0 +1,4 @@ +object Test { self => + def a = 5 + self.a +} diff --git a/tests/pos/t3612.scala b/tests/pos/t3612.scala new file mode 100644 index 000000000000..a9d063998ca1 --- /dev/null +++ b/tests/pos/t3612.scala @@ -0,0 +1,6 @@ +trait C + +class Outer { + object O0 extends C {} + object O extends C { self => } +}