Defined tpeHK in a manner consistent with tpe so it has a better

chance of being found/understood, and tried to clean up its documentation
a little bit.  Review by moors.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25153 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2011-06-24 13:16:45 +00:00
parent 590fcf5179
commit 3da81185ba
2 changed files with 59 additions and 27 deletions

View File

@ -745,9 +745,11 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
* @M you should use tpeHK for a type symbol with type parameters if
* the kind of the type need not be *, as tpe introduces dummy arguments
* to generate a type of kind *
* for a term symbol, its usual type
* for a term symbol, its usual type.
* See the tpe/tpeHK overrides in TypeSymbol for more.
*/
def tpe: Type = info
def tpeHK: Type = tpe
/** Get type info associated with symbol at current phase, after
* ensuring that symbol is initialized (i.e. type is completed).
@ -926,15 +928,6 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
def typeConstructor: Type =
abort("typeConstructor inapplicable for " + this)
/** @M -- tpe vs tpeHK:
* Symbol::tpe creates a TypeRef that has dummy type arguments to get a type of kind *
* Symbol::tpeHK creates a TypeRef without type arguments, but with type params --> higher-kinded if non-empty list of tpars
* calling tpe may hide errors or introduce spurious ones
* (e.g., when deriving a type from the symbol of a type argument that must be higher-kinded)
* as far as I can tell, it only makes sense to call tpe in conjunction with a substitution that replaces the generated dummy type arguments by their actual types
*/
def tpeHK = if (isType) typeConstructor else tpe // @M! used in memberType
/** The type parameters of this symbol, without ensuring type completion.
* assumption: if a type starts out as monomorphic, it will not acquire
* type parameters later.
@ -2016,7 +2009,8 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
tpeCache = NoType
val targs =
if (phase.erasedTypes && this != ArrayClass) List()
else unsafeTypeParams map (_.typeConstructor) //@M! use typeConstructor to generate dummy type arguments,
else unsafeTypeParams map (_.typeConstructor)
//@M! use typeConstructor to generate dummy type arguments,
// sym.tpe should not be called on a symbol that's supposed to be a higher-kinded type
// memberType should be used instead, that's why it uses tpeHK and not tpe
tpeCache = newTypeRef(targs)
@ -2025,6 +2019,22 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
assert(tpeCache ne null/*, "" + this + " " + phase*/)//debug
tpeCache
}
/** @M -- tpe vs tpeHK:
*
* tpe: creates a TypeRef with dummy type arguments and kind *
* tpeHK: creates a TypeRef with no type arguments but with type parameters
*
* If typeParams is nonEmpty, calling tpe may hide errors or
* introduce spurious ones. (For example, when deriving a type from
* the symbol of a type argument that must be higher-kinded.) As far
* as I can tell, it only makes sense to call tpe in conjunction
* with a substitution that replaces the generated dummy type
* arguments by their actual types.
*
* TODO: the above conditions desperately need to be enforced by code.
*/
override def tpeHK = typeConstructor // @M! used in memberType
// needed for experimental code for early types as type parameters
// def refreshType() { tpePeriod = NoPeriod }
@ -2100,7 +2110,8 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
/** If type skolem comes from an existential, the tree where it was created */
override def unpackLocation = origin
override def typeParams = info.typeParams //@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo
//@M! (not deSkolemize.typeParams!!), also can't leave superclass definition: use info, not rawInfo
override def typeParams = info.typeParams
override def cloneSymbolImpl(owner: Symbol): Symbol =
new TypeSkolem(owner, pos, name, origin)
@ -2110,7 +2121,6 @@ trait Symbols /* extends reflect.generic.Symbols*/ { self: SymbolTable =>
else super.nameString
}
/** A class for class symbols */
class ClassSymbol(initOwner: Symbol, initPos: Position, initName: TypeName)
extends TypeSymbol(initOwner, initPos, initName) {

View File

@ -1839,26 +1839,36 @@ A type's typeSymbol should never be inspected directly.
else sym.unsafeTypeParams
// placeholders derived from type params
private def dummyArgs = typeParamsDirect map (_.typeConstructor) //@M must be .typeConstructor
private def dummyArgs = {
// @PP to @AM: this appears to me a place where
// higher-order tparams are going off the beam.
// if (sym.isAbstractType) { something goes wrong }
//@M must be .typeConstructor
typeParamsDirect map (_.typeConstructor)
}
// (!result.isEmpty) IFF isHigherKinded
override def typeParams: List[Symbol] = if (isHigherKinded) typeParamsDirect else List()
// note: does not go through typeRef. There's no need to because
// neither `pre` nor `sym` changes. And there's a performance
// advantage to call TypeRef directly.
override def typeConstructor = TypeRef(pre, sym, Nil)
// note: does not go through typeRef. There's no need to because neither `pre` nor `sym` changes.
// And there's a performance advantage to call TypeRef directly.
// a reference (in a Scala program) to a type that has type parameters, but where the reference does not include type arguments
// note that it doesn't matter whether the symbol refers to a java or scala symbol,
// it does matter whether it occurs in java or scala code
// typerefs w/o type params that occur in java signatures/code are considered raw types, and are represented as existential types
// A reference (in a Scala program) to a type that has type
// parameters, but where the reference does not include type
// arguments. Note that it doesn't matter whether the symbol refers
// to a java or scala symbol, it does matter whether it occurs in
// java or scala code. TypeRefs w/o type params that occur in java
// signatures/code are considered raw types, and are represented as
// existential types.
override def isHigherKinded = args.isEmpty && typeParamsDirect.nonEmpty
override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
if (isHigherKinded) {
val substTps = formals.intersect(typeParams)
if (sameLength(substTps, typeParams))
copyTypeRef(this, pre, sym, actuals)
else if (sameLength(formals, actuals)) // partial application (needed in infer when bunching type arguments from classes and methods together)
@ -1869,12 +1879,17 @@ A type's typeSymbol should never be inspected directly.
super.instantiateTypeParams(formals, actuals)
/** @pre: sym.info.typeParams.length == typeArgs.length */
@inline private def betaReduce: Type = {
assert(sameLength(sym.info.typeParams, typeArgs), this)
// isHKSubType0 introduces synthetic type params so that betaReduce can first apply sym.info to typeArgs before calling asSeenFrom
// asSeenFrom then skips synthetic type params, which are used to reduce HO subtyping to first-order subtyping, but which can't be instantiated from the given prefix and class
// appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) // this crashes pos/depmet_implicit_tpbetareduce.scala
// isHKSubType0 introduces synthetic type params so that
// betaReduce can first apply sym.info to typeArgs before calling
// asSeenFrom. asSeenFrom then skips synthetic type params, which
// are used to reduce HO subtyping to first-order subtyping, but
// which can't be instantiated from the given prefix and class.
transform(sym.info.resultType)
//
// this crashes pos/depmet_implicit_tpbetareduce.scala
// appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner)
}
// @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala)
@ -5075,7 +5090,7 @@ A type's typeSymbol should never be inspected directly.
*
* @See baseTypeSeq for a definition of sorted and upwards closed.
*/
private def lubList(tss: List[List[Type]], depth: Int): List[Type] =
private def lubList(tss: List[List[Type]], depth: Int): List[Type] = {
if (tss.tail.isEmpty) tss.head
else if (tss exists (_.isEmpty)) List()
else {
@ -5086,6 +5101,13 @@ A type's typeSymbol should never be inspected directly.
else
lubList(tss map (ts => if (ts.head.typeSymbol == sym) ts.tail else ts), depth)
}
}
// @PP lubLists gone bad: lubList(List(
// List(scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq], ScalaObject, java.lang.Object, Any)
// List(scala.collection.generic.GenericCompanion[scala.collection.mutable.Seq], ScalaObject, java.lang.Object, Any)
// )) == (
// List(scala.collection.generic.GenericCompanion[Seq[Any]], ScalaObject, java.lang.Object, Any)
// )
private def lubBaseTypeSeq(tss: List[BaseTypeSeq], depth: Int): List[Type] =
lubList(tss map (_.toList), depth)