From 9346e2bb4da36945706bd7ee145f3950d7936944 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 5 Jan 2016 12:50:03 -0800 Subject: [PATCH] Only include all base types for class definitions For refinement types, the Structure was already restricted to declarations (and not inherited members), but all base types were still included for a refinement's parents, which would create unwieldy, and even erroneous (cyclic) types by expanding all constituents of an intersection type to add all base types. Since the logic already disregarded inherited members, it seems logical to only include direct parents, and not all ancestor types. ``` class Dep { def bla(c: Boolean) = if (c) new Value else "bla" } class Value extends java.lang.Comparable[Value] { def compareTo(that: Value): Int = 1 } ``` --- .../src/main/scala/xsbt/ExtractAPI.scala | 21 ++++++++++++------- .../fbounded-existentials/fbounds.scala | 10 +++++++++ .../fbounded-existentials/test | 1 + 3 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 sbt/src/sbt-test/source-dependencies/fbounded-existentials/fbounds.scala create mode 100644 sbt/src/sbt-test/source-dependencies/fbounded-existentials/test diff --git a/compile/interface/src/main/scala/xsbt/ExtractAPI.scala b/compile/interface/src/main/scala/xsbt/ExtractAPI.scala index 9179c2c87..4575dc27e 100644 --- a/compile/interface/src/main/scala/xsbt/ExtractAPI.scala +++ b/compile/interface/src/main/scala/xsbt/ExtractAPI.scala @@ -336,14 +336,19 @@ class ExtractAPI[GlobalType <: CallbackGlobal](val global: GlobalType, private def removeConstructors(ds: List[Symbol]): List[Symbol] = ds filter { !_.isConstructor } - private def mkStructure(info: Type, s: Symbol, inherit: Boolean): xsbti.api.Structure = - { - val (declared, inherited) = info.members.toList.reverse.partition(_.owner == s) - val baseTypes = info.baseClasses.tail.map(info.baseType) - val ds = if (s.isModuleClass) removeConstructors(declared) else declared - val is = if (inherit) removeConstructors(inherited) else Nil - mkStructure(s, baseTypes, ds, is) - } + private def mkStructure(info: Type, s: Symbol, inherit: Boolean): xsbti.api.Structure = { + val (declared, inherited) = info.members.reverse.partition(_.owner == s) + // Note that the ordering of classes in `baseClasses` is important. + // It would be easier to just say `val baseTypes = baseTypeSeq`, but that does not seem + // to take linearization into account. + // Also, we take info.parents when we're not interested in the full linearization, + // which side steps issues with baseType when f-bounded existential types and refined types mix + // (and we get cyclic types which cause a stack overflow in showAPI) + val baseTypes = if (inherit) info.baseClasses.tail.map(info.baseType) else info.parents + val ds = if (s.isModuleClass) removeConstructors(declared) else declared + val is = if (inherit) removeConstructors(inherited) else Nil + mkStructure(s, baseTypes, ds, is) + } // If true, this template is publicly visible and should be processed as a public inheritance dependency. // Local classes and local refinements will never be traversed by the api phase, so we don't need to check for that. diff --git a/sbt/src/sbt-test/source-dependencies/fbounded-existentials/fbounds.scala b/sbt/src/sbt-test/source-dependencies/fbounded-existentials/fbounds.scala new file mode 100644 index 000000000..60fe40879 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/fbounded-existentials/fbounds.scala @@ -0,0 +1,10 @@ +class Dep { + // The API representation for `bla`'s result type contains a cycle + // (an existential's type variable's bound is the existential type itself) + // This results in a stack overflow while showing the API diff. + // Note that the actual result type in the compiler is not cyclic + // (the f-bounded existential for Comparable is truncated) + def bla(c: Boolean) = if (c) new Value else "bla" +} + +class Value extends java.lang.Comparable[Value] { def compareTo(that: Value): Int = 1 } \ No newline at end of file diff --git a/sbt/src/sbt-test/source-dependencies/fbounded-existentials/test b/sbt/src/sbt-test/source-dependencies/fbounded-existentials/test new file mode 100644 index 000000000..5df2af1f3 --- /dev/null +++ b/sbt/src/sbt-test/source-dependencies/fbounded-existentials/test @@ -0,0 +1 @@ +> compile