diff --git a/compile/interface/src/main/scala/xsbt/ExtractAPI.scala b/compile/interface/src/main/scala/xsbt/ExtractAPI.scala index 07336d31b..75733b1fa 100644 --- a/compile/interface/src/main/scala/xsbt/ExtractAPI.scala +++ b/compile/interface/src/main/scala/xsbt/ExtractAPI.scala @@ -578,7 +578,7 @@ class ExtractAPI[GlobalType <: CallbackGlobal](val global: GlobalType, // as that invariant is established on completing the class symbol (`mkClassLike` calls `s.initialize` before calling us). // Technically, we could even ignore a self type that's a supertype of the class's type, // as it does not contribute any information relevant outside of the class definition. - if ((s.thisSym eq s) || s.typeOfThis == s.info) Constants.emptyType else processType(in, s.typeOfThis) + if ((s.thisSym eq s) || (s.thisSym.tpeHK == s.tpeHK)) Constants.emptyType else processType(in, s.typeOfThis) def classLike(in: Symbol, c: Symbol): ClassLike = classLikeCache.getOrElseUpdate((in, c), mkClassLike(in, c)) private def mkClassLike(in: Symbol, c: Symbol): ClassLike = { diff --git a/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala b/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala index c4009eabc..d0a9f6908 100644 --- a/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala +++ b/compile/interface/src/test/scala/xsbt/ExtractAPISpecification.scala @@ -1,7 +1,7 @@ package xsbt import org.junit.runner.RunWith -import xsbti.api.{ Definition, SourceAPI, ClassLike, Def } +import xsbti.api._ import xsbt.api.SameAPI import org.specs2.mutable.Specification import org.specs2.runner.JUnitRunner @@ -40,11 +40,13 @@ class ExtractAPISpecification extends Specification { } /** - * Checks if representation of the inherited Namer class (with a declared self variable) in Global.Foo - * is stable between compiling from source and unpickling. We compare extracted APIs of Global when Global - * is compiled together with Namers or Namers is compiled first and then Global refers - * to Namers by unpickling types from class files. - */ + * Checks if representation of the inherited Namer class (with a declared self variable) in Global.Foo + * is stable between compiling from source and unpickling. We compare extracted APIs of Global when Global + * is compiled together with Namers or Namers is compiled first and then Global refers + * to Namers by unpickling types from class files. + * + * See https://github.com/sbt/sbt/issues/2504 + */ "Self variable and no self type" in { def selectNamer(api: SourceAPI): ClassLike = { def selectClass(defs: Iterable[Definition], name: String): ClassLike = defs.collectFirst { @@ -70,5 +72,33 @@ class ExtractAPISpecification extends Specification { val namerApi1 = selectNamer(src2Api1) val namerApi2 = selectNamer(src2Api2) SameAPI(namerApi1, namerApi2) - }.pendingUntilFixed("have unstable representation (#2504)") + } + + /** + * Checks if self type is properly extracted in various cases of declaring a self type + * with our without a self variable. + */ + "Self type" in { + def collectFirstClass(defs: Array[Definition]): ClassLike = defs.collectFirst { + case c: ClassLike => c + }.get + val srcX = "trait X" + val srcY = "trait Y" + val srcC1 = "class C1 { this: C1 => }" + val srcC2 = "class C2 { thisC: C2 => }" + val srcC3 = "class C3 { this: X => }" + val srcC4 = "class C4 { thisC: X => }" + val srcC5 = "class C5 extends AnyRef with X with Y { self: X with Y => }" + val srcC6 = "class C6 extends AnyRef with X { self: X with Y => }" + val compilerForTesting = new ScalaCompilerForUnitTesting + val apis = compilerForTesting.extractApisFromSrcs(reuseCompilerInstance = true)( + List(srcX, srcY, srcC1, srcC2, srcC3, srcC4, srcC5, srcC6) + ).map(x => collectFirstClass(x.definitions)) + val emptyType = new EmptyType + def hasSelfType(c: ClassLike): Boolean = + c.selfType != emptyType + val (withSelfType, withoutSelfType) = apis.partition(hasSelfType) + withSelfType.map(_.name).toSet === Set("C3", "C4", "C5", "C6") + withoutSelfType.map(_.name).toSet === Set("X", "Y", "C1", "C2") + } }