diff options
author | Paul Phillips <paulp@improving.org> | 2010-10-08 07:06:00 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-10-08 07:06:00 +0000 |
commit | 41d7f547c03f2226748a3f9683a4e50084933776 (patch) | |
tree | 9c808bd69fa1bf86e9664b1b85e3e8c50bbdd1bb /src/compiler | |
parent | 001e910f9774b2da00da2d56b7ba92d78a9c20ce (diff) | |
download | scala-41d7f547c03f2226748a3f9683a4e50084933776.tar.gz scala-41d7f547c03f2226748a3f9683a4e50084933776.tar.bz2 scala-41d7f547c03f2226748a3f9683a4e50084933776.zip |
Fans of scala cinema who have viewed this types...
Fans of scala cinema who have viewed this types video:
http://www.scala-lang.org/sites/default/files/martin_ordersky_scala_inte
rnals_2009-03-04.avi may have noticed that martin entered a variety of
priceless comments in the course of the lecture and never checked them
in. As the self-appointed royal stenographer I have come forward to
right this wrong.
It being a grainy video and almost inaudible, I may well have butchered
it somewhere, so review by odersky.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 178 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 2 |
3 files changed, 117 insertions, 65 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 9dac3c530b..e68fb73596 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -24,14 +24,19 @@ import scala.util.control.ControlThrowable case NoPrefix => case ThisType(sym) => // sym.this.type + case SuperType(thistpe, supertpe) => + // super references case SingleType(pre, sym) => // pre.sym.type case ConstantType(value) => - // int(2) + // Int(2) case TypeRef(pre, sym, args) => // pre.sym[targs] + // Outer.this.C would be represented as TypeRef(ThisType(Outer), C, List()) case RefinedType(parents, defs) => // parent1 with ... with parentn { defs } + case ExistentialType(tparams, result) => + // result forSome { tparams } case AnnotatedType(annots, tp, selfsym) => // tp @annots @@ -43,27 +48,31 @@ import scala.util.control.ControlThrowable // same as RefinedType except as body of class case MethodType(paramtypes, result) => // (paramtypes)result + // For instance def m(): T is represented as MethodType(List(), T) case PolyType(tparams, result) => // [tparams]result where result is a MethodType or ClassInfoType // or // []T for a eval-by-name type - case ExistentialType(tparams, result) => - // exists[tparams]result + // For instance def m: T is represented as PolyType(List(), T) - // the last five types are not used after phase `typer'. + // The remaining types are not used after phase `typer'. case OverloadedType(pre, tparams, alts) => // all alternatives of an overloaded ident - case AntiPolyType(pre: Type, targs) => - case TypeVar(_, _) => + case AntiPolyType(pre, targs) => + // rarely used, disappears when combined with a PolyType + case TypeVar(inst, constr) => // a type variable + // Replace occurrences of type parameters with type vars, where + // inst is the instantiation and constr is a list of bounds. case DeBruijnIndex(level, index) + // for dependent method types: a type referring to a method parameter. + // Not presently used, it seems. */ trait Types extends reflect.generic.Types { self: SymbolTable => import definitions._ - //statistics def uniqueTypeCount = if (uniques == null) 0 else uniques.size @@ -154,7 +163,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable => case ClassInfoType(parents, defs, clazz) => "class "+ clazz.nameString + (parents map debugString).mkString("", " with ", "") + defs.toList.mkString("{", " ;\n ", "}") case PolyType(tparams, result) => tparams.mkString("[", ", ", "] ") + debugString(result) case TypeBounds(lo, hi) => ">: "+ debugString(lo) +" <: "+ debugString(hi) - case tv : TypeVar => tv.toString + case tv @ TypeVar(_, _) => tv.toString case ExistentialType(tparams, qtpe) => "forsome "+ tparams.mkString("[", ", ", "] ") + debugString(qtpe) case _ => tp.toString } @@ -297,13 +306,19 @@ trait Types extends reflect.generic.Types { self: SymbolTable => * identity on all other types */ def underlying: Type = this - /** Widen from singleton type to its underlying non-singleton base type - * by applying one or more `underlying' derefernces, - * identity for all other types */ + /** Widen from singleton type to its underlying non-singleton + * base type by applying one or more `underlying' dereferences, + * identity for all other types. + * + * class Outer { class C ; val x: C } + * val o: Outer + * <o.x.type>.widen = o.C + */ def widen: Type = this /** Map a constant type or not-null-type to its underlying base type, - * identity for all other types */ + * identity for all other types. + */ def deconst: Type = this /** The type of `this' of a class type or reference type @@ -311,6 +326,10 @@ trait Types extends reflect.generic.Types { self: SymbolTable => def typeOfThis: Type = typeSymbol.typeOfThis /** Map to a singleton type which is a subtype of this type. + * The fallback implemented here gives + * T.narrow = (T {}).this.type + * Overridden where we know more about where types come from. + * * todo: change to singleton type of an existentially defined variable * of the right type instead of making this a `this` of a refined type. */ @@ -336,10 +355,13 @@ trait Types extends reflect.generic.Types { self: SymbolTable => * The empty list for all other types */ def parents: List[Type] = List() - /** For a typeref or single-type, the prefix of the normalized type (@see normalize). NoType for all other types. */ + /** For a typeref or single-type, the prefix of the normalized type (@see normalize). + * NoType for all other types. */ def prefix: Type = NoType - /** A chain of all typeref or singletype prefixes of this type, longest first */ + /** A chain of all typeref or singletype prefixes of this type, longest first. + * (Only used from safeToString.) + */ def prefixChain: List[Type] = this match { case TypeRef(pre, _, _) => pre :: pre.prefixChain case SingleType(pre, _) => pre :: pre.prefixChain @@ -353,18 +375,19 @@ trait Types extends reflect.generic.Types { self: SymbolTable => def typeArgs: List[Type] = List() /** For a method or poly type, its direct result type, - * the type itself for all other types */ + * the type itself for all other types. */ def resultType: Type = this def resultType(actuals: List[Type]) = this + /** Only used for dependent method types. */ + def resultApprox: Type = if(settings.YdepMethTpes.value) ApproximateDependentMap(resultType) else resultType + /** If this is a TypeRef `clazz`[`T`], return the argument `T` * otherwise return this type */ def remove(clazz: Symbol): Type = this - def resultApprox: Type = if(settings.YdepMethTpes.value) ApproximateDependentMap(resultType) else resultType - /** For a curried method or poly type its non-method result type, * the type itself for all other types */ def finalResultType: Type = this @@ -413,13 +436,19 @@ trait Types extends reflect.generic.Types { self: SymbolTable => */ def skolemizeExistential(owner: Symbol, origin: AnyRef): Type = this - /** A simple version of skolemizeExistential for situations where * owner or unpack location do not matter (typically used in subtype tests) */ def skolemizeExistential: Type = skolemizeExistential(NoSymbol, null) - /** Reduce to beta eta-long normal form. Expands type aliases and converts higher-kinded TypeRef's to PolyTypes. @M */ + /** Reduce to beta eta-long normal form. + * Expands type aliases and converts higher-kinded TypeRefs to PolyTypes. + * Functions on types are also implemented as PolyTypes. + * + * Example: (in the below, <List> is the type constructor of List) + * TypeRef(pre, <List>, List()) is replaced by + * PolyType(X, TypeRef(pre, <List>, List(X))) + */ def normalize = this // @MAT /** Expands type aliases. */ @@ -436,7 +465,8 @@ trait Types extends reflect.generic.Types { self: SymbolTable => /** For a classtype or refined type, its defined or declared members; * inherited by subtypes and typerefs. - * The empty scope for all other types */ + * The empty scope for all other types. + */ def decls: Scope = EmptyScope /** The defined or declared members with name `name' in this type; @@ -498,15 +528,23 @@ trait Types extends reflect.generic.Types { self: SymbolTable => findMember(name, LOCAL | BRIDGES, 0, false) /** The least type instance of given class which is a supertype - * of this type */ + * of this type. Example: + * class D[T] + * class C extends p.D[Int] + * ThisType(C).baseType(D) = p.D[Int] + */ def baseType(clazz: Symbol): Type = NoType - /** This type as seen from prefix `pre' and class - * `clazz'. This means: + /** This type as seen from prefix `pre' and class `clazz'. This means: * Replace all thistypes of `clazz' or one of its subclasses - * by `pre' and instantiate all parameters by arguments of - * `pre'. + * by `pre' and instantiate all parameters by arguments of `pre'. * Proceed analogously for thistypes referring to outer classes. + * + * Example: + * class D[T] { def m: T } + * class C extends p.D[Int] + * T.asSeenFrom(ThisType(C), D) (where D is owner of m) + * = Int */ def asSeenFrom(pre: Type, clazz: Symbol): Type = if (!isTrivial && (!phase.erasedTypes || pre.typeSymbol == ArrayClass)) { @@ -520,6 +558,11 @@ trait Types extends reflect.generic.Types { self: SymbolTable => } else this /** The info of `sym', seen as a member of this type. + * + * Example: + * class D[T] { def m: T } + * class C extends p.D[Int] + * ThisType(C).memberType(m) = Int */ def memberInfo(sym: Symbol): Type = { sym.info.asSeenFrom(this, sym.owner) @@ -552,8 +595,9 @@ trait Types extends reflect.generic.Types { self: SymbolTable => * first, as otherwise symbols will immediately get rebound in typeRef to the old * symbol. */ - def substSym(from: List[Symbol], to: List[Symbol]): Type = if (from eq to) this - else new SubstSymMap(from, to) apply this + def substSym(from: List[Symbol], to: List[Symbol]): Type = + if (from eq to) this + else new SubstSymMap(from, to) apply this /** Substitute all occurrences of `ThisType(from)' in this type * by `to'. @@ -667,8 +711,8 @@ trait Types extends reflect.generic.Types { self: SymbolTable => if (explainSwitch) explain("specializes", specializesSym, this, sym) else specializesSym(this, sym) - /** Is this type close enough to that type so that - * members with the two type would override each other? + /** Is this type close enough to that type so that members + * with the two type would override each other? * This means: * - Either both types are polytypes with the same number of * type parameters and their result types match after renaming @@ -691,21 +735,29 @@ trait Types extends reflect.generic.Types { self: SymbolTable => * A list or array of types ts is upwards closed if * * for all t in ts: - * for all typerefs p.s[args] such that t <: p.s[args] + * for all typerefs p.s[args] such that t <: p.s[args] * there exists a typeref p'.s[args'] in ts such that - * t <: p'.s['args] <: p.s[args], + * t <: p'.s['args] <: p.s[args], + * * and - * for all singleton types p.s such that t <: p.s + * + * for all singleton types p.s such that t <: p.s * there exists a singleton type p'.s in ts such that - * t <: p'.s <: p.s + * t <: p'.s <: p.s * * Sorting is with respect to Symbol.isLess() on type symbols. */ def baseTypeSeq: BaseTypeSeq = baseTypeSingletonSeq(this) - /** The maximum depth (@see maxDepth) of each type in the BaseTypeSeq of this type. */ + /** The maximum depth (@see maxDepth) + * of each type in the BaseTypeSeq of this type. + */ def baseTypeSeqDepth: Int = 1 + /** The list of all baseclasses of this type (including its own typeSymbol) + * in reverse linearization order, starting with the class itself and ending + * in class Any. + */ def baseClasses: List[Symbol] = List() /** @@ -740,10 +792,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable => protected def objectPrefix = "object " protected def packagePrefix = "package " - def trimPrefix(str: String) = - if (str.startsWith(objectPrefix)) str.substring(objectPrefix.length) - else if (str.startsWith(packagePrefix)) str.substring(packagePrefix.length) - else str + def trimPrefix(str: String) = str stripPrefix objectPrefix stripPrefix packagePrefix /** The string representation of this type used as a prefix */ def prefixString = trimPrefix(toString) + "#" @@ -1036,7 +1085,9 @@ trait Types extends reflect.generic.Types { self: SymbolTable => override def kind = "ErrorType" } - /** An object representing an unknown type */ + /** An object representing an unknown type, used during type inference. + * If you see WildcardType outside of inference it is almost certainly a bug. + */ case object WildcardType extends Type { override def isWildcard = true override def safeToString: String = "?" @@ -1107,7 +1158,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable => // // todo: this should be a subtype, which forwards to underlying // } - /** A class for singleton types of the form <prefix>.<sym.name>.type. + /** A class for singleton types of the form <prefix>.<sym.name>.type. * Cannot be created directly; one should always use * `singleType' for creation. */ @@ -1333,15 +1384,18 @@ trait Types extends reflect.generic.Types { self: SymbolTable => } /** A class representing intersection types with refinements of the form - * `<parents_0> with ... with <parents_n> { decls }' + * `<parents_0> with ... with <parents_n> { decls }' * Cannot be created directly; * one should always use `refinedType' for creation. */ case class RefinedType(override val parents: List[Type], override val decls: Scope) extends CompoundType { - override def isHigherKinded = - !parents.isEmpty && (parents forall (_.isHigherKinded)) // @MO to AM: please check this class! + override def isHigherKinded = ( + parents.nonEmpty && + (parents forall (_.isHigherKinded)) && + !phase.erasedTypes // @MO to AM: please check this class! + ) override def typeParams = if (isHigherKinded) parents.head.typeParams @@ -1585,7 +1639,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable => private val pendingVolatiles = new collection.mutable.HashSet[Symbol] /** A class for named types of the form - * `<prefix>.<sym.name>[args]' + * `<prefix>.<sym.name>[args]' * Cannot be created directly; one should always use `typeRef' * for creation. (@M: Otherwise hashing breaks) * @@ -1922,6 +1976,11 @@ A type's typeSymbol should never be inspected directly. } /** A class representing a method type with parameters. + * Note that a parameterless method is instead encoded + * as a PolyType, as shown here: + * + * def m(): Int MethodType(Nil, Int) + * def m: Int PolyType(Nil, Int) */ case class MethodType(override val params: List[Symbol], override val resultType: Type) extends Type { @@ -1994,14 +2053,14 @@ A type's typeSymbol should never be inspected directly. override def isJava = true } - /** A class representing a polymorphic type or, if tparams.length == 0, - * a parameterless method type. + /** A class representing a polymorphic type or, if typeParams.isEmpty, a parameterless method type. + * * (@M: note that polymorphic nullary methods have non-empty tparams, * e.g., isInstanceOf or def makeList[T] = new List[T]. * Ideally, there would be a NullaryMethodType, but since the only polymorphic values are methods, it's not that problematic. * More pressingly, we should add a TypeFunction type for anonymous type constructors -- for now, PolyType is used in: * - normalize: for eta-expansion of type aliases - * - abstractTypeSig ) + * - typeDefSig ) */ case class PolyType(override val typeParams: List[Symbol], override val resultType: Type) extends Type { @@ -2025,7 +2084,7 @@ A type's typeSymbol should never be inspected directly. override def isVolatile = resultType.isVolatile override def finalResultType: Type = resultType.finalResultType - /** @M: abstractTypeSig now wraps a TypeBounds in a PolyType + /** @M: typeDefSig now wraps a TypeBounds in a PolyType * to represent a higher-kinded type parameter * wrap lo&hi in polytypes to bind variables */ @@ -2896,15 +2955,8 @@ A type's typeSymbol should never be inspected directly. val dropNonConstraintAnnotations = false /** Check whether two lists have elements that are eq-equal */ - def allEq[T <: AnyRef](l1: List[T], l2: List[T]): Boolean = - (l1, l2) match { - case (Nil, Nil) => true - case (hd1::tl1, hd2::tl2) => - if (!(hd1 eq hd2)) - return false - allEq(tl1, tl2) - case _ => false - } + def allEq[T <: AnyRef](l1: List[T], l2: List[T]) = + (l1 corresponds l2)(_ eq _) // #3731: return sym1 for which holds: pre bound sym.name to sym and pre1 now binds sym.name to sym1, conceptually exactly the same symbol as sym // the selection of sym on pre must be updated to the selection of sym1 on pre1, @@ -4370,7 +4422,7 @@ A type's typeSymbol should never be inspected directly. val tpsFresh = cloneSymbols(tparams1) (tparams1 corresponds tparams2)((p1, p2) => - p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) && // @PP: corresponds + p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) && res1.substSym(tparams1, tpsFresh) <:< res2.substSym(tparams2, tpsFresh) //@M the forall in the previous test could be optimised to the following, @@ -4837,7 +4889,7 @@ A type's typeSymbol should never be inspected directly. var bounds = instantiatedBounds(pre, owner, tparams, targs) if (targs.exists(_.annotations.nonEmpty)) bounds = adaptBoundsToAnnotations(bounds, tparams, targs) - (bounds corresponds targs)(_ containsType _) // @PP: corresponds + (bounds corresponds targs)(_ containsType _) } def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] = @@ -4846,9 +4898,9 @@ A type's typeSymbol should never be inspected directly. // Lubs and Glbs --------------------------------------------------------- /** The least sorted upwards closed upper bound of a non-empty list - * of lists of types relative to the following ordering <= between lists of types: + * of lists of types relative to the following ordering <= between lists of types: * - * xs <= ys iff forall y in ys exists x in xs such that x <: y + * xs <= ys iff forall y in ys exists x in xs such that x <: y * * @See baseTypeSeq for a definition of sorted and upwards closed. */ @@ -5010,7 +5062,7 @@ A type's typeSymbol should never be inspected directly. glbResults.clear() } - /** The least upper bound wrt <:< of a list of types */ + /** The least upper bound wrt <:< of a list of types */ def lub(ts: List[Type], depth: Int): Type = { def lub0(ts0: List[Type]): Type = elimSub(ts0, depth) match { case List() => NothingClass.tpe @@ -5125,7 +5177,7 @@ A type's typeSymbol should never be inspected directly. glbResults.clear() } - /** The greatest lower bound wrt <:< of a list of types */ + /** The greatest lower bound wrt <:< of a list of types */ private def glb(ts: List[Type], depth: Int): Type = { def glb0(ts0: List[Type]): Type = elimSuper(ts0 map (_.deconst)) match {// todo: deconst needed? case List() => AnyClass.tpe diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index dd6d7b23a6..51ace68ddc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -421,7 +421,7 @@ trait Infer { def isCoercible(tp: Type, pt: Type): Boolean = false def isCompatibleArgs(tps: List[Type], pts: List[Type]) = - (tps corresponds pts)(isCompatibleArg) // @PP: corresponds + (tps corresponds pts)(isCompatibleArg) /* -- Type instantiation------------------------------------------------ */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 533793dbc4..3133449050 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1218,7 +1218,7 @@ trait Namers { self: Analyzer => ErrorType } result match { - case PolyType(tparams, restpe) if (tparams.nonEmpty && tparams.head.owner.isTerm) => + case PolyType(tparams @ (tp :: _), _) if tp.owner.isTerm => // || // Adriaan: The added condition below is quite a hack. It seems that HK type parameters is relying // on a pass that forces all infos in the type to get everything right. |