Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
magarciaEPFL committed Feb 14, 2012
1 parent 42e58cd commit e7411f7
Show file tree
Hide file tree
Showing 20 changed files with 238 additions and 133 deletions.
28 changes: 20 additions & 8 deletions src/compiler/scala/reflect/internal/Definitions.scala
Expand Up @@ -586,14 +586,6 @@ trait Definitions extends reflect.api.StandardDefinitions {
case _ => NoType
}

/** To avoid unchecked warnings on polymorphic classes, translate
* a Foo[T] into a Foo[_] for use in the pattern matcher.
*/
def typeCaseType(clazz: Symbol) = clazz.tpe.normalize match {
case TypeRef(_, sym, args) if args.nonEmpty => newExistentialType(sym.typeParams, clazz.tpe)
case tp => tp
}

def seqType(arg: Type) = appliedType(SeqClass.typeConstructor, List(arg))
def arrayType(arg: Type) = appliedType(ArrayClass.typeConstructor, List(arg))
def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg))
Expand All @@ -609,6 +601,26 @@ trait Definitions extends reflect.api.StandardDefinitions {
def vmClassType(arg: Type): Type = ClassType(arg)
def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!!

/** Given a class symbol C with type parameters T1, T2, ... Tn
* which have upper/lower bounds LB1/UB1, LB1/UB2, ..., LBn/UBn,
* returns an existential type of the form
*
* C[E1, ..., En] forSome { E1 >: LB1 <: UB1 ... en >: LBn <: UBn }.
*/
def classExistentialType(clazz: Symbol): Type =
newExistentialType(clazz.typeParams, clazz.tpe)

/** Given type U, creates a Type representing Class[_ <: U].
*/
def boundedClassType(upperBound: Type) =
appliedTypeAsUpperBounds(ClassClass.typeConstructor, List(upperBound))

/** To avoid unchecked warnings on polymorphic classes, translate
* a Foo[T] into a Foo[_] for use in the pattern matcher.
*/
@deprecated("Use classExistentialType", "2.10.0")
def typeCaseType(clazz: Symbol): Type = classExistentialType(clazz)

//
// .NET backend
//
Expand Down
108 changes: 61 additions & 47 deletions src/compiler/scala/reflect/internal/Importers.scala
Expand Up @@ -32,8 +32,11 @@ trait Importers { self: SymbolTable =>

def importPosition(pos: from.Position): Position = NoPosition

def importSymbol(sym: from.Symbol): Symbol = {
def importSymbol(sym0: from.Symbol): Symbol = {
def doImport(sym: from.Symbol): Symbol = {
if (symMap.contains(sym))
return symMap(sym)

val myowner = importSymbol(sym.owner)
val mypos = importPosition(sym.pos)
val myname = importName(sym.name).toTermName
Expand All @@ -47,7 +50,7 @@ trait Importers { self: SymbolTable =>
case x: from.MethodSymbol =>
linkReferenced(myowner.newMethod(myname, mypos, myflags), x, importSymbol)
case x: from.ModuleSymbol =>
linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, doImport)
linkReferenced(myowner.newModuleSymbol(myname, mypos, myflags), x, importSymbol)
case x: from.FreeVar =>
newFreeVar(importName(x.name).toTermName, importType(x.tpe), x.value, myflags)
case x: from.TermSymbol =>
Expand All @@ -59,14 +62,14 @@ trait Importers { self: SymbolTable =>
case y: from.Symbol => importSymbol(y)
}
myowner.newTypeSkolemSymbol(myname.toTypeName, origin, mypos, myflags)
/*
case x: from.ModuleClassSymbol =>
val mysym = new ModuleClassSymbol(myowner, mypos, myname.toTypeName)
mysym.sourceModule = importSymbol(x.sourceModule)
mysym
*/
case x: from.ModuleClassSymbol =>
val mysym = myowner.newModuleClassSymbol(myname.toTypeName, mypos, myflags)
symMap(x) = mysym
mysym.sourceModule = importSymbol(x.sourceModule)
mysym
case x: from.ClassSymbol =>
val mysym = myowner.newClassSymbol(myname.toTypeName, mypos, myflags)
symMap(x) = mysym
if (sym.thisSym != sym) {
mysym.typeOfThis = importType(sym.typeOfThis)
mysym.thisSym.name = importName(sym.thisSym.name)
Expand All @@ -78,7 +81,7 @@ trait Importers { self: SymbolTable =>
symMap(sym) = mysym
mysym setFlag Flags.LOCKED
mysym setInfo {
val mytypeParams = sym.typeParams map doImport
val mytypeParams = sym.typeParams map importSymbol
new LazyPolyType(mytypeParams) {
override def complete(s: Symbol) {
val result = sym.info match {
Expand All @@ -94,58 +97,69 @@ trait Importers { self: SymbolTable =>
} // end doImport

def importOrRelink: Symbol = {
val sym = sym0 // makes sym visible in the debugger
if (sym == null)
null
else if (sym == from.NoSymbol)
NoSymbol
else if (sym.isRoot)
definitions.RootClass
else {
val myowner = importSymbol(sym.owner)
val myname = importName(sym.name)
if (sym.isModuleClass) {
assert(sym.sourceModule != NoSymbol, sym)
val mymodule = importSymbol(sym.sourceModule)
assert(mymodule != NoSymbol, sym)
assert(mymodule.moduleClass != NoSymbol, mymodule)
mymodule.moduleClass
} else if (myowner.isClass && !myowner.isRefinementClass && !(myowner hasFlag Flags.LOCKED) && sym.owner.info.decl(sym.name).exists) {
// symbol is in class scope, try to find equivalent one in local scope
if (sym.isOverloaded)
myowner.newOverloaded(myowner.thisType, sym.alternatives map importSymbol)
else {
var existing: Symbol = myowner.info.decl(myname)
if (existing.isOverloaded) {
existing =
if (sym.isMethod) {
val localCopy = doImport(sym)
existing filter (_.tpe matches localCopy.tpe)
} else {
existing filter (!_.isMethod)
}
assert(!existing.isOverloaded,
"import failure: cannot determine unique overloaded method alternative from\n "+
(existing.alternatives map (_.defString) mkString "\n")+"\n that matches "+sym+":"+sym.tpe)
val name = sym.name
val owner = sym.owner
var scope = if (owner.isClass && !owner.isRefinementClass) owner.info else from.NoType
var existing = scope.decl(name)
if (sym.isPackageClass || sym.isModuleClass) existing = existing.moduleClass
if (!existing.exists) scope = from.NoType

val myname = importName(name)
val myowner = importSymbol(owner)
val myscope = if (scope != from.NoType && !(myowner hasFlag Flags.LOCKED)) myowner.info else NoType
var myexisting = if (myscope != NoType) myowner.info.decl(myname) else NoSymbol // cannot load myexisting in general case, because it creates cycles for methods
if (sym.isPackageClass || sym.isModuleClass) myexisting = importSymbol(sym.sourceModule).moduleClass
if (!sym.isOverloaded && myexisting.isOverloaded) {
myexisting =
if (sym.isMethod) {
val localCopy = doImport(sym)
myexisting filter (_.tpe matches localCopy.tpe)
} else {
myexisting filter (!_.isMethod)
}
if (existing != NoSymbol) existing
else {
assert(!myexisting.isOverloaded,
"import failure: cannot determine unique overloaded method alternative from\n "+
(myexisting.alternatives map (_.defString) mkString "\n")+"\n that matches "+sym+":"+sym.tpe)
}

val mysym = {
if (sym.isOverloaded) {
myowner.newOverloaded(myowner.thisType, sym.alternatives map importSymbol)
} else if (sym.isTypeParameter && sym.paramPos >= 0 && !(myowner hasFlag Flags.LOCKED)) {
assert(myowner.typeParams.length > sym.paramPos,
"import failure: cannot determine parameter "+sym+" (#"+sym.paramPos+") in "+
myowner+typeParamsString(myowner.rawInfo)+"\n original symbol was: "+
sym.owner+from.typeParamsString(sym.owner.info))
myowner.typeParams(sym.paramPos)
} else {
if (myexisting != NoSymbol) {
myexisting
} else {
val mysym = doImport(sym)
assert(myowner.info.decls.lookup(myname) == NoSymbol, myname+" "+myowner.info.decl(myname)+" "+existing)
myowner.info.decls enter mysym

if (myscope != NoType) {
assert(myowner.info.decls.lookup(myname) == NoSymbol, myname+" "+myowner.info.decl(myname)+" "+myexisting)
myowner.info.decls enter mysym
}

mysym
}
}
} else if (sym.isTypeParameter && sym.paramPos >= 0 && !(myowner hasFlag Flags.LOCKED)) {
assert(myowner.typeParams.length > sym.paramPos,
"import failure: cannot determine parameter "+sym+" (#"+sym.paramPos+") in "+
myowner+typeParamsString(myowner.rawInfo)+"\n original symbol was: "+
sym.owner+from.typeParamsString(sym.owner.info))
myowner.typeParams(sym.paramPos)
} else
doImport(sym)
}

mysym
}
} // end importOrRelink

val sym = sym0
if (symMap contains sym) {
symMap(sym)
} else {
Expand Down Expand Up @@ -410,4 +424,4 @@ trait Importers { self: SymbolTable =>
case _ => constant.value
})
}
}
}
2 changes: 1 addition & 1 deletion src/compiler/scala/reflect/internal/Scopes.scala
Expand Up @@ -120,7 +120,7 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* @param sym ...
*/
def enterUnique(sym: Symbol) {
assert(lookup(sym.name) == NoSymbol)
assert(lookup(sym.name) == NoSymbol, (sym.fullLocationString, lookup(sym.name).fullLocationString))
enter(sym)
}

Expand Down
8 changes: 5 additions & 3 deletions src/compiler/scala/reflect/internal/SymbolTable.scala
Expand Up @@ -120,9 +120,11 @@ abstract class SymbolTable extends api.Universe
try op
finally phase = current
}

@inline final def afterPhase[T](ph: Phase)(op: => T): T =
atPhase(ph.next)(op)
/** Since when it is to be "at" a phase is inherently ambiguous,
* a couple unambiguously named methods.
*/
@inline final def beforePhase[T](ph: Phase)(op: => T): T = atPhase(ph)(op)
@inline final def afterPhase[T](ph: Phase)(op: => T): T = atPhase(ph.next)(op)

@inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T =
if (target != NoPhase && phase.id > target.id) atPhase(target)(op) else op
Expand Down
9 changes: 6 additions & 3 deletions src/compiler/scala/reflect/internal/Symbols.scala
Expand Up @@ -1708,6 +1708,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* (which is always the interface, by convention)
* - before erasure, it looks up the interface name in the scope of the owner of the class.
* This only works for implementation classes owned by other classes or traits.
* !!! Why?
*/
final def toInterface: Symbol =
if (isImplClass) {
Expand Down Expand Up @@ -2084,6 +2085,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

def infosString = infos.ToString

def debugLocationString = fullLocationString + " " + debugFlagString
def debugFlagString = hasFlagsToString(-1L)
def hasFlagsToString(mask: Long): String = flagsToString(
flags & mask,
if (hasAccessBoundary) privateWithin.ToString else ""
Expand Down Expand Up @@ -2182,7 +2185,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}

def setLazyAccessor(sym: Symbol): TermSymbol = {
assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, hasFlagsToString(-1L), referenced, sym))
assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, debugFlagString, referenced, sym))
referenced = sym
this
}
Expand Down Expand Up @@ -2323,15 +2326,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>

/** Overridden in subclasses for which it makes sense.
*/
def existentialBound: Type = abort("unexpected type: "+_root_.java.lang.Object.instancehelper_getClass(this)+ " "+this.fullLocationString+ " " + hasFlagsToString(-1L))
def existentialBound: Type = abort("unexpected type: "+_root_.java.lang.Object.instancehelper_getClass(this)+ " "+debugLocationString)

override def name: TypeName = super.name.asInstanceOf[TypeName]
final override def isType = true
override def isNonClassType = true
override def isAbstractType = {
if (settings.debug.value) {
if (isDeferred) {
println("TypeSymbol claims to be abstract type: " + _root_.java.lang.Object.instancehelper_getClass(this) + " " + hasFlagsToString(-1L) + " at ")
println("TypeSymbol claims to be abstract type: " + _root_.java.lang.Object.instancehelper_getClass(this) + " " + debugFlagString + " at ")
java.lang.Throwable.instancehelper_printStackTrace(new java.lang.Throwable)
}
}
Expand Down
65 changes: 49 additions & 16 deletions src/compiler/scala/reflect/internal/Types.scala
Expand Up @@ -2433,25 +2433,37 @@ trait Types extends api.Types { self: SymbolTable =>
case _ =>
List()
}

/** An existential can only be printed with wildcards if:
* - the underlying type is a typeref
* - where there is a 1-to-1 correspondence between underlying's typeargs and quantified
* - and none of the existential parameters is referenced from anywhere else in the type
* - and none of the existential parameters are singleton types
*/
private def isRepresentableWithWildcards = !settings.debug.value && {
val qset = quantified.toSet
!qset.exists(_.isSingletonExistential) && (underlying match {
case TypeRef(_, sym, args) =>
sameLength(args, quantified) && {
args forall { arg =>
qset(arg.typeSymbol) && !qset.exists(arg.typeSymbol.info.bounds contains _)
}
}
case _ => false
})
}
override def safeToString: String = {
if (!(quantified exists (_.isSingletonExistential)) && !settings.debug.value)
// try to represent with wildcards first
underlying match {
case TypeRef(pre, sym, args) if args.nonEmpty =>
val wargs = wildcardArgsString(quantified.toSet, args)
if (sameLength(wargs, args))
return TypeRef(pre, sym, List()) + wargs.mkString("[", ", ", "]")
case _ =>
}
var ustr = underlying.ToString
def clauses = {
val str = quantified map (_.existentialToString) mkString (" forSome { ", "; ", " }")
if (settings.explaintypes.value) "(" + str + ")" else str
}
underlying match {
case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => ustr = "("+ustr+")"
case TypeRef(pre, sym, args) if isRepresentableWithWildcards =>
"" + TypeRef(pre, sym, Nil) + wildcardArgsString(quantified.toSet, args).mkString("[", ", ", "]")
case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) =>
"(" + underlying + ")" + clauses
case _ =>
"" + underlying + clauses
}
val str =
ustr+(quantified map (_.existentialToString) mkString(" forSome { ", "; ", " }"))
if (settings.explaintypes.value) "("+str+")" else str
}

override def cloneInfo(owner: Symbol) =
Expand Down Expand Up @@ -3260,6 +3272,25 @@ trait Types extends api.Types { self: SymbolTable =>
case WildcardType => tycon // needed for neg/t0226
case _ => abort(debugString(tycon))
}

/** A creator for existential types where the type arguments,
* rather than being applied directly, are interpreted as the
* upper bounds of unknown types. For instance if the type argument
* list given is List(AnyRefClass), the resulting type would be
* e.g. Set[_ <: AnyRef] rather than Set[AnyRef] .
*/
def appliedTypeAsUpperBounds(tycon: Type, args: List[Type]): Type = {
tycon match {
case TypeRef(pre, sym, _) if sameLength(sym.typeParams, args) =>
val eparams = typeParamsToExistentials(sym)
val bounds = args map (TypeBounds upper _)
(eparams, bounds).zipped foreach (_ setInfo _)

newExistentialType(eparams, typeRef(pre, sym, eparams map (_.tpe)))
case _ =>
appliedType(tycon, args)
}
}

/** A creator for type parameterizations that strips empty type parameter lists.
* Use this factory method to indicate the type has kind * (it's a polymorphic value)
Expand Down Expand Up @@ -3845,6 +3876,8 @@ trait Types extends api.Types { self: SymbolTable =>

eparams map (_ substInfo (tparams, eparams))
}
def typeParamsToExistentials(clazz: Symbol): List[Symbol] =
typeParamsToExistentials(clazz, clazz.typeParams)

// note: it's important to write the two tests in this order,
// as only typeParams forces the classfile to be read. See #400
Expand Down Expand Up @@ -3876,7 +3909,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (expanded contains sym) AnyRefClass.tpe
else try {
expanded += sym
val eparams = mapOver(typeParamsToExistentials(sym, sym.typeParams))
val eparams = mapOver(typeParamsToExistentials(sym))
existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe)))
} finally {
expanded -= sym
Expand Down

0 comments on commit e7411f7

Please sign in to comment.