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 }
```
This commit is contained in:
Adriaan Moors 2016-01-05 12:50:03 -08:00 committed by Eugene Yokota
parent 3e03e0d1b5
commit 9346e2bb4d
3 changed files with 24 additions and 8 deletions

View File

@ -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.

View File

@ -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 }

View File

@ -0,0 +1 @@
> compile