Skip to content

Commit

Permalink
approximate type parameters and references by name
Browse files Browse the repository at this point in the history
not as accurate, but simpler.
  • Loading branch information
harrah committed May 13, 2012
1 parent 00d0918 commit 864580a
Show file tree
Hide file tree
Showing 9 changed files with 21 additions and 233 deletions.
28 changes: 0 additions & 28 deletions compile/api/APIUtil.scala
Expand Up @@ -16,34 +16,6 @@ object APIUtil
new Modifiers( x(0), x(1), x(2), x(3), x(4), x(5), x(6) )
}

def verifyTypeParameters(s: SourceAPI): Boolean =
{
val check = new CheckTypeParameters
val invalid = check(s)
if(!invalid.isEmpty) println("References to undefined type parameters: " + invalid.mkString(", "))
invalid.isEmpty
}
private[this] class CheckTypeParameters extends Visit
{
private val defined = new HashSet[Int]
private val referenced = new HashSet[Int]
def apply(s: SourceAPI): List[Int] =
{
super.visitAPI(s)
(referenced filterNot defined).toList
}
override def visitTypeParameter(parameter: TypeParameter)
{
defined += parameter.id
super.visitTypeParameter(parameter)
}
override def visitParameterRef(ref: ParameterRef)
{
referenced += ref.id
super.visitParameterRef(ref)
}
}

def hasMacro(s: SourceAPI): Boolean =
{
val check = new HasMacro
Expand Down
5 changes: 2 additions & 3 deletions compile/api/ClassToAPI.scala
Expand Up @@ -172,9 +172,8 @@ object ClassToAPI
new api.TypeParameter(typeVariable(tp), emptyAnnotationArray, emptyTypeParameterArray, api.Variance.Invariant, NothingRef, upperBounds(tp.getBounds))

// needs to be stable across compilations
// preferably, it would be a proper unique id based on de Bruijn index
def typeVariable[T <: GenericDeclaration](tv: TypeVariable[T]): Int =
reduceHash((name(tv.getGenericDeclaration) + " " + tv.getName).getBytes)
def typeVariable[T <: GenericDeclaration](tv: TypeVariable[T]): String =
name(tv.getGenericDeclaration) + " " + tv.getName

def reduceHash(in: Array[Byte]): Int =
(0 /: in)( (acc, b) => (acc * 43) ^ b)
Expand Down
15 changes: 4 additions & 11 deletions compile/api/HashAPI.scala
Expand Up @@ -6,21 +6,16 @@ package xsbt.api
import scala.util
import xsbti.api._
import util.MurmurHash
import TagTypeVariables.TypeVars
import HashAPI.Hash

object HashAPI
{
type Hash = Int
def apply(a: SourceAPI): Hash =
{
/** de Bruijn levels for type parameters in source a and b*/
val tags = TagTypeVariables(a)
(new HashAPI(tags, false, true)).hashAPI(a)
}
(new HashAPI(false, true)).hashAPI(a)
}

final class HashAPI(tags: TypeVars, includePrivate: Boolean, includeParamNames: Boolean)
final class HashAPI(includePrivate: Boolean, includeParamNames: Boolean)
{
import scala.collection.mutable
import MurmurHash._
Expand Down Expand Up @@ -229,6 +224,7 @@ final class HashAPI(tags: TypeVars, includePrivate: Boolean, includeParamNames:
def hashTypeParameters(parameters: Seq[TypeParameter]) = hashSeq(parameters, hashTypeParameter)
def hashTypeParameter(parameter: TypeParameter)
{
hashString(parameter.id)
extend(parameter.variance.ordinal)
hashTypeParameters(parameter.typeParameters)
hashType(parameter.lowerBound)
Expand Down Expand Up @@ -267,10 +263,7 @@ final class HashAPI(tags: TypeVars, includePrivate: Boolean, includeParamNames:
def hashParameterRef(p: ParameterRef)
{
extend(ParameterRefHash)
tags.get(p.id) match {
case Some((a,b)) => extend(a); extend(b)
case None => extend(-1)
}
hashString(p.id)
}
def hashSingleton(s: Singleton)
{
Expand Down
23 changes: 6 additions & 17 deletions compile/api/SameAPI.scala
Expand Up @@ -39,7 +39,7 @@ object TopLevel
def definitions(i: Iterable[SourceAPI]) = SameAPI.separateDefinitions(i.toSeq.flatMap( _.definitions ))
def names(s: Iterable[Definition]): Set[String] = Set() ++ s.map(_.name)
}
import TagTypeVariables.TypeVars

/** Checks the API of two source files for equality.*/
object SameAPI
{
Expand All @@ -56,11 +56,7 @@ object SameAPI
println("\n=========== API #2 ================")
println(ShowAPI.show(b))*/

/** de Bruijn levels for type parameters in source a and b*/
val tagsA = TagTypeVariables(a)
val tagsB = TagTypeVariables(b)

val result = (new SameAPI(tagsA,tagsB, false, true)).check(a,b)
val result = (new SameAPI(false, true)).check(a,b)
val end = System.currentTimeMillis
//println(" API comparison took: " + (end - start) / 1000.0 + " s")
result
Expand Down Expand Up @@ -99,13 +95,11 @@ object SameAPI
case _ => true
}
}
/** Used to implement API equality. All comparisons must be done between constructs in source files `a` and `b`. For example, when doing:
* `sameDefinitions(as, bs)`, `as` must be definitions from source file `a` and `bs` must be definitions from source file `b`. This is in order
* to properly handle type parameters, which must be computed for each source file and then referenced during comparison.
/** Used to implement API equality.
*
* If `includePrivate` is true, `private` and `private[this]` members are included in the comparison. Otherwise, those members are excluded.
*/
class SameAPI(tagsA: TypeVars, tagsB: TypeVars, includePrivate: Boolean, includeParamNames: Boolean)
class SameAPI(includePrivate: Boolean, includeParamNames: Boolean)
{
import SameAPI._

Expand Down Expand Up @@ -304,13 +298,8 @@ class SameAPI(tagsA: TypeVars, tagsB: TypeVars, includePrivate: Boolean, include
debug(sameType(a.upperBound, b.upperBound), "Different upper bound") &&
sameTags(a.id, b.id)
}
// until dangling type parameter references are straightened out in API phase, approximate
def sameTags(a: Int, b: Int): Boolean =
{
val ta = tagsA.get(a)
val tb = tagsB.get(b)
debug(ta == tb, "Different type parameter bindings: " + ta + "(" + a + "), " + tb + "(" + b + ")")
}
def sameTags(a: String, b: String): Boolean =
debug(a == b, "Different type parameter bindings: " + a + ", " + b)

def sameType(a: Type, b: Type): Boolean =
samePending(a,b)(sameTypeDirect)
Expand Down
164 changes: 0 additions & 164 deletions compile/api/TagTypeVariables.scala

This file was deleted.

9 changes: 4 additions & 5 deletions compile/interface/API.scala
Expand Up @@ -126,9 +126,7 @@ final class API(val global: CallbackGlobal) extends Compat
else if(sym.isRoot || sym.isRootPackage) Constants.emptyType
else new xsbti.api.Projection(simpleType(in, pre), sym.nameString)
}

private def reference(sym: Symbol): xsbti.api.ParameterRef = new xsbti.api.ParameterRef(sym.id)

private def reference(sym: Symbol): xsbti.api.ParameterRef = new xsbti.api.ParameterRef(tparamID(sym))

private def annotations(in: Symbol, as: List[AnnotationInfo]): Array[xsbti.api.Annotation] = as.toArray[AnnotationInfo].map(annotation(in,_))
private def annotation(in: Symbol, a: AnnotationInfo) =
Expand Down Expand Up @@ -338,11 +336,12 @@ final class API(val global: CallbackGlobal) extends Compat
val variance = if(varianceInt < 0) Contravariant else if(varianceInt > 0) Covariant else Invariant
viewer(in).memberInfo(s) match
{
case TypeBounds(low, high) => new xsbti.api.TypeParameter( s.id, annots, typeParameters(in, s), variance, processType(in, low), processType(in, high) )
case PolyType(typeParams, base) => new xsbti.api.TypeParameter( s.id, annots, typeParameters(in, typeParams), variance, processType(in, base.bounds.lo), processType(in, base.bounds.hi))
case TypeBounds(low, high) => new xsbti.api.TypeParameter( tparamID(s), annots, typeParameters(in, s), variance, processType(in, low), processType(in, high) )
case PolyType(typeParams, base) => new xsbti.api.TypeParameter( tparamID(s), annots, typeParameters(in, typeParams), variance, processType(in, base.bounds.lo), processType(in, base.bounds.hi))
case x => error("Unknown type parameter info: " + x.getClass)
}
}
private def tparamID(s: Symbol) = s.fullName
private def selfType(in: Symbol, s: Symbol): xsbti.api.Type = processType(in, s.thisSym.typeOfThis)

private def classLike(in: Symbol, c: Symbol): ClassLike = classLikeCache.getOrElseUpdate( (in,c), mkClassLike(in, c))
Expand Down
6 changes: 3 additions & 3 deletions compile/persist/APIFormats.scala
Expand Up @@ -62,8 +62,8 @@ trait APIFormats extends FormatExtra
implicit def formatExistential(implicit t: Format[Type], tps: Format[Array[TypeParameter]]): Format[Existential] =
p2( (e: Existential) => (e.baseType, e.clause) )( new Existential(_,_) )(t,tps)

implicit def formatParameterRef(implicit i: Format[Int]): Format[ParameterRef] =
wrap[ParameterRef, Int](_.id, new ParameterRef(_))(i)
implicit def formatParameterRef(implicit i: Format[String]): Format[ParameterRef] =
wrap[ParameterRef, String](_.id, new ParameterRef(_))(i)

// cyclic with many formats
def formatType(implicit s: Format[SimpleType], a: Format[Annotated], st: Format[Structure], e: Format[Existential], po: Format[Polymorphic]): Format[Type] =
Expand Down Expand Up @@ -172,7 +172,7 @@ trait APIFormats extends FormatExtra
implicit def formatModifiers(implicit bf: Format[Byte]): Format[Modifiers] =
wrap[Modifiers, Byte]( modifiersToByte, byteToModifiers )

def formatTypeParameter(tps: Format[TypeParameter] => Format[Array[TypeParameter]])(implicit as: Format[Array[Annotation]], t: Format[Type], v: Format[Variance], i: Format[Int]): Format[TypeParameter] =
def formatTypeParameter(tps: Format[TypeParameter] => Format[Array[TypeParameter]])(implicit as: Format[Array[Annotation]], t: Format[Type], v: Format[Variance], i: Format[String]): Format[TypeParameter] =
{
lazy val ltps: Format[Array[TypeParameter]] = lazyFormat( tps(ltp) )
lazy val ltp = p6( (tp: TypeParameter) => (tp.id, tp.annotations, tp.typeParameters, tp.variance, tp.lowerBound, tp.upperBound))(new TypeParameter(_,_,_,_,_,_))(i, as, ltps, v, t, t)
Expand Down
2 changes: 1 addition & 1 deletion interface/other
Expand Up @@ -39,7 +39,7 @@ MethodParameter
modifier: ParameterModifier

TypeParameter
id: Int
id: String
annotations: Annotation*
typeParameters : TypeParameter*
variance: Variance
Expand Down
2 changes: 1 addition & 1 deletion interface/type
Expand Up @@ -5,7 +5,7 @@ Type
prefix : SimpleType
id: String
ParameterRef
id: Int
id: String
Singleton
path: Path
EmptyType
Expand Down

0 comments on commit 864580a

Please sign in to comment.