alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (Types.scala)

This example Scala source code file (Types.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

boolean, boolean, existentialtype, int, list, list, notype, symbol, symbol, type, type, typebounds, typeref, typevar

The Scala Types.scala source code

/* NSC -- new Scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala.tools.nsc
package symtab

import scala.collection.{ mutable, immutable }
import scala.ref.WeakReference
import mutable.ListBuffer
import ast.TreeGen
import util.{ Position, NoPosition }
import util.Statistics._
import Flags._
import scala.util.control.ControlThrowable
import scala.annotation.tailrec

/* A standard type pattern match:
  case ErrorType =>
    // internal: error
  case WildcardType =>
    // internal: unknown
  case NoType =>
  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)
  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

  // the following are non-value types; you cannot write them down in Scala source.

  case TypeBounds(lo, hi) =>  
    // >: lo <: hi
  case ClassInfoType(parents, defs, clazz) =>
    // 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 NullaryMethodType(result) => // eliminated by uncurry
    // an eval-by-name type
    // For instance def m: T is represented as NullaryMethodType(T)
  case PolyType(tparams, result) =>
    // [tparams]result where result is a (Nullary)MethodType or ClassInfoType

  // The remaining types are not used after phase `typer'. 
  case OverloadedType(pre, tparams, alts) =>
    // all alternatives of an overloaded ident
  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

  private var explainSwitch = false
  private final val emptySymbolSet = immutable.Set.empty[Symbol]

  private final val alternativeNarrow = false

  private final val LogPendingSubTypesThreshold = 50
  private final val LogPendingBaseTypesThreshold = 50
  private final val LogVolatileThreshold = 50

  /** A don't care value for the depth parameter in lubs/glbs and related operations */
  private final val AnyDepth = -3

  /** Decrement depth unless it is a don't care */
  private final def decr(depth: Int) = if (depth == AnyDepth) AnyDepth else depth - 1

  private final val printLubs = false
  /** In case anyone wants to turn off lub verification without reverting anything. */
  private final val verifyLubs = true

  /** The current skolemization level, needed for the algorithms
   *  in isSameType, isSubType that do constraint solving under a prefix 
   */
  var skolemizationLevel = 0

  /** A log of type variable with their original constraints. Used in order
   *  to undo constraints in the case of isSubType/isSameType failure.
   */
  object undoLog {
    private type UndoLog = List[(TypeVar, TypeConstraint)]
    private[nsc] var log: UndoLog = List()

    /** Undo all changes to constraints to type variables upto `limit'
     */
    private def undoTo(limit: UndoLog) {
      while ((log ne limit) && log.nonEmpty) {
        val (tv, constr) = log.head
        tv.constr = constr
        log = log.tail
      }
    }

    private[Types] def record(tv: TypeVar) = {
      log ::= (tv, tv.constr.cloneInternal)
    }
    private[nsc] def clear() {
      if (settings.debug.value)
        self.log("Clearing " + log.size + " entries from the undoLog.")

      log = Nil
    }

    // `block` should not affect constraints on typevars
    def undo[T](block: => T): T = {
      val before = log

      try block
      finally undoTo(before)
    }

    // if `block` evaluates to false, it should not affect constraints on typevars
    def undoUnless(block: => Boolean): Boolean = {
      val before = log
      var result = false
      
      try result = block
      finally if (!result) undoTo(before)
      
      result
    }
  }

  /** A map from lists to compound types that have the given list as parents.
   *  This is used to avoid duplication in the computation of base type sequences and baseClasses.
   *  It makes use of the fact that these two operations depend only on the parents,
   *  not on the refinement.
   */
  val intersectionWitness = new mutable.WeakHashMap[List[Type], WeakReference[Type]]

  private object gen extends {
    val global : Types.this.type = Types.this
  } with TreeGen

  import gen._

  /** A proxy for a type (identified by field `underlying') that forwards most 
   *  operations to it (for exceptions, see WrappingProxy, which forwards even more operations).
   *  every operation that is overridden for some kind of types should be forwarded.
   */
  trait SimpleTypeProxy extends Type {
    def underlying: Type

    // the following operations + those in RewrappingTypeProxy are all operations 
    // in class Type that are overridden in some subclass
    // Important to keep this up-to-date when new operations are added!
    override def isTrivial = underlying.isTrivial
    override def isHigherKinded: Boolean = underlying.isHigherKinded
    override def typeConstructor: Type = underlying.typeConstructor 
    override def isNotNull = underlying.isNotNull
    override def isError = underlying.isError
    override def isErroneous = underlying.isErroneous
    override def isStable: Boolean = underlying.isStable
    override def isVolatile = underlying.isVolatile
    override def finalResultType = underlying.finalResultType
    override def paramSectionCount = underlying.paramSectionCount
    override def paramss = underlying.paramss
    override def params = underlying.params
    override def paramTypes = underlying.paramTypes
    override def termSymbol = underlying.termSymbol
    override def termSymbolDirect = underlying.termSymbolDirect
    override def typeParams = underlying.typeParams
    override def boundSyms = underlying.boundSyms
    override def typeSymbol = underlying.typeSymbol
    override def typeSymbolDirect = underlying.typeSymbolDirect
    override def widen = underlying.widen
    override def typeOfThis = underlying.typeOfThis
    override def bounds = underlying.bounds
    override def parents = underlying.parents
    override def prefix = underlying.prefix
    override def decls = underlying.decls
    override def baseType(clazz: Symbol) = underlying.baseType(clazz)
    override def baseTypeSeq = underlying.baseTypeSeq
    override def baseTypeSeqDepth = underlying.baseTypeSeqDepth
    override def baseClasses = underlying.baseClasses
  }

  /** A proxy for a type (identified by field `underlying') that forwards most 
   *  operations to it. Every operation that is overridden for some kind of types is
   *  forwarded here. Some operations are rewrapped again.
   */
  trait RewrappingTypeProxy extends SimpleTypeProxy {
    protected def maybeRewrap(newtp: Type) = if (newtp eq underlying) this else rewrap(newtp)
    protected def rewrap(newtp: Type): Type

    // the following are all operations in class Type that are overridden in some subclass
    // Important to keep this up-to-date when new operations are added!
    override def widen = maybeRewrap(underlying.widen)
    override def narrow = underlying.narrow
    override def deconst = maybeRewrap(underlying.deconst)
    override def resultType = maybeRewrap(underlying.resultType)
    override def resultType(actuals: List[Type]) = maybeRewrap(underlying.resultType(actuals))
    override def finalResultType = maybeRewrap(underlying.finalResultType)
    override def paramSectionCount = 0
    override def paramss: List[List[Symbol]] = List()
    override def params: List[Symbol] = List()
    override def paramTypes: List[Type] = List()
    override def typeArgs = underlying.typeArgs
    override def notNull = maybeRewrap(underlying.notNull)
    override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = underlying.instantiateTypeParams(formals, actuals)
    override def skolemizeExistential(owner: Symbol, origin: AnyRef) = underlying.skolemizeExistential(owner, origin)
    override def normalize = maybeRewrap(underlying.normalize)
    override def dealias = maybeRewrap(underlying.dealias)
    override def cloneInfo(owner: Symbol) = maybeRewrap(underlying.cloneInfo(owner))
    override def atOwner(owner: Symbol) = maybeRewrap(underlying.atOwner(owner))
    override def prefixString = underlying.prefixString
    override def isComplete = underlying.isComplete
    override def complete(sym: Symbol) = underlying.complete(sym)
    override def load(sym: Symbol) { underlying.load(sym) }
    override def withAnnotations(annots: List[AnnotationInfo]) = maybeRewrap(underlying.withAnnotations(annots))
    override def withoutAnnotations = maybeRewrap(underlying.withoutAnnotations)
  }

  /** The base class for all types */
  abstract class Type extends AbsType {
    
    /** Types for which asSeenFrom always is the identity, no matter what
     *  prefix or owner.
     */
    def isTrivial: Boolean = false

    /** Is this type higher-kinded, i.e., is it a type constructor @M */
    def isHigherKinded: Boolean = false 
    
    /** Does this type denote a stable reference (i.e. singleton type)? */
    def isStable: Boolean = false

    /** Is this type dangerous (i.e. it might contain conflicting
     *  type information when empty, so that it can be constructed
     *  so that type unsoundness results.) A dangerous type has an underlying
     *  type of the form T_1 with T_n { decls }, where one of the
     *  T_i (i > 1) is an abstract type.
     */
    def isVolatile: Boolean = false

    /** Is this type guaranteed not to have `null' as a value? */
    def isNotNull: Boolean = false

    /** Is this type a structural refinement type (it 'refines' members that have not been inherited) */
    def isStructuralRefinement: Boolean = false

    /** Does this type depend immediately on an enclosing method parameter? 
      * i.e., is it a singleton type whose termSymbol refers to an argument of the symbol's owner (which is a method)
      */
    def isImmediatelyDependent: Boolean = false

    /** Does this depend on an enclosing method parameter? */
    def isDependent: Boolean = IsDependentCollector.collect(this)

    /** True for WildcardType or BoundedWildcardType */
    def isWildcard = false

    /** The term symbol associated with the type
      * Note that the symbol of the normalized type is returned (@see normalize)
      */
    def termSymbol: Symbol = NoSymbol

    /** The type symbol associated with the type
      * Note that the symbol of the normalized type is returned (@see normalize)
      */
    def typeSymbol: Symbol = NoSymbol

    /** The term symbol *directly* associated with the type
      */
    def termSymbolDirect: Symbol = termSymbol

    /** The type symbol *directly* associated with the type
      */
    def typeSymbolDirect: Symbol = typeSymbol

    /** The base type underlying a type proxy,
     *  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' 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.
     */
    def deconst: Type = this

    /** The type of `this' of a class type or reference type
     */
    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.
     */
    def narrow: Type =
      if (phase.erasedTypes) this
      else if (alternativeNarrow) { // investigate why this does not work!
        val tparam = commonOwner(this) freshExistential ".type" setInfo singletonBounds(this)
        tparam.tpe
      } else {
        val cowner = commonOwner(this)
        refinedType(List(this), cowner, EmptyScope, cowner.pos).narrow
      }

    /** For a TypeBounds type, itself;
     *  for a reference denoting an abstract type, its bounds,
     *  for all other types, a TypeBounds type all of whose bounds are this type.
     */
    def bounds: TypeBounds = TypeBounds(this, this)

    /** For a class or intersection type, its parents.
     *  For a TypeBounds type, the parents of its hi bound.
     *  inherited by typerefs, singleton types, and refinement types,
     *  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. */
    def prefix: Type = NoType

    /** 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
      case _ => List()
    }

    /** This type, without its type arguments @M */
    def typeConstructor: Type = this

    /** For a typeref, its arguments. The empty list for all other types */
    def typeArgs: List[Type] = List()

    /** For a (nullary) method or poly type, its direct result type, 
     *  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

    /** For a curried/nullary method or poly type its non-method result type, 
     *  the type itself for all other types */
    def finalResultType: Type = this

    /** For a method type, the number of its value parameter sections,
     *  0 for all other types */
    def paramSectionCount: Int = 0

    /** For a method or poly type, a list of its value parameter sections,
     *  the empty list for all other types */
    def paramss: List[List[Symbol]] = List()

    /** For a method or poly type, its first value parameter section,
     *  the empty list for all other types */
    def params: List[Symbol] = List()

    /** For a method or poly type, the types of its first value parameter section,
     *  the empty list for all other types */
    def paramTypes: List[Type] = List()
    
    /** For a (potentially wrapped) poly type, its type parameters,
     *  the empty list for all other types */
    def typeParams: List[Symbol] = List()
  
    /** For a (potentially wrapped) poly or existential type, its bound symbols,
     *  the empty list for all other types */
    def boundSyms: immutable.Set[Symbol] = emptySymbolSet

    /** Mixin a NotNull trait unless type already has one
     *  ...if the option is given, since it is causing typing bugs.
     */
    def notNull: Type =
      if (!settings.Ynotnull.value || isNotNull || phase.erasedTypes) this
      else NotNullType(this)
    
    /** Replace formal type parameter symbols with actual type arguments. 
     *
     * Amounts to substitution except for higher-kinded types. (See overridden method in TypeRef) -- @M
     */
    def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
      if (sameLength(formals, actuals)) this.subst(formals, actuals) else ErrorType

    /** If this type is an existential, turn all existentially bound variables to type skolems.
     *  @param  owner    The owner of the created type skolems
     *  @param  origin   The tree whose type was an existential for which the skolem was created.
     */
    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 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. */
    def dealias = this
    
    /** Is this type produced as a repair for an error? */
    def isError: Boolean = typeSymbol.isError || termSymbol.isError

    /** Is this type produced as a repair for an error? */
    def isErroneous: Boolean = ErroneousCollector.collect(this)

    /** Does this type denote a reference type which can be null? */
    // def isNullable: Boolean = false

    /** For a classtype or refined type, its defined or declared members;
     *  inherited by subtypes and typerefs.
     *  The empty scope for all other types.
     */
    def decls: Scope = EmptyScope

    /** The defined or declared members with name `name' in this type;
     *  an OverloadedSymbol if several exist, NoSymbol if none exist.
     *  Alternatives of overloaded symbol appear in the order they are declared.
     */
    def decl(name: Name): Symbol = findDecl(name, 0)

    /** The non-private defined or declared members with name `name' in this type;
     *  an OverloadedSymbol if several exist, NoSymbol if none exist.
     *  Alternatives of overloaded symbol appear in the order they are declared.
     */
    def nonPrivateDecl(name: Name): Symbol = findDecl(name, PRIVATE)

    /** A list of all members of this type (defined or inherited)
     *  Members appear in linearization order of their owners.
     *  Members with the same owner appear in reverse order of their declarations.
     */
    def members: List[Symbol] = findMember(nme.ANYNAME, 0, 0, false).alternatives

    /** A list of all non-private members of this type (defined or inherited) */
    def nonPrivateMembers: List[Symbol] =
      findMember(nme.ANYNAME, PRIVATE | BRIDGES, 0, false).alternatives

    /** A list of all non-private members of this type  (defined or inherited),
     *  admitting members with given flags `admit`
     */
    def nonPrivateMembersAdmitting(admit: Long): List[Symbol] =
      findMember(nme.ANYNAME, (PRIVATE | BRIDGES) & ~admit, 0, false).alternatives

    /** A list of all implicit symbols of this type  (defined or inherited) */
    def implicitMembers: List[Symbol] =
      findMember(nme.ANYNAME, BRIDGES, IMPLICIT, false).alternatives

    /** A list of all deferred symbols of this type  (defined or inherited) */
    def deferredMembers: List[Symbol] =
      findMember(nme.ANYNAME, BRIDGES, DEFERRED, false).alternatives

    /** The member with given name, 
     *  an OverloadedSymbol if several exist, NoSymbol if none exist */
    def member(name: Name): Symbol = findMember(name, BRIDGES, 0, false)

    /** The non-private member with given name,
     *  an OverloadedSymbol if several exist, NoSymbol if none exist.
     *  Bridges are excluded from the result
     */
    def nonPrivateMember(name: Name): Symbol =
      findMember(name, PRIVATE | BRIDGES, 0, false)
  
    /** The non-private member with given name, admitting members with given flags `admit`
     *  an OverloadedSymbol if several exist, NoSymbol if none exist
     */
    def nonPrivateMemberAdmitting(name: Name, admit: Long): Symbol =
      findMember(name, (PRIVATE | BRIDGES) & ~admit, 0, false)
  
    /** The non-local member with given name,
     *  an OverloadedSymbol if several exist, NoSymbol if none exist */
    def nonLocalMember(name: Name): Symbol =
      findMember(name, LOCAL | BRIDGES, 0, false)

    /** The least type instance of given class which is a supertype
     *  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:
     *  Replace all thistypes of `clazz' or one of its subclasses
     *  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)) {
        incCounter(asSeenFromCount)
        val start = startTimer(asSeenFromNanos)
        val m = new AsSeenFromMap(pre.normalize, clazz)
        val tp = m apply this
        val result = existentialAbstraction(m.capturedParams, tp)
        stopTimer(asSeenFromNanos, start)
        result
      } 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)
    }

    /** The type of `sym', seen as a member of this type. */
    def memberType(sym: Symbol): Type = sym match {
      case meth: MethodSymbol =>
        meth.typeAsMemberOf(this)
      case _ =>
        computeMemberType(sym)
    }

    def computeMemberType(sym: Symbol): Type = sym.tpeHK match { //@M don't prematurely instantiate higher-kinded types, they will be instantiated by transform, typedTypeApply, etc. when really necessary
      case OverloadedType(_, alts) =>
        OverloadedType(this, alts)
      case tp =>
        tp.asSeenFrom(this, sym.owner)
    }

    /** Substitute types `to' for occurrences of references to
     *  symbols `from' in this type.
     */
    def subst(from: List[Symbol], to: List[Type]): Type =
      if (from.isEmpty) this
      else new SubstTypeMap(from, to) apply this

    /** Substitute symbols `to' for occurrences of symbols
     *  `from' in this type.
     * !!! NOTE !!!: If you need to do a substThis and a substSym, the substThis has to come
     * 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

    /** Substitute all occurrences of `ThisType(from)' in this type
     *  by `to'.
     * !!! NOTE !!!: If you need to do a substThis and a substSym, the substThis has to come
     * first, as otherwise symbols will immediately get rebound in typeRef to the old 
     * symbol.
     */
    def substThis(from: Symbol, to: Type): Type =
      new SubstThisMap(from, to) apply this

    def substSuper(from: Type, to: Type): Type =
      new SubstSuperMap(from, to) apply this

    /** Returns all parts of this type which satisfy predicate `p' */
    def filter(p: Type => Boolean): List[Type] = new FilterTypeCollector(p).collect(this).toList

    /** Returns optionally first type (in a preorder traversal) which satisfies predicate `p',
     *  or None if none exists. 
     */
    def find(p: Type => Boolean): Option[Type] = new FindTypeCollector(p).collect(this)

    /** Apply `f' to each part of this type */
    def foreach(f: Type => Unit) { new ForEachTypeTraverser(f).traverse(this) }

    /** Apply `f' to each part of this type; children get mapped before their parents */
    def map(f: Type => Type): Type = new TypeMap {
      def apply(x: Type) = f(mapOver(x))
    } apply this

    /** Is there part of this type which satisfies predicate `p'? */
    def exists(p: Type => Boolean): Boolean = !find(p).isEmpty

    /** Does this type contain a reference to this symbol? */
    def contains(sym: Symbol): Boolean = new ContainsCollector(sym).collect(this)

    /** Does this type contain a reference to this type */
    def containsTp(tp: Type): Boolean = new ContainsTypeCollector(tp).collect(this)

    /** Is this type a subtype of that type? */
    def <:<(that: Type): Boolean = {
      if (util.Statistics.enabled) stat_<:<(that)
      else {
        (this eq that) ||
        (if (explainSwitch) explain("<:", isSubType, this, that)
         else isSubType(this, that, AnyDepth))
      }
    }
    
    /** Can this type only be subtyped by bottom types?
     *  This is assessed to be the case if the class is final,
     *  and all type parameters (if any) are invariant.
     */
    def isFinalType = (
      typeSymbol.isFinal &&
      (typeSymbol.typeParams forall (_.variance == 0))
    )
    
    /** Is this type a subtype of that type in a pattern context?
     *  Any type arguments on the right hand side are replaced with
     *  fresh existentials, except for Arrays.
     *
     *  See bug1434.scala for an example of code which would fail
     *  if only a <:< test were applied.
     */     
    def matchesPattern(that: Type): Boolean = {
      (this <:< that) || ((this, that) match {        
        case (TypeRef(_, ArrayClass, List(arg1)), TypeRef(_, ArrayClass, List(arg2))) if arg2.typeSymbol.typeParams.nonEmpty =>
          arg1 matchesPattern arg2
        case (_, TypeRef(_, _, args)) =>
          val newtp = existentialAbstraction(args map (_.typeSymbol), that)
          !(that =:= newtp) && (this <:< newtp)
        case _ =>
          false
      })
    }
    
    def stat_<:<(that: Type): Boolean = {
      incCounter(subtypeCount)
      val start = startTimer(subtypeNanos)
      val result = 
        (this eq that) ||
        (if (explainSwitch) explain("<:", isSubType, this, that)
         else isSubType(this, that, AnyDepth))
      stopTimer(subtypeNanos, start)
      result
    }

    /** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
     */
    def weak_<:<(that: Type): Boolean = {
      incCounter(subtypeCount)
      val start = startTimer(subtypeNanos)
      val result =
        ((this eq that) ||
         (if (explainSwitch) explain("weak_<:", isWeakSubType, this, that)
          else isWeakSubType(this, that)))
      stopTimer(subtypeNanos, start)
      result
    }

    /** Is this type equivalent to that type? */
    def =:=(that: Type): Boolean = (
      (this eq that) ||
      (if (explainSwitch) explain("=", isSameType, this, that)
       else isSameType(this, that))
    );

    /** Does this type implement symbol `sym' with same or stronger type?
     */
    def specializes(sym: Symbol): Boolean =
      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?
     *  This means: 
     *    - Either both types are polytypes with the same number of
     *      type parameters and their result types match after renaming 
     *      corresponding type parameters
     *    - Or both types are (nullary) method types with equivalent type parameter types
     *      and matching result types
     *    - Or both types are equivalent
     *    - Or phase.erasedTypes is false and both types are neither method nor
     *      poly types.
     */
    def matches(that: Type): Boolean = matchesType(this, that, !phase.erasedTypes)

    /** Same as matches, except that non-method types are always assumed to match.
     */
    def looselyMatches(that: Type): Boolean = matchesType(this, that, true)

    /** The shortest sorted upwards closed array of types that contains
     *  this type as first element.
     *
     *  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] 
     *      there exists a typeref p'.s[args'] in ts such that 
     *      t <: p'.s['args] <: p.s[args],
     *
     *      and
     *
     *      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
     *
     *  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.
     */
    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()

    /**
     *  @param sym the class symbol
     *  @return    the index of given class symbol in the BaseTypeSeq of this type,
     *             or -1 if no base type with given class symbol exists.
     */
    def baseTypeIndex(sym: Symbol): Int = {
      val bts = baseTypeSeq
      var lo = 0
      var hi = bts.length - 1
      while (lo <= hi) {
        val mid = (lo + hi) / 2
        val btssym = bts.typeSymbol(mid)
        if (sym == btssym) return mid
        else if (sym isLess btssym) hi = mid - 1
        else if (btssym isLess sym) lo = mid + 1
        else abort()
      }
      -1
    }

    /** If this is a poly- or methodtype, a copy with cloned type / value parameters
     *  owned by `owner'. Identity for all other types.
     */
    def cloneInfo(owner: Symbol) = this

    /** Make sure this type is correct as the info of given owner; clone it if not.
     */
    def atOwner(owner: Symbol) = this

    protected def objectPrefix = "object "
    protected def packagePrefix = "package "

    def trimPrefix(str: String) = str stripPrefix objectPrefix stripPrefix packagePrefix

    /** The string representation of this type used as a prefix */
    def prefixString = trimPrefix(toString) + "#"

    /** The string representation of this type, with singletypes explained */
    def toLongString = {
      val str = toString
      if (str endsWith ".type") str + " (with underlying type " + widen + ")"
      else str
    }

    /** A test whether a type contains any unification type variables */
    def isGround: Boolean = this match {
      case TypeVar(_, constr) => 
        constr.instValid && constr.inst.isGround
      case TypeRef(pre, sym, args) =>
        sym.isPackageClass || pre.isGround && (args forall (_.isGround))
      case SingleType(pre, sym) =>
        sym.isPackageClass || pre.isGround
      case ThisType(_) | NoPrefix | WildcardType | NoType | ErrorType | ConstantType(_) =>
        true
      case _ => 
        typeVarToOriginMap(this) eq this
    }

    /** If this is a symbol loader type, load and assign a new type to
     *  `sym'.
     */
    def load(sym: Symbol) {}

    private def findDecl(name: Name, excludedFlags: Int): Symbol = {
      var alts: List[Symbol] = List()
      var sym: Symbol = NoSymbol
      var e: ScopeEntry = decls.lookupEntry(name)
      while (e ne null) {
        if (!e.sym.hasFlag(excludedFlags)) {
          if (sym == NoSymbol) sym = e.sym
          else {
            if (alts.isEmpty) alts = List(sym)
            alts = e.sym :: alts
          }
        }
        e = decls.lookupNextEntry(e)
      }
      if (alts.isEmpty) sym
      else (baseClasses.head.newOverloaded(this, alts))
    }
    
    /**
     *  Find member(s) in this type. If several members matching criteria are found, they are
     *  returned in an OverloadedSymbol
     *  
     *  @param name           The member's name, where nme.ANYNAME means `unspecified' 
     *  @param excludedFlags  Returned members do not have these flags
     *  @param requiredFlags  Returned members do have these flags
     *  @param stableOnly     If set, return only members that are types or stable values
     */
    //TODO: use narrow only for modules? (correct? efficiency gain?)
    def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = {
      var suspension: mutable.HashSet[TypeVar] = null
      // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by
      // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements
      // without this, the matchesType call would lead to type variables on both sides
      // of a subtyping/equality judgement, which can lead to recursive types being constructed.
      // See (t0851) for a situation where this happens.
      if (!this.isGround) {
        // PP: The foreach below was formerly expressed as:
        //   for(tv @ TypeVar(_, _) <- this) { suspension suspend tv }
        //
        // The tree checker failed this saying a TypeVar is required, but a (Type @unchecked) was found.
        // This is a consequence of using a pattern match and variable binding + ticket #1503, which
        // was addressed by weakening the type of bindings in pattern matches if they occur on the right.
        // So I'm not quite sure why this works at all, as the checker is right that it is mistyped.
        // For now I modified it as below, which achieves the same without error.
        //
        // make each type var in this type use its original type for comparisons instead of collecting constraints
        val susp = new mutable.HashSet[TypeVar] // use a local val so it remains unboxed
        this foreach {
          case tv: TypeVar  => tv.suspended = true; susp += tv
          case _            => 
        }
        suspension = susp
      }

      incCounter(findMemberCount)
      val start = startTimer(findMemberNanos)

      //Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
      var members: Scope = null
      var member: Symbol = NoSymbol
      var excluded = excludedFlags | DEFERRED
      var continue = true
      var self: Type = null
      var membertpe: Type = null
      while (continue) {
        continue = false
        val bcs0 = baseClasses
        var bcs = bcs0
        while (!bcs.isEmpty) {
          val decls = bcs.head.info.decls
          var entry =
            if (name == nme.ANYNAME) decls.elems else decls.lookupEntry(name)
          while (entry ne null) {
            val sym = entry.sym
            if (sym hasAllFlags requiredFlags) {
              val excl = sym.getFlag(excluded)
              if (excl == 0L && 
                  (// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
                   (bcs eq bcs0) ||
                   !sym.isPrivateLocal ||
                   (bcs0.head.hasTransOwner(bcs.head)))) {
                if (name.isTypeName || stableOnly && sym.isStable) {
                  stopTimer(findMemberNanos, start)
                  if (suspension ne null) suspension foreach (_.suspended = false)
                  return sym
                } else if (member == NoSymbol) {
                  member = sym
                } else if (members eq null) {
                  if (member.name != sym.name || 
                      !(member == sym ||
                        member.owner != sym.owner &&
                        !sym.isPrivate && {
                          if (self eq null) self = this.narrow
                          if (membertpe eq null) membertpe = self.memberType(member)
                          (membertpe matches self.memberType(sym))
                        })) {
                    members = new Scope(List(member, sym))
                  }
                } else {
                  var prevEntry = members.lookupEntry(sym.name)
                  var symtpe: Type = null
                  while ((prevEntry ne null) &&
                         !(prevEntry.sym == sym ||
                           prevEntry.sym.owner != sym.owner &&
                           !sym.hasFlag(PRIVATE) && {
                             if (self eq null) self = this.narrow
                             if (symtpe eq null) symtpe = self.memberType(sym)
                             self.memberType(prevEntry.sym) matches symtpe
                           })) {
                    prevEntry = members lookupNextEntry prevEntry
                  }
                  if (prevEntry eq null) {
                    members enter sym
                  }
                }
              } else if (excl == DEFERRED.toLong) {
                continue = true
              }
            }
            entry = if (name == nme.ANYNAME) entry.next else decls lookupNextEntry entry
          } // while (entry ne null)
          // excluded = excluded | LOCAL
          bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
        } // while (!bcs.isEmpty)
        excluded = excludedFlags
      } // while (continue)
      stopTimer(findMemberNanos, start)
      if (suspension ne null) suspension foreach (_.suspended = false)
      if (members eq null) {
        if (member == NoSymbol) incCounter(noMemberCount)
        member
      } else {
        incCounter(multMemberCount)
        baseClasses.head.newOverloaded(this, members.toList)
      }
    }

    /** The existential skolems and existentially quantified variables which are free in this type */
    def existentialSkolems: List[Symbol] = {
      var boundSyms: List[Symbol] = List()
      var skolems: List[Symbol] = List()
      for (t <- this) {
        t match {
          case ExistentialType(quantified, qtpe) =>
            boundSyms = boundSyms ::: quantified
          case TypeRef(_, sym, _) =>
            if ((sym hasFlag EXISTENTIAL) && !(boundSyms contains sym) && !(skolems contains sym))
              skolems = sym :: skolems
          case _ =>
        }
      }
      skolems
    }

    /** Return the annotations on this type. */
    def annotations: List[AnnotationInfo] = Nil

    /** Test for the presence of an annotation */
    def hasAnnotation(clazz: Symbol) = annotations exists { _.atp.typeSymbol == clazz }

    /** Add an annotation to this type */
    def withAnnotation(annot: AnnotationInfo) = withAnnotations(List(annot))
    
    /** Add a number of annotations to this type */
    def withAnnotations(annots: List[AnnotationInfo]): Type =
      annots match {
        case Nil => this
        case _ => AnnotatedType(annots, this, NoSymbol)
      }
      
    /** Remove any annotations from this type */
    def withoutAnnotations = this

    /** Remove any annotations from this type and from any
     *  types embedded in this type. */
    def stripAnnotations = StripAnnotationsMap(this)

    /** Set the self symbol of an annotated type, or do nothing
     *  otherwise.  */
    def withSelfsym(sym: Symbol) = this

    /** The selfsym of an annotated type, or NoSymbol of anything else */
    def selfsym: Symbol = NoSymbol

    /** The kind of this type; used for debugging */
    def kind: String = "unknown type of class "+getClass()
  }

// Subclasses ------------------------------------------------------------

  trait UniqueType {
    override lazy val hashCode: Int = super.hashCode()
  }

 /** A base class for types that defer some operations
   *  to their immediate supertype.
   */
  abstract class SubType extends Type {
    def supertype: Type
    override def parents: List[Type] = supertype.parents
    override def decls: Scope = supertype.decls
    override def baseType(clazz: Symbol): Type = supertype.baseType(clazz)
    override def baseTypeSeq: BaseTypeSeq = supertype.baseTypeSeq
    override def baseTypeSeqDepth: Int = supertype.baseTypeSeqDepth
    override def baseClasses: List[Symbol] = supertype.baseClasses
    override def isNotNull = supertype.isNotNull
  }

  case class NotNullType(override val underlying: Type) extends SubType with RewrappingTypeProxy {
    def supertype = underlying
    protected def rewrap(newtp: Type): Type = NotNullType(newtp)
    override def isNotNull: Boolean = true
    override def notNull = this
    override def deconst: Type = underlying //todo: needed?
    override def safeToString: String = underlying.toString + " with NotNull"
    override def kind = "NotNullType"
  }

  /** A base class for types that represent a single value
   *  (single-types and this-types).
   */
  abstract class SingletonType extends SubType with SimpleTypeProxy {
    def supertype = underlying
    override def isTrivial = false
    override def isStable = true
    override def isVolatile = underlying.isVolatile
    override def widen: Type = underlying.widen
    override def baseTypeSeq: BaseTypeSeq = {
      incCounter(singletonBaseTypeSeqCount)
      underlying.baseTypeSeq prepend this
    }
    override def isHigherKinded = false // singleton type classifies objects, thus must be kind *
    override def safeToString: String = prefixString + "type"
/*
    override def typeOfThis: Type = typeSymbol.typeOfThis
    override def bounds: TypeBounds = TypeBounds(this, this)
    override def prefix: Type = NoType
    override def typeArgs: List[Type] = List()
    override def typeParams: List[Symbol] = List()
*/
  }

  /** An object representing an erroneous type */
  case object ErrorType extends Type {
    // todo see whether we can do without
    override def isError: Boolean = true
    override def decls: Scope = new ErrorScope(NoSymbol)
    override def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = {
      var sym = decls lookup name
      if (sym == NoSymbol) {
        sym = NoSymbol.newErrorSymbol(name)
        decls enter sym
      }
      sym
    }
    override def baseType(clazz: Symbol): Type = this
    override def safeToString: String = "<error>"
    override def narrow: Type = this
    // override def isNullable: Boolean = true
    override def kind = "ErrorType"
  }

  /** 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 = "?"
    // override def isNullable: Boolean = true
    override def kind = "WildcardType"
  }

  case class BoundedWildcardType(override val bounds: TypeBounds) extends Type {
    override def isWildcard = true
    override def safeToString: String = "?" + bounds
    override def kind = "BoundedWildcardType"
  }

  /** An object representing a non-existing type */
  case object NoType extends Type {
    override def isTrivial: Boolean = true
    override def safeToString: String = "<notype>"
    // override def isNullable: Boolean = true
    override def kind = "NoType"
  }

  /** An object representing a non-existing prefix */
  case object NoPrefix extends Type {
    override def isTrivial: Boolean = true
    override def isStable: Boolean = true
    override def prefixString = ""
    override def safeToString: String = "<noprefix>"
    // override def isNullable: Boolean = true
    override def kind = "NoPrefixType"
  }

  /** A class for this-types of the form <sym>.this.type 
   */
  abstract case class ThisType(sym: Symbol) extends SingletonType {
    //assert(sym.isClass && !sym.isModuleClass || sym.isRoot, sym)
    override def isTrivial: Boolean = sym.isPackageClass
    override def isNotNull = true
    override def typeSymbol = sym
    override def underlying: Type = sym.typeOfThis
    override def isVolatile = false
    override def isHigherKinded = sym.isRefinementClass && underlying.isHigherKinded
    override def prefixString =
      if (settings.debug.value) sym.nameString + ".this."
      else if (sym.isAnonOrRefinementClass) "this."
      else if (sym.printWithoutPrefix) ""
      else if (sym.isModuleClass) sym.fullName + "."
      else sym.nameString + ".this."
    override def safeToString: String =
      if (sym.isRoot) "<root>"
      else if (sym.isEmptyPackageClass) "<empty>"
      else super.safeToString
    override def narrow: Type = this
    override def kind = "ThisType"
  }

  final class UniqueThisType(sym: Symbol) extends ThisType(sym) with UniqueType { }
  object ThisType extends ThisTypeExtractor {
    def apply(sym: Symbol): Type = {
      if (!phase.erasedTypes) unique(new UniqueThisType(sym))
      else if (sym.isImplClass) sym.typeOfThis
      else sym.tpe
    }
  }

  /** A class for singleton types of the form <prefix>..type.
   *  Cannot be created directly; one should always use
   *  `singleType' for creation.
   */
  abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType {
    override val isTrivial: Boolean = pre.isTrivial
    // override def isNullable = underlying.isNullable
    override def isNotNull = underlying.isNotNull
    private var underlyingCache: Type = NoType
    private var underlyingPeriod = NoPeriod
    override def underlying: Type = {
      val period = underlyingPeriod
      if (period != currentPeriod) {
        underlyingPeriod = currentPeriod
        if (!isValid(period)) {
          underlyingCache = pre.memberType(sym).resultType;
          assert(underlyingCache ne this, this)
        }
      }
      underlyingCache
    }

    // more precise conceptually, but causes cyclic errors:    (paramss exists (_ contains sym))
    override def isImmediatelyDependent = (sym ne NoSymbol) && (sym.owner.isMethod && sym.isValueParameter)

    override def isVolatile : Boolean = underlying.isVolatile && !sym.isStable
/*
    override def narrow: Type = {
      if (phase.erasedTypes) this
      else {
        val thissym = refinedType(List(this), sym.owner, EmptyScope).typeSymbol
        if (sym.owner != NoSymbol) {
          //Console.println("narrowing module " + sym + thissym.owner);
          thissym.typeOfThis = this
        }
        thissym.thisType
      }
    }
*/
    override def narrow: Type = this

    override def termSymbol = sym
    override def prefix: Type = pre
    override def prefixString: String = 
      if ((sym.isEmptyPackage || sym.isInterpreterWrapper || sym.isPredefModule || sym.isScalaPackage) && !settings.debug.value) ""
      else pre.prefixString + sym.nameString + "."
    override def kind = "SingleType"
  }

  final class UniqueSingleType(pre: Type, sym: Symbol) extends SingleType(pre, sym) with UniqueType { }
  object SingleType extends SingleTypeExtractor {
    def apply(pre: Type, sym: Symbol): Type = {
      unique(new UniqueSingleType(pre, sym))
    }
  }

  abstract case class SuperType(thistpe: Type, supertpe: Type) extends SingletonType {
    override val isTrivial: Boolean = thistpe.isTrivial && supertpe.isTrivial
    override def isNotNull = true;
    override def typeSymbol = thistpe.typeSymbol
    override def underlying = supertpe
    override def prefix: Type = supertpe.prefix
    override def prefixString = thistpe.prefixString.replaceAll("""this\.$""", "super.")
    override def narrow: Type = thistpe.narrow
    override def kind = "SuperType"
  }

  final class UniqueSuperType(thistp: Type, supertp: Type) extends SuperType(thistp, supertp) with UniqueType { }
  object SuperType extends SuperTypeExtractor {
    def apply(thistp: Type, supertp: Type): Type = {
      if (phase.erasedTypes) supertp
      else unique(new UniqueSuperType(thistp, supertp))
    }
  }

  /** A class for the bounds of abstract types and type parameters
   */
  abstract case class TypeBounds(lo: Type, hi: Type) extends SubType {
    def supertype = hi
    override val isTrivial: Boolean = lo.isTrivial && hi.isTrivial
    override def bounds: TypeBounds = this
    def containsType(that: Type) = that match {
      case TypeBounds(_, _) => that <:< this 
      case _                => lo <:< that && that <:< hi
    }
    // override def isNullable: Boolean = NullClass.tpe <:< lo;
    override def safeToString = ">: " + lo + " <: " + hi
    override def kind = "TypeBoundsType"
  }

  final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) with UniqueType { }
  object TypeBounds extends TypeBoundsExtractor {
    def empty: TypeBounds           = apply(NothingClass.tpe, AnyClass.tpe)
    def upper(hi: Type): TypeBounds = apply(NothingClass.tpe, hi)
    def lower(lo: Type): TypeBounds = apply(lo, AnyClass.tpe)
    def apply(lo: Type, hi: Type): TypeBounds = {
      unique(new UniqueTypeBounds(lo, hi)).asInstanceOf[TypeBounds]
    }
  }

  /** A common base class for intersection types and class types 
   */
  abstract class CompoundType extends Type {

    var baseTypeSeqCache: BaseTypeSeq = _
    private var baseTypeSeqPeriod = NoPeriod
    private var baseClassesCache: List[Symbol] = _
    private var baseClassesPeriod = NoPeriod

    override def baseTypeSeq: BaseTypeSeq = {
      val period = baseTypeSeqPeriod;
      if (period != currentPeriod) { // no caching in IDE
        baseTypeSeqPeriod = currentPeriod
        if (!isValidForBaseClasses(period)) {
          if (parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
            // rename type vars to fresh type params, take base type sequence of
            // resulting type, and rename back all the entries in that sequence
            var tvs = Set[TypeVar]()
            for (p <- parents)
              for (t <- p) t match {
                case tv: TypeVar => tvs += tv
                case _ =>
              }
            val varToParamMap: Map[Type, Symbol] = tvs map (tv => tv -> tv.origin.typeSymbol.cloneSymbol) toMap 
            val paramToVarMap = varToParamMap map (_.swap)
            val varToParam = new TypeMap {
              def apply(tp: Type) = varToParamMap get tp match {
                case Some(sym) => sym.tpe
                case _ => mapOver(tp)
              }
            }
            val paramToVar = new TypeMap {
              def apply(tp: Type) = tp match {
                case TypeRef(_, tsym, _) if paramToVarMap.isDefinedAt(tsym) => paramToVarMap(tsym)
                case _ => mapOver(tp)
              }
            }
            val bts = copyRefinedType(this.asInstanceOf[RefinedType], parents map varToParam, varToParam mapOver decls).baseTypeSeq
            baseTypeSeqCache = bts lateMap paramToVar
          } else {
            incCounter(compoundBaseTypeSeqCount)
            baseTypeSeqCache = undetBaseTypeSeq
            baseTypeSeqCache = if (typeSymbol.isRefinementClass)
              memo(compoundBaseTypeSeq(this))(_.baseTypeSeq updateHead typeSymbol.tpe)
            else
              compoundBaseTypeSeq(this)
            // [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
            // when compiling with 
            // scalac scala.collection.IterableViewLike.scala scala.collection.IterableLike.scala
            // I have not yet figured out precisely why this is the case.
            // My current assumption is that taking memos forces baseTypeSeqs to be computed
            // at stale types (i.e. the underlying typeSymbol has already another type).
            // I do not yet see precisely why this would cause a problem, but it looks
            // fishy in any case.
          }
        }
        //Console.println("baseTypeSeq(" + typeSymbol + ") = " + baseTypeSeqCache.toList);//DEBUG
      }
      if (baseTypeSeqCache eq undetBaseTypeSeq)
        throw new TypeError("illegal cyclic inheritance involving " + typeSymbol)
      baseTypeSeqCache
    }

    override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth

    override def baseClasses: List[Symbol] = {
      def computeBaseClasses: List[Symbol] =
        if (parents.isEmpty) List(typeSymbol)
        else {
          //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG
          // optimized, since this seems to be performance critical
          val superclazz = parents.head
          var mixins = parents.tail
          val sbcs = superclazz.baseClasses
          var bcs = sbcs
          def isNew(clazz: Symbol): Boolean = (
            superclazz.baseTypeIndex(clazz) < 0 &&
            { var p = bcs;
              while ((p ne sbcs) && (p.head != clazz)) p = p.tail;
              p eq sbcs
            }
          );
          while (!mixins.isEmpty) {
            def addMixinBaseClasses(mbcs: List[Symbol]): List[Symbol] =
              if (mbcs.isEmpty) bcs
              else if (isNew(mbcs.head)) mbcs.head :: addMixinBaseClasses(mbcs.tail)
              else addMixinBaseClasses(mbcs.tail);
            bcs = addMixinBaseClasses(mixins.head.baseClasses)
            mixins = mixins.tail
          }
          typeSymbol :: bcs
         }
      val period = baseClassesPeriod
      if (period != currentPeriod) {
        baseClassesPeriod = currentPeriod
        if (!isValidForBaseClasses(period)) {
          baseClassesCache = null
          baseClassesCache = memo(computeBaseClasses)(typeSymbol :: _.baseClasses.tail)
        }
      }
      if (baseClassesCache eq null)
        throw new TypeError("illegal cyclic reference involving " + typeSymbol)
      baseClassesCache
    }

    /** The slightly less idiomatic use of Options is due to 
     *  performance considerations. A version using for comprehensions
     *  might be too slow (this is deemed a hotspot of the type checker).
     *  
     *  See with Martin before changing this method.
     */
    def memo[A](op1: => A)(op2: Type => A): A = {
      def updateCache(): A = {
        intersectionWitness(parents) = new WeakReference(this)
        op1
      }
      
      intersectionWitness get parents match {
        case Some(ref) =>
          ref.get match {
            case Some(w) => if (w eq this) op1 else op2(w)
            case None => updateCache()
          }
        case None => updateCache() 
      }
     
    }
 
    override def baseType(sym: Symbol): Type = {
      val index = baseTypeIndex(sym)
      if (index >= 0) baseTypeSeq(index) else NoType
    }

    override def narrow: Type = typeSymbol.thisType
    override def isNotNull: Boolean = parents exists (_.isNotNull)
    
    override def isStructuralRefinement: Boolean =
      typeSymbol.isAnonOrRefinementClass &&
        (decls.toList exists { entry => !entry.isConstructor && entry.allOverriddenSymbols.isEmpty })

    // override def isNullable: Boolean =
    // parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);

    override def safeToString: String =
      parents.mkString(" with ") +
      (if (settings.debug.value || parents.isEmpty || (decls.elems ne null))
        decls.mkString("{", "; ", "}") else "")
  }

  /** A class representing intersection types with refinements of the form
   *    `<parents_0> with ... with  { 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.nonEmpty && 
      (parents forall (_.isHigherKinded)) &&
      !phase.erasedTypes    // @MO to AM: please check this class!
    )

    override def typeParams = 
      if (isHigherKinded) parents.head.typeParams
      else super.typeParams

    //@M may result in an invalid type (references to higher-order args become dangling )
    override def typeConstructor = 
      copyRefinedType(this, parents map (_.typeConstructor), decls)
    
    private def dummyArgs = typeParams map (_.typeConstructor)

    /* MO to AM: This is probably not correct
     * If they are several higher-kinded parents with different bounds we need
     * to take the intersection of their bounds
     */
    override def normalize = {
      if (isHigherKinded) {
        typeFun(
          typeParams,
          RefinedType(
            parents map {
              case TypeRef(pre, sym, List()) => TypeRef(pre, sym, dummyArgs)
              case p => p
            },
            decls,
            typeSymbol))
      }
      else super.normalize
    }

    /** A refined type P1 with ... with Pn { decls } is volatile if
     *  one of the parent types Pi is an abstract type, and
     *  either i > 1, or decls or a following parent Pj, j > 1, contributes
     *  an abstract member.
     *  A type contributes an abstract member if it has an abstract member which
     *  is also a member of the whole refined type. A scope `decls' contributes
     *  an abstract member if it has an abstract definition which is also
     *  a member of the whole type.
     */
    override def isVolatile = {
      def isVisible(m: Symbol) = 
        this.nonPrivateMember(m.name).alternatives contains m
      def contributesAbstractMembers(p: Type) = 
        p.deferredMembers exists isVisible

      ((parents exists (_.isVolatile)) 
       ||
       (parents dropWhile (! _.typeSymbol.isAbstractType) match {
         case ps @ (_ :: ps1) => 
           (ps ne parents) ||
           (ps1 exists contributesAbstractMembers) ||
           (decls.iterator exists (m => m.isDeferred && isVisible(m)))
         case _ =>
           false
       }))
    }

    override def kind = "RefinedType"
  }

  final class RefinedType0(parents: List[Type], decls: Scope, clazz: Symbol) extends RefinedType(parents, decls) {
    override def typeSymbol = clazz
  }
  object RefinedType extends RefinedTypeExtractor {
    def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType =
      new RefinedType0(parents, decls, clazz)
  }

  /** A class representing a class info
   */
  case class ClassInfoType(
    override val parents: List[Type],
    override val decls: Scope,
    override val typeSymbol: Symbol) extends CompoundType 
  {
    
    /** refs indices */
    private final val NonExpansive = 0
    private final val Expansive = 1

    /** initialization states */
    private final val UnInitialized = 0
    private final val Initializing = 1
    private final val Initialized = 2

    private type RefMap = Map[Symbol, immutable.Set[Symbol]]

    /** All type parameters reachable from given type parameter
     *  by a path which contains at least one expansive reference.
     *  @See Kennedy, Pierce: On Decidability of Nominal Subtyping with Variance
     */
    def expansiveRefs(tparam: Symbol) = {
      if (state == UnInitialized) {
        computeRefs()
        while (state != Initialized) propagate()
      }
      getRefs(Expansive, tparam)
    }

    /* The rest of this class is auxiliary code for `expansiveRefs'
     */

    /** The type parameters which are referenced type parameters of this class.
     *  Two entries: refs(0): Non-expansive references
     *               refs(1): Expansive references
     */
    private var refs: Array[RefMap] = _

    /** The initialization state of the class: UnInialized --> Initializing --> Initialized
     */
    private var state = UnInitialized

    /** Get references for given type parameter
     *  @param  which in {NonExpansive, Expansive}
     *  @param  from  The type parameter from which references originate.
     */
    private def getRefs(which: Int, from: Symbol): Set[Symbol] = refs(which) get from match {
      case Some(set) => set
      case none => Set()
    }

    /** Augment existing refs map with reference <pre>from -> to
* @param which <- {NonExpansive, Expansive} */ private def addRef(which: Int, from: Symbol, to: Symbol) { refs(which) = refs(which) + (from -> (getRefs(which, from) + to)) } /** Augment existing refs map with references <pre>from -> sym, for * all elements <pre>sym of set `to'. * @param which <- {NonExpansive, Expansive} */ private def addRefs(which: Int, from: Symbol, to: Set[Symbol]) { refs(which) = refs(which) + (from -> (getRefs(which, from) ++ to)) } /** The ClassInfoType which belongs to the class containing given type parameter */ private def classInfo(tparam: Symbol): ClassInfoType = tparam.owner.info.resultType match { case ci: ClassInfoType => ci case _ => classInfo(ObjectClass) // something's wrong; fall back to safe value // (this can happen only for erroneous programs). } /** Compute initial (one-step) references and set state to `Initializing'. */ private def computeRefs() { refs = Array(Map(), Map()) for (tparam <- typeSymbol.typeParams) { val enterRefs = new TypeMap { def apply(tp: Type): Type = { tp match { case TypeRef(_, sym, args) => for ((tparam1, arg) <- sym.info.typeParams zip args) if (arg contains tparam) { addRef(NonExpansive, tparam, tparam1) if (arg.typeSymbol != tparam) addRef(Expansive, tparam, tparam1) } case _ => } mapOver(tp) } } for (p <- parents) enterRefs(p) } state = Initializing } /** Propagate to form transitive closure. * Set state to Initialized if no change resulted from propagation. * @return true iff there as a change in last iteration */ private def propagate(): Boolean = { if (state == UnInitialized) computeRefs() //Console.println("Propagate "+symbol+", initial expansive = "+refs(Expansive)+", nonexpansive = "+refs(NonExpansive))//DEBUG val lastRefs = Array(refs(0), refs(1)) state = Initialized var change = false for ((from, targets) <- refs(NonExpansive).iterator) for (target <- targets) { var thatInfo = classInfo(target) if (thatInfo.state != Initialized) change = change | thatInfo.propagate() addRefs(NonExpansive, from, thatInfo.getRefs(NonExpansive, target)) addRefs(Expansive, from, thatInfo.getRefs(Expansive, target)) } for ((from, targets) <- refs(Expansive).iterator) for (target <- targets) { var thatInfo = classInfo(target) if (thatInfo.state != Initialized) change = change | thatInfo.propagate() addRefs(Expansive, from, thatInfo.getRefs(NonExpansive, target)) } change = change || refs(0) != lastRefs(0) || refs(1) != lastRefs(1) if (change) state = Initializing //else Console.println("Propagate "+symbol+", final expansive = "+refs(Expansive)+", nonexpansive = "+refs(NonExpansive))//DEBUG change } // override def isNullable: Boolean = // symbol == AnyClass || // symbol != NothingClass && (symbol isSubClass ObjectClass) && !(symbol isSubClass NonNullClass); // override def isNonNull: Boolean = symbol == NonNullClass || super.isNonNull; override def kind = "ClassInfoType" } object ClassInfoType extends ClassInfoTypeExtractor class PackageClassInfoType(decls: Scope, clazz: Symbol) extends ClassInfoType(List(), decls, clazz) /** A class representing a constant type. * * @param value ... */ abstract case class ConstantType(value: Constant) extends SingletonType { override def underlying: Type = value.tpe assert(underlying.typeSymbol != UnitClass) override def isTrivial: Boolean = true override def isNotNull = value.value != null override def deconst: Type = underlying override def safeToString: String = underlying.toString + "(" + value.escapedStringValue + ")" // override def isNullable: Boolean = value.value eq null // override def isNonNull: Boolean = value.value ne null override def kind = "ConstantType" } final class UniqueConstantType(value: Constant) extends ConstantType(value) with UniqueType { /** Save the type of 'value'. For Java enums, it depends on finding the linked class, * which might not be found after 'flatten'. */ private lazy val _tpe: Type = value.tpe override def underlying: Type = _tpe } object ConstantType extends ConstantTypeExtractor { def apply(value: Constant): ConstantType = { unique(new UniqueConstantType(value)).asInstanceOf[ConstantType] } } private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] /** A class for named types of the form * `<prefix>.[args]' * Cannot be created directly; one should always use `typeRef' * for creation. (@M: Otherwise hashing breaks) * * @M: a higher-kinded type is represented as a TypeRef with sym.info.typeParams.nonEmpty, but args.isEmpty * @param pre ... * @param sym ... * @param args ... */ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { // assert(!sym.isAbstractType || pre.isStable || pre.isError) // assert(!pre.isInstanceOf[ClassInfoType], this) // assert(!(sym hasFlag (PARAM | EXISTENTIAL)) || pre == NoPrefix, this) // assert(args.isEmpty || !sym.info.typeParams.isEmpty, this) // assert(args.isEmpty || ((sym ne AnyClass) && (sym ne NothingClass)) private var parentsCache: List[Type] = _ private var parentsPeriod = NoPeriod private var baseTypeSeqCache: BaseTypeSeq = _ private var baseTypeSeqPeriod = NoPeriod private var symInfoCache: Type = _ private var memberInfoCache: Type = _ private var thisInfoCache: Type = _ private var relativeInfoCache: Type = _ private var normalized: Type = null override def isStable: Boolean = { sym == NothingClass || sym == SingletonClass || sym.isAliasType && normalize.isStable || sym.isAbstractType && (bounds.hi.typeSymbol isSubClass SingletonClass) } override def isVolatile: Boolean = { sym.isAliasType && normalize.isVolatile || sym.isAbstractType && { // need to be careful not to fall into an infinite recursion here // because volatile checking is done before all cycles are detected. // the case to avoid is an abstract type directly or // indirectly upper-bounded by itself. See #2918 try { volatileRecursions += 1 if (volatileRecursions < LogVolatileThreshold) bounds.hi.isVolatile else if (pendingVolatiles(sym)) true // we can return true here, because a cycle will be detected // here afterwards and an error will result anyway. else try { pendingVolatiles += sym bounds.hi.isVolatile } finally { pendingVolatiles -= sym } } finally { volatileRecursions -= 1 } } } override lazy val isTrivial: Boolean = !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial) override def isNotNull = sym.isModuleClass || sym == NothingClass || isValueClass(sym) || super.isNotNull // @M: propagate actual type params (args) to `tp', by replacing formal type parameters with actual ones // if tp is higher kinded, the "actual" type arguments are types that simply reference the corresponding type parameters (unbound type variables) def transform(tp: Type): Type = { val res = tp.asSeenFrom(pre, sym.owner) if (sym.typeParams.isEmpty || (args exists (_.isError)) || isRaw(sym, args)/*#2266/2305*/) res else res.instantiateTypeParams(sym.typeParams, typeArgsOrDummies) } //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs) def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies) def thisInfo: Type = if (sym.isAliasType) normalize else if (!sym.isNonClassType) sym.info else { val symInfo = sym.info if (thisInfoCache == null || (symInfo ne symInfoCache)) { symInfoCache = symInfo thisInfoCache = transformInfo(symInfo) } thisInfoCache } def relativeInfo: Type = if (!sym.isNonClassType) pre.memberInfo(sym) else { val memberInfo = pre.memberInfo(sym) if (relativeInfoCache == null || (memberInfo ne memberInfoCache)) { memberInfoCache = memberInfo relativeInfoCache = transformInfo(memberInfo) } relativeInfoCache } override def typeSymbol = if (sym.isAliasType) normalize.typeSymbol else sym override def termSymbol = if (sym.isAliasType) normalize.termSymbol else super.termSymbol override def typeSymbolDirect = sym override def termSymbolDirect = super.termSymbol /* @MAT whenever you see `tp.typeSymbol.isXXXX' and then act on tp based on that predicate, you're on thin ice, as `typeSymbol' (and `prefix') automatically normalize, but the other inspectors don't. In other words, even if `tp.normalize.sym.isXXX' is true, `tp.sym.isXXX' may be false (if sym were a public method to access the non-normalized typeSymbol)... In retrospect, I think `tp.typeSymbol.isXXX' or (worse) `tp.typeSymbol==XXX' should be replaced by `val tp = tp0.asXXX'. A type's typeSymbol should never be inspected directly. */ override def bounds: TypeBounds = if (sym.isAbstractType) thisInfo.bounds // transform(thisInfo.bounds).asInstanceOf[TypeBounds] // ??? seems to be doing asSeenFrom twice else super.bounds override def parents: List[Type] = { val period = parentsPeriod if (period != currentPeriod) { parentsPeriod = currentPeriod if (!isValidForBaseClasses(period)) { parentsCache = thisInfo.parents map transform } else if (parentsCache == null) { // seems this can happen if things are currupted enough, see #2641 parentsCache = List(AnyClass.tpe) } } parentsCache } override def typeOfThis = transform(sym.typeOfThis) /* override def narrow = if (sym.isModuleClass) transform(sym.thisType) else if (sym.isAliasType) normalize.narrow else super.narrow */ override def narrow = if (sym.isModuleClass) singleType(pre, sym.sourceModule) else if (sym.isAliasType) normalize.narrow else super.narrow override def prefix: Type = if (sym.isAliasType) normalize.prefix else pre override def typeArgs: List[Type] = args private def typeArgsOrDummies = if (!isHigherKinded) args else dummyArgs // def hasFishyArgs = args == dummyArgs // @MAT was typeSymbol.unsafeTypeParams, but typeSymbol normalizes now private def typeParamsDirect = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams // placeholders derived from type params 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) // 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) copyTypeRef(this, pre, sym, dummyArgs).subst(formals, actuals) else ErrorType } else super.instantiateTypeParams(formals, actuals) /** @pre: sym.info.typeParams.length == typeArgs.length */ @inline private def betaReduce: Type = { // 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) @inline private def etaExpand: Type = { val tpars = sym.info.typeParams // must go through sym.info for typeParams to initialise symbol typeFunAnon(tpars, copyTypeRef(this, pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? } override def dealias: Type = if (sym.isAliasType && sameLength(sym.info.typeParams, args)) { betaReduce.dealias } else this private def normalize0: Type = if (pre eq WildcardType) WildcardType // arises when argument-dependent types are approximated (see def depoly in implicits) else if (isHigherKinded) etaExpand // eta-expand, subtyping relies on eta-expansion of higher-kinded types else if (sym.isAliasType && sameLength(sym.info.typeParams, args)) betaReduce.normalize // beta-reduce, but don't do partial application -- cycles have been checked in typeRef else if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers else { if(sym.isAliasType) ErrorType //println("!!error: "+(pre, sym, sym.info, sym.info.typeParams, args)) else super.normalize } // TODO: test case that is compiled in a specific order and in different runs override def normalize: Type = { if (phase.erasedTypes) normalize0 else { if (normalized == null) normalized = normalize0 normalized } } override def decls: Scope = { sym.info match { case TypeRef(_, sym1, _) => assert(sym1 != sym, this) // @MAT was != typeSymbol case _ => } thisInfo.decls } override def baseType(clazz: Symbol): Type = if (sym == clazz) this else if (sym.isClass) transform(sym.info.baseType(clazz)) else try { basetypeRecursions += 1 if (basetypeRecursions < LogPendingBaseTypesThreshold) relativeInfo.baseType(clazz) else if (pendingBaseTypes contains this) if (clazz == AnyClass) clazz.tpe else NoType else try { pendingBaseTypes += this relativeInfo.baseType(clazz) } finally { pendingBaseTypes -= this } } finally { basetypeRecursions -= 1 } override def baseTypeSeq: BaseTypeSeq = { val period = baseTypeSeqPeriod if (period != currentPeriod) { baseTypeSeqPeriod = currentPeriod if (!isValidForBaseClasses(period)) { incCounter(typerefBaseTypeSeqCount) baseTypeSeqCache = undetBaseTypeSeq baseTypeSeqCache = if (sym.isAbstractType) transform(bounds.hi).baseTypeSeq prepend this else sym.info.baseTypeSeq map transform } } if (baseTypeSeqCache == undetBaseTypeSeq) throw new TypeError("illegal cyclic inheritance involving " + sym) baseTypeSeqCache } override def baseTypeSeqDepth: Int = baseTypeSeq.maxDepth override def baseClasses: List[Symbol] = thisInfo.baseClasses // override def isNullable: Boolean = sym.info.isNullable override def safeToString: String = { if (!settings.debug.value) { this match { case TypeRef(_, RepeatedParamClass, arg :: _) => return arg + "*" case TypeRef(_, ByNameParamClass, arg :: _) => return "=> " + arg case _ => if (isFunctionType(this)) { val targs = normalize.typeArgs // Aesthetics: printing Function1 as T => R rather than (T) => R val paramlist = targs.init match { case Nil => "()" case x :: Nil => "" + x case xs => xs.mkString("(", ", ", ")") } return paramlist + " => " + targs.last } else if (isTupleTypeOrSubtype(this)) return normalize.typeArgs.mkString("(", ", ", if (hasLength(normalize.typeArgs, 1)) ",)" else ")") else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic)) { val normed = normalize; if (normed ne this) return normed.toString } } } val monopart = if (!settings.debug.value && (shorthands contains sym.fullName) && (sym.ownerChain forall (_.isClass))) // ensure that symbol is not a local copy with a name coincidence sym.name.toString else pre.prefixString + sym.nameString var str = monopart + (if (args.isEmpty) "" else args.mkString("[", ",", "]")) if (sym.isPackageClass) packagePrefix + str else if (sym.isModuleClass) objectPrefix + str else if (sym.isAnonymousClass && sym.isInitialized && !settings.debug.value && !phase.erasedTypes) thisInfo.parents.mkString(" with ") + { if (sym.isStructuralRefinement) ((decls.toList filter { entry => !entry.isConstructor && entry.allOverriddenSymbols.isEmpty && !entry.isPrivate }) map { entry => entry.defString }).mkString("{", "; ", "}") else "" } else if (sym.isRefinementClass && sym.isInitialized) thisInfo.toString else str } override def prefixString = "" + ( if (settings.debug.value) super.prefixString else if (sym.printWithoutPrefix) "" else if (sym.isPackageClass) sym.fullName + "." else if (isStable && nme.isSingletonName(sym.name)) nme.dropSingletonName(sym.name) + "." else super.prefixString ) override def kind = "TypeRef" } final class UniqueTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends TypeRef(pre, sym, args) with UniqueType { } object TypeRef extends TypeRefExtractor { def apply(pre: Type, sym: Symbol, args: List[Type]): Type = { unique(new UniqueTypeRef(pre, sym, args)) } } /** A class representing a method type with parameters. * Note that a parameterless method is represented by a NullaryMethodType: * * def m(): Int MethodType(Nil, Int) * def m: Int NullaryMethodType(Int) */ case class MethodType(override val params: List[Symbol], override val resultType: Type) extends Type { override def isTrivial: Boolean = isTrivial0 private lazy val isTrivial0 = resultType.isTrivial && params.forall{p => p.tpe.isTrivial && ( !settings.YdepMethTpes.value || !(params.exists(_.tpe.contains(p)) || resultType.contains(p))) } def isImplicit = params.nonEmpty && params.head.isImplicit def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized? //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG override def paramSectionCount: Int = resultType.paramSectionCount + 1 override def paramss: List[List[Symbol]] = params :: resultType.paramss override def paramTypes = params map (_.tpe) override def boundSyms = immutable.Set[Symbol](params ++ resultType.boundSyms: _*) // AM to TR: #dropNonContraintAnnotations // this is needed for plugins to work correctly, only TypeConstraint annotations are supposed to be carried over // TODO: this should probably be handled in a more structured way in adapt -- remove this map in resultType and watch the continuations tests fail object dropNonContraintAnnotations extends TypeMap { override val dropNonConstraintAnnotations = true def apply(x: Type) = mapOver(x) } override def resultType(actuals: List[Type]) = if (isTrivial) dropNonContraintAnnotations(resultType) else { if (sameLength(actuals, params)) { val idm = new InstantiateDependentMap(params, actuals) val res = idm(resultType) // println("resultTypeDep "+(params, actuals, resultType, idm.existentialsNeeded, "\n= "+ res)) existentialAbstraction(idm.existentialsNeeded, res) } else { // Thread.dumpStack() // println("resultType "+(params, actuals, resultType)) if (phase.erasedTypes) resultType else existentialAbstraction(params, resultType) } } // implicit args can only be depended on in result type: TODO this may be generalised so that the only constraint is dependencies are acyclic def approximate: MethodType = MethodType(params, resultApprox) override def finalResultType: Type = resultType.finalResultType override def safeToString = paramString(this) + resultType override def cloneInfo(owner: Symbol) = { val vparams = cloneSymbols(params, owner) copyMethodType(this, vparams, resultType.substSym(params, vparams).cloneInfo(owner)) } override def atOwner(owner: Symbol) = if ((params exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType)) cloneInfo(owner) else this override def kind = "MethodType" } object MethodType extends MethodTypeExtractor class JavaMethodType(ps: List[Symbol], rt: Type) extends MethodType(ps, rt) { override def isJava = true } case class NullaryMethodType(override val resultType: Type) extends Type { // AM to TR: #dropNonContraintAnnotations // change isTrivial to the commented version and watch continuations-run/t3225.scala fail // isTrivial implies asSeenFrom is bypassed, since it's supposed to be the identity map // it's not really the identity due to dropNonContraintAnnotations override def isTrivial: Boolean = false //resultType.isTrivial -- `false` to make continuations plugin work (so that asSeenFromMap drops non-constrain annotations even when type doesn't change otherwise) override def prefix: Type = resultType.prefix override def narrow: Type = resultType.narrow override def finalResultType: Type = resultType.finalResultType override def termSymbol: Symbol = resultType.termSymbol override def typeSymbol: Symbol = resultType.typeSymbol override def parents: List[Type] = resultType.parents override def decls: Scope = resultType.decls override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth override def baseClasses: List[Symbol] = resultType.baseClasses override def baseType(clazz: Symbol): Type = resultType.baseType(clazz) override def boundSyms = resultType.boundSyms override def isVolatile = resultType.isVolatile override def safeToString: String = "=> "+ resultType override def kind = "NullaryMethodType" } object NullaryMethodType extends NullaryMethodTypeExtractor /** A type function or the type of a polymorphic value (and thus of kind *). * * Before the introduction of NullaryMethodType, a polymorphic nullary method (e.g, def isInstanceOf[T]: Boolean) * used to be typed as PolyType(tps, restpe), and a monomorphic one as PolyType(Nil, restpe) * This is now: PolyType(tps, NullaryMethodType(restpe)) and NullaryMethodType(restpe) * by symmetry to MethodTypes: PolyType(tps, MethodType(params, restpe)) and MethodType(params, restpe) * * Thus, a PolyType(tps, TypeRef(...)) unambiguously indicates a type function (which results from eta-expanding a type constructor alias). * Similarly, PolyType(tps, ClassInfoType(...)) is a type constructor. * * A polytype is of kind * iff its resultType is a (nullary) method type. */ case class PolyType(override val typeParams: List[Symbol], override val resultType: Type) extends Type { //assert(!(typeParams contains NoSymbol), this) assert(typeParams nonEmpty, this) // used to be a marker for nullary method type, illegal now (see @NullaryMethodType) override def paramSectionCount: Int = resultType.paramSectionCount override def paramss: List[List[Symbol]] = resultType.paramss override def params: List[Symbol] = resultType.params override def paramTypes: List[Type] = resultType.paramTypes override def parents: List[Type] = resultType.parents override def decls: Scope = resultType.decls override def termSymbol: Symbol = resultType.termSymbol override def typeSymbol: Symbol = resultType.typeSymbol override def boundSyms = immutable.Set[Symbol](typeParams ++ resultType.boundSyms: _*) override def prefix: Type = resultType.prefix override def baseTypeSeq: BaseTypeSeq = resultType.baseTypeSeq override def baseTypeSeqDepth: Int = resultType.baseTypeSeqDepth override def baseClasses: List[Symbol] = resultType.baseClasses override def baseType(clazz: Symbol): Type = resultType.baseType(clazz) override def narrow: Type = resultType.narrow override def isVolatile = resultType.isVolatile override def finalResultType: Type = resultType.finalResultType /** @M: typeDefSig wraps a TypeBounds in a PolyType * to represent a higher-kinded type parameter * wrap lo&hi in polytypes to bind variables */ override def bounds: TypeBounds = TypeBounds(typeFun(typeParams, resultType.bounds.lo), typeFun(typeParams, resultType.bounds.hi)) override def isHigherKinded = !typeParams.isEmpty override def safeToString = typeParamsString(this) + resultType override def cloneInfo(owner: Symbol) = { val tparams = cloneSymbols(typeParams, owner) PolyType(tparams, resultType.substSym(typeParams, tparams).cloneInfo(owner)) } override def atOwner(owner: Symbol) = if ((typeParams exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType)) cloneInfo(owner) else this override def kind = "PolyType" } object PolyType extends PolyTypeExtractor case class ExistentialType(quantified: List[Symbol], override val underlying: Type) extends RewrappingTypeProxy { override protected def rewrap(newtp: Type) = existentialAbstraction(quantified, newtp) override def isTrivial = false override def isStable: Boolean = false override def bounds = TypeBounds(maybeRewrap(underlying.bounds.lo), maybeRewrap(underlying.bounds.hi)) override def parents = underlying.parents map maybeRewrap override def boundSyms = quantified.toSet override def prefix = maybeRewrap(underlying.prefix) override def typeArgs = underlying.typeArgs map maybeRewrap override def params = underlying.params mapConserve { param => val tpe1 = rewrap(param.tpe) if (tpe1 eq param.tpe) param else param.cloneSymbol.setInfo(tpe1) } override def paramTypes = underlying.paramTypes map maybeRewrap override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = { // maybeRewrap(underlying.instantiateTypeParams(formals, actuals)) val quantified1 = new SubstTypeMap(formals, actuals) mapOver quantified val underlying1 = underlying.instantiateTypeParams(formals, actuals) if ((quantified1 eq quantified) && (underlying1 eq underlying)) this else existentialAbstraction(quantified1, underlying1.substSym(quantified, quantified1)) } override def baseType(clazz: Symbol) = maybeRewrap(underlying.baseType(clazz)) override def baseTypeSeq = underlying.baseTypeSeq map maybeRewrap override def isHigherKinded = false override def skolemizeExistential(owner: Symbol, origin: AnyRef) = { def mkSkolem(tparam: Symbol): Symbol = { val skolem = new TypeSkolem( if (owner == NoSymbol) tparam.owner else owner, tparam.pos, tparam.name.toTypeName, origin) skolem.setInfo(tparam.info.cloneInfo(skolem)) .setFlag(tparam.flags | EXISTENTIAL) .resetFlag(PARAM) } val skolems = quantified map mkSkolem for (skolem <- skolems) skolem setInfo skolem.info.substSym(quantified, skolems) underlying.substSym(quantified, skolems) } private def wildcardArgsString(available: Set[Symbol], args: List[Type]): List[String] = args match { case TypeRef(_, sym, _) :: args1 if (available contains sym) => ("_"+sym.infoString(sym.info)) :: wildcardArgsString(available - sym, args1) case arg :: args1 if !(quantified exists (arg contains _)) => arg.toString :: wildcardArgsString(available, args1) case _ => List() } 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 underlying match { case MethodType(_, _) | NullaryMethodType(_) | PolyType(_, _) => ustr = "("+ustr+")" case _ => } val str = ustr+(quantified map (_.existentialToString) mkString(" forSome { ", "; ", " }")) if (settings.explaintypes.value) "("+str+")" else str } override def cloneInfo(owner: Symbol) = { val tparams = cloneSymbols(quantified, owner) ExistentialType(tparams, underlying.substSym(quantified, tparams)) } override def atOwner(owner: Symbol) = if (quantified exists (_.owner != owner)) cloneInfo(owner) else this override def kind = "ExistentialType" def withTypeVars(op: Type => Boolean): Boolean = withTypeVars(op, AnyDepth) def withTypeVars(op: Type => Boolean, depth: Int): Boolean = { val quantifiedFresh = cloneSymbols(quantified) val tvars = quantifiedFresh map (tparam => TypeVar(tparam)) val underlying1 = underlying.instantiateTypeParams(quantified, tvars) // fuse subst quantified -> quantifiedFresh -> tvars op(underlying1) && { solve(tvars, quantifiedFresh, quantifiedFresh map (x => 0), false, depth) && isWithinBounds(NoPrefix, NoSymbol, quantifiedFresh, tvars map (_.constr.inst)) } } } object ExistentialType extends ExistentialTypeExtractor /** A class containing the alternatives and type prefix of an overloaded symbol. * Not used after phase `typer'. */ case class OverloadedType(pre: Type, alternatives: List[Symbol]) extends Type { override def prefix: Type = pre override def safeToString = (alternatives map pre.memberType).mkString("", " <and> ", "") override def kind = "OverloadedType" } /** A class remembering a type instantiation for some a set of overloaded * polymorphic symbols. * Not used after phase `typer'. */ case class AntiPolyType(pre: Type, targs: List[Type]) extends Type { override def safeToString = pre.toString + targs.mkString("(with type arguments ", ",", ")"); override def memberType(sym: Symbol) = appliedType(pre.memberType(sym), targs) // override def memberType(sym: Symbol) = pre.memberType(sym) match { // case PolyType(tparams, restp) => // restp.subst(tparams, targs) // /* I don't think this is needed, as existential types close only over value types // case ExistentialType(tparams, qtpe) => // existentialAbstraction(tparams, qtpe.memberType(sym)) // */ // case ErrorType => // ErrorType // } override def kind = "AntiPolyType" } //private var tidCount = 0 //DEBUG //@M // a TypeVar used to be a case class with only an origin and a constr // then, constr became mutable (to support UndoLog, I guess), // but pattern-matching returned the original constr0 (a bug) // now, pattern-matching returns the most recent constr object TypeVar { // encapsulate suspension so we can automatically link the suspension of cloned // typevars to their original if this turns out to be necessary /* def Suspension = new Suspension class Suspension { private val suspended = mutable.HashSet[TypeVar]() def suspend(tv: TypeVar): Unit = { tv.suspended = true suspended += tv } def resumeAll(): Unit = { for (tv <- suspended) { tv.suspended = false } suspended.clear() } } */ def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List()) // TODO why not initialise TypeConstraint with bounds of tparam? // @PP: I tried that, didn't work out so well for me. def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams) def apply(origin: Type, constr: TypeConstraint, args: List[Type], params: List[Symbol]) = new TypeVar(origin, constr, args, params) } /** A class representing a type variable * Not used after phase `typer'. * A higher-kinded type variable has type arguments (a list of Type's) and type parameters (list of Symbols) * A TypeVar whose list of args is non-empty can only be instantiated by a higher-kinded type that can be applied to these args * a typevar is much like a typeref, except it has special logic for type equality/subtyping */ class TypeVar(val origin: Type, val constr0: TypeConstraint, override val typeArgs: List[Type], override val params: List[Symbol]) extends Type { // params are needed to keep track of variance (see mapOverArgs in SubstMap) assert(typeArgs.isEmpty || sameLength(typeArgs, params)) // var tid = { tidCount += 1; tidCount } //DEBUG /** The constraint associated with the variable */ var constr = constr0 def instValid = constr.instValid /** The variable's skolemization level */ val level = skolemizationLevel /** * two occurrences of a higher-kinded typevar, e.g. ?CC[Int] and ?CC[String], correspond to * *two instances* of TypeVar that share the *same* TypeConstraint * constr for ?CC only tracks type constructors anyway, so when ?CC[Int] <:< List[Int] and ?CC[String] <:< Iterable[String] * ?CC's hibounds contains List and Iterable */ def applyArgs(newArgs: List[Type]): TypeVar = if (newArgs.isEmpty) this // SubstMap relies on this (though this check is redundant when called from appliedType...) else TypeVar(origin, constr, newArgs, params) // @M TODO: interaction with undoLog?? // newArgs.length may differ from args.length (could've been empty before) // example: when making new typevars, you start out with C[A], then you replace C by ?C, which should yield ?C[A], then A by ?A, ?C[?A] // we need to track a TypeVar's arguments, and map over them (see TypeMap::mapOver) // TypeVars get applied to different arguments over time (in asSeenFrom) // -- see pos/tcpoly_infer_implicit_tuplewrapper.scala // thus: make new TypeVar's for every application of a TV to args, // inference may generate several TypeVar's for a single type parameter that must be inferred, // only one of them is in the set of tvars that need to be solved, but // they share the same TypeConstraint instance // <region name="constraint mutators + undoLog"> // invariant: before mutating constr, save old state in undoLog (undoLog is used to reset constraints to avoid piling up unrelated ones) def setInst(tp: Type) { // assert(!(tp containsTp this), this) undoLog record this constr.inst = tp } def addLoBound(tp: Type, isNumericBound: Boolean = false) { assert(tp != this) // implies there is a cycle somewhere (?) //println("addLoBound: "+(safeToString, debugString(tp))) //DEBUG undoLog record this constr.addLoBound(tp, isNumericBound) } def addHiBound(tp: Type, isNumericBound: Boolean = false) { // assert(tp != this) //println("addHiBound: "+(safeToString, debugString(tp))) //DEBUG undoLog record this constr.addHiBound(tp, isNumericBound) } // </region> // ignore subtyping&equality checks while true -- see findMember private[Types] var suspended = false /** Called when a TypeVar is involved in a subtyping check. Result is whether * this TypeVar could plausibly be a [super/sub]type of argument `tp` and if so, * tracks tp as a [lower/upper] bound of this TypeVar. * * if (isLowerBound) this typevar could be a subtype, track tp as a lower bound * if (!isLowerBound) this typevar could be a supertype, track tp as an upper bound * * If isNumericBound is true, the subtype check is performed with weak_<:< instead of <:<. */ def registerBound(tp: Type, isLowerBound: Boolean, isNumericBound: Boolean = false): Boolean = { // println("regBound: "+(safeToString, debugString(tp), isLowerBound)) //@MDEBUG if (isLowerBound) assert(tp != this) def checkSubtypeLower(tp1: Type, tp2: Type) = if (isNumericBound) tp1 weak_<:< tp2 else tp1 <:< tp2 // swaps the arguments if it's an upper bound def checkSubtype(tp1: Type, tp2: Type) = if (isLowerBound) checkSubtypeLower(tp1, tp2) else checkSubtypeLower(tp2, tp1) def addBound(tp: Type) = { if (isLowerBound) addLoBound(tp, isNumericBound) else addHiBound(tp, isNumericBound) // println("addedBound: "+(this, tp)) // @MDEBUG true } /** Simple case: type arguments can be ignored, because either this typevar has * no type parameters, or we are comparing to Any/Nothing. * * The latter condition is needed because HK unification is limited to constraints of the shape * TC1[T1,..., TN] <: TC2[T'1,...,T'N] * which would preclude the following important constraints: * Nothing <: ?TC[?T] * ?TC[?T] <: Any */ def unifySimple = (params.isEmpty || tp.typeSymbol == NothingClass || tp.typeSymbol == AnyClass) && addBound(tp) /** Full case: involving a check of the form * TC1[T1,..., TN] <: TC2[T'1,...,T'N] * Checks subtyping of higher-order type vars, and uses variances as defined in the * type parameter we're trying to infer (the result will be sanity-checked later) */ def unifyFull(tp: Type) = sameLength(typeArgs, tp.typeArgs) && { // this is a higher-kinded type var with same arity as tp // side effect: adds the type constructor itself as a bound addBound(tp.typeConstructor) if (isLowerBound) isSubArgs(tp.typeArgs, typeArgs, params) else isSubArgs(typeArgs, tp.typeArgs, params) } /** TODO: need positive/negative test cases demonstrating this is correct. */ def unifyParents = if (isLowerBound) tp.parents exists unifyFull else tp.parents forall unifyFull // TODO: fancier unification, maybe rewrite constraint as follows? // val sym = constr.hiBounds map {_.typeSymbol} find { _.typeParams.length == typeArgs.length} // this <: tp.baseType(sym) if (suspended) checkSubtype(tp, origin) else if (constr.instValid) checkSubtype(tp, constr.inst) // type var is already set else isRelatable(tp) && { // gradually let go of some type precision in hopes of finding a type that has the same shape as the type variable // okay, this just screams "CLEAN ME UP" -- I think we could use tp.widen instead of tp straight from the get-go in registerBound, since we don't infer singleton types anyway (but maybe that'll change?) unifySimple || unifyFull(tp) || unifyFull(tp.dealias) || unifyFull(tp.widen) || unifyFull(tp.widen.dealias) || unifyParents } } def registerTypeEquality(tp: Type, typeVarLHS: Boolean): Boolean = { //println("regTypeEq: "+(safeToString, debugString(tp), typeVarLHS)) //@MDEBUG def checkIsSameType(tp: Type) = if(typeVarLHS) constr.inst =:= tp else tp =:= constr.inst if (suspended) tp =:= origin else if (constr.instValid) checkIsSameType(tp) else isRelatable(tp) && { val newInst = wildcardToTypeVarMap(tp) if (constr.isWithinBounds(newInst)) { setInst(tp) true } else false } } /** * ?A.T =:= tp is rewritten as the constraint ?A <: {type T = tp} * * TODO: make these constraints count (incorporate them into implicit search in applyImplicitArgs) * (T corresponds to @param sym) */ def registerTypeSelection(sym: Symbol, tp: Type): Boolean = { val bound = refinedType(List(WildcardType), NoSymbol) val bsym = bound.typeSymbol.newAliasType(NoPosition, sym.name.toTypeName) bsym setInfo tp bound.decls enter bsym registerBound(bound, false) } /** Can this variable be related in a constraint to type `tp'? * This is not the case if `tp' contains type skolems whose * skolemization level is higher than the level of this variable. */ def isRelatable(tp: Type): Boolean = !tp.exists { t => t.typeSymbol match { case ts: TypeSkolem => ts.level > level case _ => false } } override val isHigherKinded = typeArgs.isEmpty && params.nonEmpty override def normalize: Type = if (constr.instValid) constr.inst // get here when checking higher-order subtyping of the typevar by itself // TODO: check whether this ever happens? else if (isHigherKinded) typeFun(params, applyArgs(params map (_.typeConstructor))) else super.normalize override def typeSymbol = origin.typeSymbol override def isStable = origin.isStable override def isVolatile = origin.isVolatile private def levelString = if (settings.explaintypes.value) level else "" override def safeToString = constr.inst match { case null => "<null " + origin + ">" case NoType => "?" + levelString + origin + typeArgsString(this) case x => "" + x } override def kind = "TypeVar" def cloneInternal = { // cloning a suspended type variable when it's suspended will cause the clone // to never be resumed with the current implementation assert(!suspended) TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? } } /** A type carrying some annotations. Created by the typechecker * when eliminating ``Annotated'' trees (see typedAnnotated). * * @param annotations the list of annotations on the type * @param underlying the type without the annotation * @param selfsym a "self" symbol with type <code>underlying; * only available if -Yself-in-annots is turned on. Can be NoSymbol * if it is not used. */ case class AnnotatedType(override val annotations: List[AnnotationInfo], override val underlying: Type, override val selfsym: Symbol) extends RewrappingTypeProxy { assert(!annotations.isEmpty) override protected def rewrap(tp: Type) = AnnotatedType(annotations, tp, selfsym) override def isTrivial: Boolean = isTrivial0 private lazy val isTrivial0 = underlying.isTrivial && (annotations forall (_.isTrivial)) override def safeToString: String = { val attString = if (annotations.isEmpty) "" else annotations.mkString(" @", " @", "") underlying + attString } /** Add a number of annotations to this type */ override def withAnnotations(annots: List[AnnotationInfo]): Type = copy(annots:::this.annotations) /** Remove any annotations from this type */ override def withoutAnnotations = underlying.withoutAnnotations /** Set the self symbol */ override def withSelfsym(sym: Symbol) = AnnotatedType(annotations, underlying, sym) /** Drop the annotations on the bounds, unless but the low and high * bounds are exactly tp. */ override def bounds: TypeBounds = underlying.bounds match { case TypeBounds(_: this.type, _: this.type) => TypeBounds(this, this) case oftp => oftp } // ** Replace formal type parameter symbols with actual type arguments. * / override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = { val annotations1 = annotations.map(info => AnnotationInfo(info.atp.instantiateTypeParams( formals, actuals), info.args, info.assocs).setPos(info.pos)) val underlying1 = underlying.instantiateTypeParams(formals, actuals) if ((annotations1 eq annotations) && (underlying1 eq underlying)) this else AnnotatedType(annotations1, underlying1, selfsym) } /** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp * is precisely tp itself. */ override def baseTypeSeq: BaseTypeSeq = { val oftp = underlying.baseTypeSeq if ((oftp.length == 1) && (oftp(0) eq underlying)) baseTypeSingletonSeq(this) else oftp } override def kind = "AnnotatedType" } object AnnotatedType extends AnnotatedTypeExtractor /** A class representing types with a name. When an application uses * named arguments, the named argument types for calling isApplicable * are represented as NamedType. */ case class NamedType(name: Name, tp: Type) extends Type { override def safeToString: String = name.toString +": "+ tp } /** A class representing an as-yet unevaluated type. */ abstract class LazyType extends Type with AbsLazyType { override def kind = "LazyType" } // Creators --------------------------------------------------------------- /** Rebind symbol `sym' to an overriding member in type `pre'. */ private def rebind(pre: Type, sym: Symbol): Symbol = { val owner = sym.owner if (owner.isClass && owner != pre.typeSymbol && !sym.isEffectivelyFinal && !sym.isClass) { //Console.println("rebind "+pre+" "+sym)//DEBUG val rebind = pre.nonPrivateMember(sym.name).suchThat(sym => sym.isType || sym.isStable) if (rebind == NoSymbol) sym else { // Console.println("rebound "+pre+" "+sym+" to "+rebind)//DEBUG rebind } } else sym } /** Convert a `super' prefix to a this-type if `sym' * is abstract or final. */ private def removeSuper(tp: Type, sym: Symbol): Type = tp match { case SuperType(thistp, _) => if (sym.isEffectivelyFinal || sym.isDeferred) thistp else tp case _ => tp } /** The canonical creator for single-types */ def singleType(pre: Type, sym: Symbol): Type = { if (phase.erasedTypes) sym.tpe.resultType else if (sym.isRootPackage) ThisType(RootClass) else { var sym1 = rebind(pre, sym) val pre1 = removeSuper(pre, sym1) if (pre1 ne pre) sym1 = rebind(pre1, sym1) SingleType(pre1, sym1) } } /** the canonical creator for a refined type with a given scope */ def refinedType(parents: List[Type], owner: Symbol, decls: Scope, pos: Position): Type = { if (phase.erasedTypes) if (parents.isEmpty) ObjectClass.tpe else parents.head else { val clazz = owner.newRefinementClass(NoPosition) val result = RefinedType(parents, decls, clazz) clazz.setInfo(result) result } } /** The canonical creator for a refined type with an initially empty scope. * * @param parents ... * @param owner ... * @return ... */ def refinedType(parents: List[Type], owner: Symbol): Type = refinedType(parents, owner, new Scope, owner.pos) def copyRefinedType(original: RefinedType, parents: List[Type], decls: Scope) = if ((parents eq original.parents) && (decls eq original.decls)) original else { val owner = if (original.typeSymbol == NoSymbol) NoSymbol else original.typeSymbol.owner val result = refinedType(parents, owner) val syms1 = decls.toList for (sym <- syms1) result.decls.enter(sym.cloneSymbol(result.typeSymbol)) val syms2 = result.decls.toList val resultThis = result.typeSymbol.thisType for (sym <- syms2) sym.setInfo(sym.info.substThis(original.typeSymbol, resultThis).substSym(syms1, syms2)) result } /** The canonical creator for typerefs * todo: see how we can clean this up a bit */ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = { // type alias selections are rebound in TypeMap ("coevolved", actually -- see #3731) // e.g., when type parameters that are referenced by the alias are instantiated in // the prefix. See pos/depmet_rebind_typealias. def rebindTR(pre: Type, sym: Symbol) = if (sym.isAbstractType) rebind(pre, sym) else sym val sym1 = rebindTR(pre, sym) // we require that object is initialized, thus info.typeParams instead of typeParams. if (sym1.isAliasType && sameLength(sym1.info.typeParams, args)) { if (sym1.lockOK) TypeRef(pre, sym1, args) // don't expand type alias (cycles checked by lockOK) else throw new TypeError("illegal cyclic reference involving " + sym1) } else { val pre1 = removeSuper(pre, sym1) if (pre1 ne pre) typeRef(pre1, rebindTR(pre1, sym1), args) else pre match { case _: CompoundType if sym1.isClass => // sharpen prefix so that it is maximal and still contains the class. pre.parents.reverse dropWhile (_.member(sym1.name) != sym1) match { case Nil => TypeRef(pre, sym1, args) case parent :: _ => typeRef(parent, sym1, args) } case _ => TypeRef(pre, sym1, args) } } } def copyTypeRef(tp: Type, pre: Type, sym: Symbol, args: List[Type]): Type = tp match { case TypeRef(pre0, sym0, args0) => if ((pre == pre0) && (sym.name == sym0.name)) { val sym1 = sym // we require that object is initialized, thus info.typeParams instead of typeParams. if (sym1.isAliasType && sameLength(sym1.info.typeParams, args)) { if (sym1.lockOK) TypeRef(pre, sym1, args) // don't expand type alias (cycles checked by lockOK) else throw new TypeError("illegal cyclic reference involving " + sym1) } else { TypeRef(pre, sym1, args) } } else typeRef(pre, sym, args) } /** The canonical creator for implicit method types */ def JavaMethodType(params: List[Symbol], resultType: Type): JavaMethodType = new JavaMethodType(params, resultType) // don't unique this! /** Create a new MethodType of the same class as tp, i.e. keep JavaMethodType */ def copyMethodType(tp: Type, params: List[Symbol], restpe: Type): Type = tp match { case _: JavaMethodType => JavaMethodType(params, restpe) case _ => MethodType(params, restpe) } /** A creator for intersection type where intersections of a single type are * replaced by the type itself, and repeated parent classes are merged. */ def intersectionType(tps: List[Type], owner: Symbol): Type = tps match { case List(tp) => tp case _ => refinedType(tps, owner) /* def merge(tps: List[Type]): List[Type] = tps match { case tp :: tps1 => val tps1a = tps1 filter (_.typeSymbol.==(tp.typeSymbol)) val tps1b = tps1 filter (_.typeSymbol.!=(tp.typeSymbol)) mergePrefixAndArgs(tps1a, -1) match { case Some(tp1) => tp1 :: merge(tps1b) case None => throw new MalformedType( "malformed type: "+refinedType(tps, owner)+" has repeated parent class "+ tp.typeSymbol+" with incompatible prefixes or type arguments") } case _ => tps } refinedType(merge(tps), owner) */ } /** A creator for intersection type where intersections of a single type are * replaced by the type itself. */ def intersectionType(tps: List[Type]): Type = tps match { case List(tp) => tp case _ => refinedType(tps, commonOwner(tps)) } /** A creator for type applications */ def appliedType(tycon: Type, args: List[Type]): Type = if (args.isEmpty) tycon //@M! `if (args.isEmpty) tycon' is crucial (otherwise we create new types in phases after typer and then they don't get adapted (??)) else tycon match { case TypeRef(pre, sym @ (NothingClass|AnyClass), _) => copyTypeRef(tycon, pre, sym, Nil) //@M drop type args to Any/Nothing case TypeRef(pre, sym, _) => copyTypeRef(tycon, pre, sym, args) case PolyType(tparams, restpe) => restpe.instantiateTypeParams(tparams, args) case ExistentialType(tparams, restpe) => ExistentialType(tparams, appliedType(restpe, args)) case st: SingletonType => appliedType(st.widen, args) // @M TODO: what to do? see bug1 case RefinedType(parents, decls) => RefinedType(parents map (appliedType(_, args)), decls) // MO to AM: please check case TypeBounds(lo, hi) => TypeBounds(appliedType(lo, args), appliedType(hi, args)) case tv@TypeVar(_, _) => tv.applyArgs(args) case AnnotatedType(annots, underlying, self) => AnnotatedType(annots, appliedType(underlying, args), self) case ErrorType => tycon case WildcardType => tycon // needed for neg/t0226 case _ => abort(debugString(tycon)) } /** 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) * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty) */ def polyType(tparams: List[Symbol], tpe: Type): Type = if (tparams nonEmpty) typeFun(tparams, tpe) else tpe // it's okay to be forgiving here /** A creator for anonymous type functions, where the symbol for the type function still needs to be created * * TODO: * type params of anonymous type functions, which currently can only arise from normalising type aliases, are owned by the type alias of which they are the eta-expansion * higher-order subtyping expects eta-expansion of type constructors that arise from a class; here, the type params are owned by that class, but is that the right thing to do? */ def typeFunAnon(tps: List[Symbol], body: Type): Type = typeFun(tps, body) /** A creator for a type functions, assuming the type parameters tps already have the right owner */ def typeFun(tps: List[Symbol], body: Type): Type = PolyType(tps, body) /** A creator for existential types. This generates: * * tpe1 where { tparams } * * where `tpe1' is the result of extrapolating `tpe' wrt to `tparams'. Extrapolating means * that type variables in `tparams' occurring in covariant positions are replaced by upper bounds, * (minus any SingletonClass markers), * type variables in `tparams' occurring in contravariant positions are replaced by upper bounds, * provided the resulting type is legal wrt to stability, and does not contain any * type variable in `tparams'. * The abstraction drops all type parameters that are not directly or indirectly * referenced by type `tpe1'. * If there are no remaining type parameters, simply returns result type `tpe'. */ def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type = if (tparams.isEmpty) tpe0 else { var occurCount = emptySymCount ++ (tparams map (_ -> 0)) val tpe = deAlias(tpe0) def countOccs(tp: Type) = for (t <- tp) { t match { case TypeRef(_, sym, _) => occurCount get sym match { case Some(count) => occurCount += (sym -> (count + 1)) case none => } case _ => } } countOccs(tpe) for (tparam <- tparams) countOccs(tparam.info) val extrapolate = new TypeMap { variance = 1 def apply(tp: Type): Type = { val tp1 = mapOver(tp) tp1 match { case TypeRef(pre, sym, args) if (variance != 0) && (occurCount isDefinedAt sym) => val repl = if (variance == 1) dropSingletonType(tp1.bounds.hi) else tp1.bounds.lo //println("eliminate "+sym+"/"+repl+"/"+occurCount(sym)+"/"+(tparams exists (repl.contains)))//DEBUG if (repl.typeSymbol != NothingClass && repl.typeSymbol != NullClass && occurCount(sym) == 1 && !(tparams exists (repl.contains))) repl else tp1 case _ => tp1 } } override def mapOver(tp: Type): Type = tp match { case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { val pre1 = this(pre) if ((pre1 eq pre) || !pre1.isStable) tp else singleType(pre1, sym) } case _ => super.mapOver(tp) } override def mapOver(tree: Tree) = tree match { case tree:Ident if tree.tpe.isStable => // Do not discard the types of existential ident's. // The symbol of the Ident itself cannot be listed // in the existential's parameters, so the // resulting existential type would be ill-formed. Some(tree) case _ => super.mapOver(tree) } } val tpe1 = extrapolate(tpe) var tparams0 = tparams var tparams1 = tparams0 filter tpe1.contains while (tparams1 != tparams0) { tparams0 = tparams1 tparams1 = tparams filter { p => tparams1 exists { p1 => p1 == p || (p1.info contains p) } } } if (tparams1.isEmpty) tpe1 else tpe1 match { case ExistentialType(tparams2, tpe2) => ExistentialType(tparams1 ::: tparams2, tpe2) case _ => ExistentialType(tparams1, tpe1) } } /** Remove any occurrences of type aliases from this type */ object deAlias extends TypeMap { def apply(tp: Type): Type = mapOver { tp match { case TypeRef(pre, sym, args) if sym.isAliasType => tp.normalize case _ => tp } } } /** Remove any occurrence of type <singleton> from this type and its parents */ object dropSingletonType extends TypeMap { def apply(tp: Type): Type = { tp match { case TypeRef(_, SingletonClass, _) => AnyClass.tpe case tp1 @ RefinedType(parents, decls) => var parents1 = parents filter (_.typeSymbol != SingletonClass) if (parents1.isEmpty) parents1 = List(AnyClass.tpe) if (parents1.tail.isEmpty && decls.isEmpty) mapOver(parents1.head) else mapOver(copyRefinedType(tp1, parents1, decls)) case tp1 => mapOver(tp1) } } } // Hash consing -------------------------------------------------------------- private val initialUniquesCapacity = 4096 private var uniques: util.HashSet[Type] = _ private var uniqueRunId = NoRunId private def unique[T <: Type](tp: T): T = { incCounter(rawTypeCount) if (uniqueRunId != currentRunId) { uniques = util.HashSet[Type]("uniques", initialUniquesCapacity) uniqueRunId = currentRunId } (uniques findEntryOrUpdate tp).asInstanceOf[T] } // Helper Classes --------------------------------------------------------- /** @PP: Unable to see why these apparently constant types should need vals * in every TypeConstraint, I lifted them out. */ private lazy val numericLoBound = IntClass.tpe private lazy val numericHiBound = intersectionType(List(ByteClass.tpe, CharClass.tpe), ScalaPackageClass) /** A class expressing upper and lower bounds constraints of type variables, * as well as their instantiations. */ class TypeConstraint(lo0: List[Type], hi0: List[Type], numlo0: Type, numhi0: Type) { def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType) def this() = this(List(), List()) private var lobounds = lo0 private var hibounds = hi0 private var numlo = numlo0 private var numhi = numhi0 def loBounds: List[Type] = if (numlo == NoType) lobounds else numlo :: lobounds def hiBounds: List[Type] = if (numhi == NoType) hibounds else numhi :: hibounds def addLoBound(tp: Type, isNumericBound: Boolean = false) { if (isNumericBound && isNumericValueType(tp)) { if (numlo == NoType || isNumericSubType(numlo, tp)) numlo = tp else if (!isNumericSubType(tp, numlo)) numlo = numericLoBound } else lobounds ::= tp } def addHiBound(tp: Type, isNumericBound: Boolean = false) { if (isNumericBound && isNumericValueType(tp)) { if (numhi == NoType || isNumericSubType(tp, numhi)) numhi = tp else if (!isNumericSubType(numhi, tp)) numhi = numericHiBound } else hibounds ::= tp } def isWithinBounds(tp: Type): Boolean = lobounds.forall(_ <:< tp) && hibounds.forall(tp <:< _) && (numlo == NoType || (numlo weak_<:< tp)) && (numhi == NoType || (tp weak_<:< numhi)) var inst: Type = NoType // @M reduce visibility? def instValid = (inst ne null) && (inst ne NoType) def cloneInternal = { val tc = new TypeConstraint(lobounds, hibounds, numlo, numhi) tc.inst = inst tc } override def toString = (loBounds map (_.safeToString)).mkString("[ _>:(", ",", ") ") + (hiBounds map (_.safeToString)).mkString("| _<:(", ",", ") ] _= ") + inst.safeToString } /** A prototype for mapping a function over all possible types */ abstract class TypeMap extends Function1[Type, Type] { // deferred inherited: def apply(tp: Type): Type /** The variance relative to start. If you want variances to be significant, set * variance = 1 * at the top of the typemap. */ var variance = 0 /** Should this map drop annotations that are not * type-constraint annotations? */ val dropNonConstraintAnnotations = false /** Check whether two lists have elements that are eq-equal */ 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, // since sym's info was probably updated by the TypeMap to yield a new symbol sym1 with transformed info // @returns sym1 protected def coevolveSym(pre: Type, pre1: Type, sym: Symbol): Symbol = if((pre ne pre1) && sym.isAliasType) // only need to rebind type aliases here, as typeRef already handles abstract types (they are allowed to be rebound more liberally) (pre, pre1) match { case (RefinedType(_, decls), RefinedType(_, decls1)) => // don't look at parents -- it would be an error to override alias types anyway //val sym1 = decls1.lookup(sym.name) // assert(decls.lookupAll(sym.name).toList.length == 1) // assert(decls1.lookupAll(sym.name).toList.length == 1) // assert(sym1.isAliasType) // println("coevolved "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) // sym1 case _ => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? // val sym1 = pre1.nonPrivateMember(sym.name).suchThat(sym => sym.isAliasType) // println("??coevolve "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) sym } else sym /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { case TypeRef(pre, sym, args) => val pre1 = this(pre) //val args1 = args mapConserve this(_) val args1 = if (args.isEmpty) args else { val tparams = sym.typeParams if (tparams.isEmpty) args else mapOverArgs(args, tparams) } if ((pre1 eq pre) && (args1 eq args)) tp else copyTypeRef(tp, pre1, coevolveSym(pre, pre1, sym), args1) case ThisType(_) => tp case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { val pre1 = this(pre) if (pre1 eq pre) tp else singleType(pre1, sym) } case MethodType(params, result) => variance = -variance val params1 = mapOver(params) variance = -variance val result1 = this(result) if ((params1 eq params) && (result1 eq result)) tp // for new dependent types: result1.substSym(params, params1)? else copyMethodType(tp, params1, result1.substSym(params, params1)) case PolyType(tparams, result) => variance = -variance val tparams1 = mapOver(tparams) variance = -variance var result1 = this(result) if ((tparams1 eq tparams) && (result1 eq result)) tp else PolyType(tparams1, result1.substSym(tparams, tparams1)) case NullaryMethodType(result) => val result1 = this(result) if (result1 eq result) tp else NullaryMethodType(result1) case ConstantType(_) => tp case SuperType(thistp, supertp) => val thistp1 = this(thistp) val supertp1 = this(supertp) if ((thistp1 eq thistp) && (supertp1 eq supertp)) tp else SuperType(thistp1, supertp1) case TypeBounds(lo, hi) => variance = -variance val lo1 = this(lo) variance = -variance val hi1 = this(hi) if ((lo1 eq lo) && (hi1 eq hi)) tp else TypeBounds(lo1, hi1) case BoundedWildcardType(bounds) => val bounds1 = this(bounds) if (bounds1 eq bounds) tp else BoundedWildcardType(bounds1.asInstanceOf[TypeBounds]) case rtp @ RefinedType(parents, decls) => val parents1 = parents mapConserve (this) val decls1 = mapOver(decls) //if ((parents1 eq parents) && (decls1 eq decls)) tp //else refinementOfClass(tp.typeSymbol, parents1, decls1) copyRefinedType(rtp, parents1, decls1) case ExistentialType(tparams, result) => val tparams1 = mapOver(tparams) var result1 = this(result) if ((tparams1 eq tparams) && (result1 eq result)) tp else ExistentialType(tparams1, result1.substSym(tparams, tparams1)) case OverloadedType(pre, alts) => val pre1 = if (pre.isInstanceOf[ClassInfoType]) pre else this(pre) if (pre1 eq pre) tp else OverloadedType(pre1, alts) case AntiPolyType(pre, args) => val pre1 = this(pre) val args1 = args mapConserve (this) if ((pre1 eq pre) && (args1 eq args)) tp else AntiPolyType(pre1, args1) case tv@TypeVar(_, constr) => if (constr.instValid) this(constr.inst) else tv.applyArgs(mapOverArgs(tv.typeArgs, tv.params)) //@M !args.isEmpty implies !typeParams.isEmpty case NotNullType(tp) => val tp1 = this(tp) if (tp1 eq tp) tp else NotNullType(tp1) case AnnotatedType(annots, atp, selfsym) => val annots1 = mapOverAnnotations(annots) val atp1 = this(atp) if ((annots1 eq annots) && (atp1 eq atp)) tp else if (annots1.isEmpty) atp1 else AnnotatedType(annots1, atp1, selfsym) /* case ErrorType => tp case WildcardType => tp case NoType => tp case NoPrefix => tp */ case _ => tp // throw new Error("mapOver inapplicable for " + tp); } def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = map2Conserve(args, tparams) { (arg, tparam) => val v = variance if (tparam.isContravariant) variance = -variance else if (!tparam.isCovariant) variance = 0 val arg1 = this(arg) variance = v arg1 } /** Map this function over given scope */ def mapOver(scope: Scope): Scope = { val elems = scope.toList val elems1 = mapOver(elems) if (elems1 eq elems) scope else new Scope(elems1) } /** Map this function over given list of symbols */ def mapOver(origSyms: List[Symbol]): List[Symbol] = { val change = origSyms exists { sym => val v = variance if (sym.isAliasType) variance = 0 val result = this(sym.info) variance = v result ne sym.info } if (!change) origSyms // fast path in case nothing changes due to map else { // map is not the identity --> do cloning properly val clonedSyms = origSyms map (_.cloneSymbol) val clonedInfos = clonedSyms map (_.info.substSym(origSyms, clonedSyms)) val transformedInfos = clonedInfos mapConserve (this) (clonedSyms, transformedInfos).zipped map (_ setInfo _) clonedSyms } } def mapOverAnnotations(annots: List[AnnotationInfo]) : List[AnnotationInfo] = { val newAnnots = annots.flatMap(mapOver(_)) if (allEq(newAnnots, annots)) annots else newAnnots } def mapOver(annot: AnnotationInfo): Option[AnnotationInfo] = { val AnnotationInfo(atp, args, assocs) = annot if (dropNonConstraintAnnotations && !(atp.typeSymbol isNonBottomSubClass TypeConstraintClass)) return None val atp1 = mapOver(atp) val args1 = mapOverAnnotArgs(args) // there is no need to rewrite assocs, as they are constants if ((args eq args1) && (atp eq atp1)) Some(annot) else if (sameLength(args1, args)) Some(AnnotationInfo(atp1, args1, assocs).setPos(annot.pos)) else None } /** Map over a set of annotation arguments. If any * of the arguments cannot be mapped, then return Nil. */ def mapOverAnnotArgs(args: List[Tree]): List[Tree] = { val args1 = args flatMap (x => mapOver(x)) if (!sameLength(args1, args)) Nil else if (allEq(args, args1)) args else args1 } def mapOver(tree: Tree): Option[Tree] = Some(mapOver(tree, ()=>return None)) /** Map a tree that is part of an annotation argument. * If the tree cannot be mapped, then invoke giveup(). * The default is to transform the tree with * TypeMapTransformer. */ def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = (new TypeMapTransformer).transform(tree) /** This transformer leaves the tree alone except to remap * its types. */ class TypeMapTransformer extends Transformer { override def transform(tree: Tree) = { val tree1 = super.transform(tree) val tpe1 = TypeMap.this(tree1.tpe) if ((tree eq tree1) && (tree.tpe eq tpe1)) tree else tree1.shallowDuplicate.setType(tpe1) } } } /** A type map that always returns the input type unchanged */ object IdentityTypeMap extends TypeMap { def apply(tp: Type) = tp } abstract class TypeTraverser extends TypeMap { def traverse(tp: Type): Unit def apply(tp: Type): Type = { traverse(tp); tp } } abstract class TypeCollector[T](initial: T) extends TypeTraverser { var result: T = _ def collect(tp: Type) = { result = initial traverse(tp) result } } private val emptySymMap = immutable.Map[Symbol, Symbol]() private val emptySymCount = immutable.Map[Symbol, Int]() def typeParamsToExistentials(clazz: Symbol, tparams: List[Symbol]): List[Symbol] = { val eparams = for ((tparam, i) <- tparams.zipWithIndex) yield { clazz.newExistential(clazz.pos, newTypeName("?"+i)).setInfo(tparam.info.bounds) } for (tparam <- eparams) tparam setInfo tparam.info.substSym(tparams, eparams) eparams } // note: it's important to write the two tests in this order, // as only typeParams forces the classfile to be read. See #400 private def isRawIfWithoutArgs(sym: Symbol) = sym.isClass && sym.typeParams.nonEmpty && sym.isJavaDefined def isRaw(sym: Symbol, args: List[Type]) = !phase.erasedTypes && isRawIfWithoutArgs(sym) && args.isEmpty /** Is type tp a ``raw type''? */ def isRawType(tp: Type) = tp match { case TypeRef(_, sym, args) => isRaw(sym, args) case _ => false } /** The raw to existential map converts a ``raw type'' to an existential type. * It is necessary because we might have read a raw type of a * parameterized Java class from a class file. At the time we read the type * the corresponding class file might still not be read, so we do not * know what the type parameters of the type are. Therefore * the conversion of raw types to existential types might not have taken place * in ClassFileparser.sigToType (where it is usually done) */ object rawToExistential extends TypeMap { private var expanded = immutable.Set[Symbol]() private var generated = immutable.Set[Type]() def apply(tp: Type): Type = tp match { case TypeRef(pre, sym, List()) if isRawIfWithoutArgs(sym) => if (expanded contains sym) AnyRefClass.tpe else try { expanded += sym val eparams = mapOver(typeParamsToExistentials(sym, sym.typeParams)) existentialAbstraction(eparams, typeRef(apply(pre), sym, eparams map (_.tpe))) } finally { expanded -= sym } case ExistentialType(_, _) if !(generated contains tp) => // to avoid infinite expansions. todo: not sure whether this is needed val result = mapOver(tp) generated += result result case _ => mapOver(tp) } } def singletonBounds(hi: Type) = { TypeBounds.upper(intersectionType(List(hi, SingletonClass.tpe))) } /** A map to compute the asSeenFrom method */ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap { override val dropNonConstraintAnnotations = true var capturedParams: List[Symbol] = List() override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object annotationArgRewriter extends TypeMapTransformer { /** Rewrite `This` trees in annotation argument trees */ def rewriteThis(tree: Tree): Tree = tree match { case This(_) if (tree.symbol isNonBottomSubClass clazz) && (pre.widen.typeSymbol isNonBottomSubClass tree.symbol) => if (pre.isStable) { // XXX why is this in this method? pull it out and guard the call `annotationArgRewriter.transform(tree)`? val termSym = pre.typeSymbol.owner.newValue( pre.typeSymbol.pos, pre.typeSymbol.name.toTermName).setInfo(pre) // what symbol should really be used? mkAttributedQualifier(pre, termSym) } else giveup() case tree => tree } override def transform(tree: Tree): Tree = { val tree1 = rewriteThis(super.transform(tree)) tree1 } } annotationArgRewriter.transform(tree) } var capturedPre = emptySymMap def stabilize(pre: Type, clazz: Symbol): Type = capturedPre.getOrElse(clazz, { val qvar = clazz freshExistential ".type" setInfo singletonBounds(pre) capturedPre += (clazz -> qvar) capturedParams = qvar :: capturedParams qvar }).tpe /** Return pre.baseType(clazz), or if that's NoType and clazz is a refinement, pre itself. * See bug397.scala for an example where the second alternative is needed. * The problem is that when forming the base type sequence of an abstract type, * any refinements in the base type list might be regenerated, and thus acquire * new class symbols. However, since refinements always have non-interesting prefixes * it looks OK to me to just take the prefix directly. */ def base(pre: Type, clazz: Symbol) = { val b = pre.baseType(clazz) if (b == NoType && clazz.isRefinementClass) pre else b } def apply(tp: Type): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else tp match { case ThisType(sym) => def toPrefix(pre: Type, clazz: Symbol): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else if ((sym isNonBottomSubClass clazz) && (pre.widen.typeSymbol isNonBottomSubClass sym)) { val pre1 = pre match { case SuperType(thistp, _) => thistp case _ => pre } if (!(pre1.isStable || pre1.typeSymbol.isPackageClass || pre1.typeSymbol.isModuleClass && pre1.typeSymbol.isStatic)) { stabilize(pre1, sym) } else { pre1 } } else { toPrefix(base(pre, clazz).prefix, clazz.owner); } toPrefix(pre, clazz) case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path else { val pre1 = this(pre) if (pre1 eq pre) tp else if (pre1.isStable) singleType(pre1, sym) else pre1.memberType(sym).resultType //todo: this should be rolled into existential abstraction } // AM: Martin, is this description accurate? // walk the owner chain of `clazz` (the original argument to asSeenFrom) until we find the type param's owner (while rewriting pre as we crawl up the owner chain) // once we're at the owner, extract the information that pre encodes about the type param, // by minimally subsuming pre to the type instance of the class that owns the type param, // the type we're looking for is the type instance's type argument at the position corresponding to the type parameter // optimisation: skip this type parameter if it's not owned by a class, as those params are not influenced by the prefix through which they are seen // (concretely: type params of anonymous type functions, which currently can only arise from normalising type aliases, are owned by the type alias of which they are the eta-expansion) // (skolems also aren't affected: they are ruled out by the isTypeParameter check) case TypeRef(prefix, sym, args) if (sym.isTypeParameter && sym.owner.isClass) => def toInstance(pre: Type, clazz: Symbol): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) mapOver(tp) //@M! see test pos/tcpoly_return_overriding.scala why mapOver is necessary else { def throwError = abort("" + tp + sym.locationString + " cannot be instantiated from " + pre.widen) def instParam(ps: List[Symbol], as: List[Type]): Type = if (ps.isEmpty) throwError else if (sym eq ps.head) // @M! don't just replace the whole thing, might be followed by type application appliedType(as.head, args mapConserve (this)) // @M: was as.head else instParam(ps.tail, as.tail); val symclazz = sym.owner if (symclazz == clazz && !pre.isInstanceOf[TypeVar] && (pre.widen.typeSymbol isNonBottomSubClass symclazz)) { // have to deconst because it may be a Class[T]. pre.baseType(symclazz).deconst match { case TypeRef(_, basesym, baseargs) => //Console.println("instantiating " + sym + " from " + basesym + " with " + basesym.typeParams + " and " + baseargs+", pre = "+pre+", symclazz = "+symclazz);//DEBUG if (sameLength(basesym.typeParams, baseargs)) { instParam(basesym.typeParams, baseargs) } else { throw new TypeError( "something is wrong (wrong class file?): "+basesym+ " with type parameters "+ basesym.typeParams.map(_.name).mkString("[",",","]")+ " gets applied to arguments "+baseargs.mkString("[",",","]")+", phase = "+phase) } case ExistentialType(tparams, qtpe) => capturedParams = capturedParams union tparams toInstance(qtpe, clazz) case _ => throwError } } else toInstance(base(pre, clazz).prefix, clazz.owner) } toInstance(pre, clazz) case _ => mapOver(tp) } } /** A base class to compute all substitutions */ abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap { val fromContains = (x: Symbol) => from.contains(x) //from.toSet <-- traversing short lists seems to be faster than allocating sets assert(sameLength(from, to), "Unsound substitution from "+ from +" to "+ to) /** Are `sym' and `sym1' the same. * Can be tuned by subclasses. */ protected def matches(sym: Symbol, sym1: Symbol): Boolean = sym eq sym1 /** Map target to type, can be tuned by subclasses */ protected def toType(fromtp: Type, tp: T): Type protected def renameBoundSyms(tp: Type): Type = tp match { case MethodType(ps, restp) => val ps1 = cloneSymbols(ps) copyMethodType(tp, ps1, renameBoundSyms(restp.substSym(ps, ps1))) case PolyType(bs, restp) => val bs1 = cloneSymbols(bs) PolyType(bs1, renameBoundSyms(restp.substSym(bs, bs1))) case ExistentialType(bs, restp) => val bs1 = cloneSymbols(bs) ExistentialType(bs1, restp.substSym(bs, bs1)) case _ => tp } def apply(tp0: Type): Type = if (from.isEmpty) tp0 else { @tailrec def subst(tp: Type, sym: Symbol, from: List[Symbol], to: List[T]): Type = if (from.isEmpty) tp // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(tp, from)) else if (matches(from.head, sym)) toType(tp, to.head) else subst(tp, sym, from.tail, to.tail) val boundSyms = tp0.boundSyms val tp1 = if (boundSyms exists fromContains) renameBoundSyms(tp0) else tp0 val tp = mapOver(tp1) tp match { // @M // 1) arguments must also be substituted (even when the "head" of the // applied type has already been substituted) // example: (subst RBound[RT] from [type RT,type RBound] to // [type RT&,type RBound&]) = RBound&[RT&] // 2) avoid loops (which occur because alpha-conversion is // not performed properly imo) // e.g. if in class Iterable[a] there is a new Iterable[(a,b)], // we must replace the a in Iterable[a] by (a,b) // (must not recurse --> loops) // 3) replacing m by List in m[Int] should yield List[Int], not just List case TypeRef(NoPrefix, sym, args) => appliedType(subst(tp, sym, from, to), args) // if args.isEmpty, appliedType is the identity case SingleType(NoPrefix, sym) => subst(tp, sym, from, to) case _ => tp } } } /** A map to implement the `substSym' method. */ class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends SubstMap(from, to) { protected def toType(fromtp: Type, sym: Symbol) = fromtp match { case TypeRef(pre, _, args) => copyTypeRef(fromtp, pre, sym, args) case SingleType(pre, _) => singleType(pre, sym) } override def apply(tp: Type): Type = if (from.isEmpty) tp else { @tailrec def subst(sym: Symbol, from: List[Symbol], to: List[Symbol]): Symbol = if (from.isEmpty) sym // else if (to.isEmpty) error("Unexpected substitution on '%s': from = %s but to == Nil".format(sym, from)) else if (matches(from.head, sym)) to.head else subst(sym, from.tail, to.tail) tp match { case TypeRef(pre, sym, args) if pre ne NoPrefix => val newSym = subst(sym, from, to) // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams)) mapOver(copyTypeRef(tp, pre, newSym, args)) // mapOver takes care of subst'ing in args case SingleType(pre, sym) if pre ne NoPrefix => mapOver(singleType(pre, subst(sym, from, to))) case _ => super.apply(tp) } } override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object trans extends TypeMapTransformer { def termMapsTo(sym: Symbol) = if (fromContains(sym)) Some(to(from.indexOf(sym))) else None override def transform(tree: Tree) = tree match { case tree@Ident(_) => termMapsTo(tree.symbol) match { case Some(tosym) => if (tosym.info.bounds.hi.typeSymbol isSubClass SingletonClass) { Ident(tosym.existentialToString) .setSymbol(tosym) .setPos(tosym.pos) .setType(dropSingletonType(tosym.info.bounds.hi)) } else { giveup() } case none => super.transform(tree) } case tree => super.transform(tree) } } trans.transform(tree) } } /** A map to implement the `subst' method. */ class SubstTypeMap(from: List[Symbol], to: List[Type]) extends SubstMap(from, to) { protected def toType(fromtp: Type, tp: Type) = tp override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { object trans extends TypeMapTransformer { override def transform(tree: Tree) = tree match { case Ident(name) if fromContains(tree.symbol) => val totpe = to(from.indexOf(tree.symbol)) if (!totpe.isStable) giveup() else Ident(name).setPos(tree.pos).setSymbol(tree.symbol).setType(totpe) case _ => super.transform(tree) } } trans.transform(tree) } } /** A map to implement the `substThis' method. */ class SubstThisMap(from: Symbol, to: Type) extends TypeMap { def apply(tp: Type): Type = tp match { case ThisType(sym) if (sym == from) => to case _ => mapOver(tp) } } class SubstSuperMap(from: Type, to: Type) extends TypeMap { def apply(tp: Type): Type = if (tp eq from) to else mapOver(tp) } class SubstWildcardMap(from: List[Symbol]) extends TypeMap { def apply(tp: Type): Type = try { tp match { case TypeRef(_, sym, _) if from contains sym => BoundedWildcardType(sym.info.bounds) case _ => mapOver(tp) } } catch { case ex: MalformedType => WildcardType } } // dependent method types object IsDependentCollector extends TypeCollector(false) { def traverse(tp: Type) { if(tp isImmediatelyDependent) result = true else if (!result) mapOver(tp) } } object ApproximateDependentMap extends TypeMap { def apply(tp: Type): Type = if(tp isImmediatelyDependent) WildcardType else mapOver(tp) } class InstantiateDependentMap(params: List[Symbol], actuals: List[Type]) extends TypeMap { private val actualsIndexed = actuals.toIndexedSeq override val dropNonConstraintAnnotations = true object ParamWithActual { def unapply(sym: Symbol): Option[Type] = { val pid = params indexOf sym if(pid != -1) Some(actualsIndexed(pid)) else None } } def apply(tp: Type): Type = mapOver(tp) match { case SingleType(NoPrefix, ParamWithActual(arg)) if arg.isStable => arg // unsound to replace args by unstable actual #3873 // (soundly) expand type alias selections on implicit arguments, see depmet_implicit_oopsla* test cases -- typically, `param.isImplicit` case tp1@TypeRef(SingleType(NoPrefix, ParamWithActual(arg)), sym, targs) => val res = typeRef(arg, sym, targs) if(res.typeSymbolDirect isAliasType) res.dealias else tp1 case tp1 => tp1 // don't return the original `tp`, which may be different from `tp1`, due to `dropNonConstraintAnnotations` } def existentialsNeeded: List[Symbol] = existSyms.filter(_ ne null).toList private val existSyms: Array[Symbol] = new Array(actualsIndexed.size) private def haveExistential(i: Int) = {assert((i >= 0) && (i <= actualsIndexed.size)); existSyms(i) ne null} /* Return the type symbol for referencing a parameter inside the existential quantifier. * (Only needed if the actual is unstable.) */ def existSymFor(actualIdx: Int) = if (haveExistential(actualIdx)) existSyms(actualIdx) else { val oldSym = params(actualIdx) val symowner = oldSym.owner val bound = singletonBounds(actualsIndexed(actualIdx)) val sym = symowner.newExistential(oldSym.pos, newTypeName(oldSym.name + ".type")) sym.setInfo(bound) sym.setFlag(oldSym.flags) existSyms(actualIdx) = sym sym } //AM propagate more info to annotations -- this seems a bit ad-hoc... (based on code by spoon) override def mapOver(arg: Tree, giveup: ()=>Nothing): Tree = { object treeTrans extends Transformer { override def transform(tree: Tree): Tree = { tree match { case RefParamAt(pid) => // TODO: this should be simplified; in the stable case, one can probably // just use an Ident to the tree.symbol. Why an existential in the non-stable case? val actual = actualsIndexed(pid) if (actual.isStable && actual.typeSymbol != NothingClass) { mkAttributedQualifier(actualsIndexed(pid), tree.symbol) } else { val sym = existSymFor(pid) (Ident(sym.name) copyAttrs tree setType typeRef(NoPrefix, sym, Nil)) } case _ => super.transform(tree) } } object RefParamAt { def unapply(tree: Tree): Option[Int] = tree match { case Ident(_) => Some(params indexOf tree.symbol) filterNot (_ == -1) case _ => None } } } treeTrans.transform(arg) } } object StripAnnotationsMap extends TypeMap { def apply(tp: Type): Type = tp match { case AnnotatedType(_, atp, _) => mapOver(atp) case tp => mapOver(tp) } } /** A map to convert every occurrence of a wildcard type to a fresh * type variable */ object wildcardToTypeVarMap extends TypeMap { def apply(tp: Type): Type = tp match { case WildcardType => TypeVar(tp, new TypeConstraint) case BoundedWildcardType(bounds) => TypeVar(tp, new TypeConstraint(List(bounds.lo), List(bounds.hi))) case _ => mapOver(tp) } } /** A map to convert every occurrence of a type variable to a wildcard type */ object typeVarToOriginMap extends TypeMap { def apply(tp: Type): Type = tp match { case TypeVar(origin, _) => origin case _ => mapOver(tp) } } /** A map to implement the `contains' method */ class ContainsCollector(sym: Symbol) extends TypeCollector(false) { def traverse(tp: Type) { if (!result) { tp.normalize match { case TypeRef(_, sym1, _) if (sym == sym1) => result = true case SingleType(_, sym1) if (sym == sym1) => result = true case _ => mapOver(tp) } } } override def mapOver(arg: Tree) = { for (t <- arg) { traverse(t.tpe) if (t.symbol == sym) result = true } Some(arg) } } /** A map to implement the `contains' method */ class ContainsTypeCollector(t: Type) extends TypeCollector(false) { def traverse(tp: Type) { if (!result) { if (tp eq t) result = true else mapOver(tp) } } override def mapOver(arg: Tree) = { for (t <- arg) { traverse(t.tpe) } Some(arg) } } /** A map to implement the `filter' method */ class FilterTypeCollector(p: Type => Boolean) extends TypeCollector(new ListBuffer[Type]) { def traverse(tp: Type) { if (p(tp)) result += tp mapOver(tp) } } class ForEachTypeTraverser(f: Type => Unit) extends TypeTraverser { def traverse(tp: Type) { f(tp) mapOver(tp) } } /** A map to implement the `filter' method */ class FindTypeCollector(p: Type => Boolean) extends TypeCollector[Option[Type]](None) { def traverse(tp: Type) { if (result.isEmpty) { if (p(tp)) result = Some(tp) mapOver(tp) } } } /** A map to implement the `contains' method */ object ErroneousCollector extends TypeCollector(false) { def traverse(tp: Type) { if (!result) { result = tp.isError mapOver(tp) } } } /** A map to compute the most deeply nested owner that contains all the symbols * of thistype or prefixless typerefs/singletype occurrences in given type. */ object commonOwnerMap extends TypeMap { var result: Symbol = _ def init() = { result = NoSymbol } def apply(tp: Type): Type = { assert(tp ne null) tp.normalize match { case ThisType(sym) => register(sym) case TypeRef(NoPrefix, sym, args) => register(sym.owner); args foreach apply case SingleType(NoPrefix, sym) => register(sym.owner) case _ => mapOver(tp) } tp } private def register(sym: Symbol) { while (result != NoSymbol && sym != result && !(sym isNestedIn result)) result = result.owner; } } class MissingAliasControl extends ControlThrowable val missingAliasException = new MissingAliasControl class MissingTypeControl extends ControlThrowable object adaptToNewRunMap extends TypeMap { private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = { if (phase.flatClasses) { sym } else if (sym.isModuleClass) { adaptToNewRun(pre, sym.sourceModule).moduleClass } else if ((pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass) { sym } else { var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) if (rebind0 == NoSymbol) { if (sym.isAliasType) throw missingAliasException if (settings.debug.value) println(pre+"."+sym+" does no longer exist, phase = "+phase) throw new MissingTypeControl // For build manager and presentation compiler purposes //assert(false, pre+"."+sym+" does no longer exist, phase = "+phase) } /** The two symbols have the same fully qualified name */ def corresponds(sym1: Symbol, sym2: Symbol): Boolean = sym1.name == sym2.name && (sym1.isPackageClass || corresponds(sym1.owner, sym2.owner)) if (!corresponds(sym.owner, rebind0.owner)) { if (settings.debug.value) log("ADAPT1 pre = "+pre+", sym = "+sym+sym.locationString+", rebind = "+rebind0+rebind0.locationString) val bcs = pre.baseClasses.dropWhile(bc => !corresponds(bc, sym.owner)); if (bcs.isEmpty) assert(pre.typeSymbol.isRefinementClass, pre) // if pre is a refinementclass it might be a structural type => OK to leave it in. else rebind0 = pre.baseType(bcs.head).member(sym.name) if (settings.debug.value) log( "ADAPT2 pre = " + pre + ", bcs.head = " + bcs.head + ", sym = " + sym+sym.locationString + ", rebind = " + rebind0 + ( if (rebind0 == NoSymbol) "" else rebind0.locationString ) ) } val rebind = rebind0.suchThat(sym => sym.isType || sym.isStable) if (rebind == NoSymbol) { if (settings.debug.value) log("" + phase + " " +phase.flatClasses+sym.owner+sym.name+" "+sym.isType) throw new MalformedType(pre, sym.nameString) } rebind } } def apply(tp: Type): Type = tp match { case ThisType(sym) => try { val sym1 = adaptToNewRun(sym.owner.thisType, sym) if (sym1 == sym) tp else ThisType(sym1) } catch { case ex: MissingTypeControl => tp } case SingleType(pre, sym) => if (sym.isPackage) tp else { val pre1 = this(pre) val sym1 = adaptToNewRun(pre1, sym) if ((pre1 eq pre) && (sym1 eq sym)) tp else singleType(pre1, sym1) } case TypeRef(pre, sym, args) => if (sym.isPackageClass) tp else { val pre1 = this(pre) val args1 = args mapConserve (this) try { val sym1 = adaptToNewRun(pre1, sym) if ((pre1 eq pre) && (sym1 eq sym) && (args1 eq args)/* && sym.isExternal*/) { tp } else if (sym1 == NoSymbol) { if (settings.debug.value) println("adapt fail: "+pre+" "+pre1+" "+sym) tp } else { copyTypeRef(tp, pre1, sym1, args1) } } catch { case ex: MissingAliasControl => apply(tp.dealias) case _: MissingTypeControl => tp } } case MethodType(params, restp) => val restp1 = this(restp) if (restp1 eq restp) tp else copyMethodType(tp, params, restp1) case NullaryMethodType(restp) => val restp1 = this(restp) if (restp1 eq restp) tp else NullaryMethodType(restp1) case PolyType(tparams, restp) => val restp1 = this(restp) if (restp1 eq restp) tp else PolyType(tparams, restp1) // Lukas: we need to check (together) whether we should also include parameter types // of PolyType and MethodType in adaptToNewRun case ClassInfoType(parents, decls, clazz) => if (clazz.isPackageClass) tp else { val parents1 = parents mapConserve (this) if (parents1 eq parents) tp else ClassInfoType(parents1, decls, clazz) } case RefinedType(parents, decls) => val parents1 = parents mapConserve (this) if (parents1 eq parents) tp else refinedType(parents1, tp.typeSymbol.owner, decls, tp.typeSymbol.owner.pos) case SuperType(_, _) => mapOver(tp) case TypeBounds(_, _) => mapOver(tp) case TypeVar(_, _) => mapOver(tp) case AnnotatedType(_,_,_) => mapOver(tp) case NotNullType(_) => mapOver(tp) case ExistentialType(_, _) => mapOver(tp) case _ => tp } } class SubTypePair(val tp1: Type, val tp2: Type) { override def hashCode = tp1.hashCode * 41 + tp2.hashCode override def equals(other: Any) = other match { case stp: SubTypePair => (tp1 =:= stp.tp1) && (tp2 =:= stp.tp2) case _ => false } override def toString = tp1+" <:'s variance conforms to sym2's variance * * If <arg>sym2 is invariant, sym1's variance is irrelevant. Otherwise they must be equal. */ def variancesMatch(sym1: Symbol, sym2: Symbol): Boolean = (sym2.variance==0 || sym1.variance==sym2.variance) // check that the type parameters <arg>hkargs to a higher-kinded type conform to the expected params hkparams def checkKindBoundsHK( hkargs: List[Symbol], arg: Symbol, param: Symbol, paramowner: Symbol, underHKParams: List[Symbol], withHKArgs: List[Symbol] ): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = { def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs) // @M sometimes hkargs != arg.typeParams, the symbol and the type may have very different type parameters val hkparams = param.typeParams if (settings.debug.value) { log("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) log("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) log("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) } if (!sameLength(hkargs, hkparams)) { if (arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded else {error = true; (List((arg, param)), Nil, Nil) } // shortcut: always set error, whether explainTypesOrNot } else { val _arityMismatches = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null val _varianceMismatches = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null val _stricterBounds = if (explainErrors) new ListBuffer[(Symbol, Symbol)] else null def varianceMismatch(a: Symbol, p: Symbol) { if(explainErrors) _varianceMismatches += ((a, p)) else error = true} def stricterBound(a: Symbol, p: Symbol) { if(explainErrors) _stricterBounds += ((a, p)) else error = true } def arityMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _arityMismatches ++= as } def varianceMismatches(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _varianceMismatches ++= as } def stricterBounds(as: Iterable[(Symbol, Symbol)]) { if(explainErrors) _stricterBounds ++= as } for ((hkarg, hkparam) <- hkargs zip hkparams) { if (hkparam.typeParams.isEmpty && hkarg.typeParams.isEmpty) { // base-case: kind * if (!variancesMatch(hkarg, hkparam)) varianceMismatch(hkarg, hkparam) // instantiateTypeParams(tparams, targs) --> higher-order bounds may contain references to type arguments // substSym(hkparams, hkargs) --> these types are going to be compared as types of kind * // --> their arguments use different symbols, but are conceptually the same // (could also replace the types by polytypes, but can't just strip the symbols, as ordering is lost then) val declaredBounds = transformedBounds(hkparam, paramowner) val declaredBoundsInst = bindHKParams(declaredBounds) val argumentBounds = transform(hkarg.info.bounds, owner) if (!(declaredBoundsInst <:< argumentBounds)) stricterBound(hkarg, hkparam) if (settings.debug.value) log( "checkKindBoundsHK base case: " + hkparam + " declared bounds: " + declaredBounds + " after instantiating earlier hkparams: " + declaredBoundsInst + "\n" + "checkKindBoundsHK base case: "+ hkarg + " has bounds: " + argumentBounds ) } else { if (settings.debug.value) log("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) val (am, vm, sb) = checkKindBoundsHK( hkarg.typeParams, hkarg, hkparam, paramowner, underHKParams ++ hkparam.typeParams, withHKArgs ++ hkarg.typeParams ) arityMismatches(am) varianceMismatches(vm) stricterBounds(sb) } if (!explainErrors && error) return (Nil, Nil, Nil) // stop as soon as we encountered an error } if (!explainErrors) (Nil, Nil, Nil) else (_arityMismatches.toList, _varianceMismatches.toList, _stricterBounds.toList) } } val errors = new ListBuffer[(Type, Symbol, List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)])] if (tparams.nonEmpty || targs.nonEmpty) log("checkKindBounds0(" + tparams + ", " + targs + ", " + pre + ", " + owner + ", " + explainErrors + ")") for { (tparam, targ) <- tparams zip targs // Prevent WildcardType from causing kind errors, as typevars may be higher-order if (targ != WildcardType) && (targ.isHigherKinded || tparam.typeParams.nonEmpty) } { // @M must use the typeParams of the *type* targ, not of the *symbol* of targ!! targ.typeSymbolDirect.info // force symbol load for #4205 val tparamsHO = targ.typeParams val (arityMismatches, varianceMismatches, stricterBounds) = ( // NOTE: *not* targ.typeSymbol, which normalizes checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) ) if (explainErrors) { if (arityMismatches.nonEmpty || varianceMismatches.nonEmpty || stricterBounds.nonEmpty) { errors += ((targ, tparam, arityMismatches, varianceMismatches, stricterBounds)) } } else if (error) return List((NoType, NoSymbol, Nil, Nil, Nil)) } errors.toList } // Errors and Diagnostics ----------------------------------------------------- /** A throwable signalling a type error */ class TypeError(var pos: Position, val msg: String) extends Throwable(msg) { def this(msg: String) = this(NoPosition, msg) } class NoCommonType(tps: List[Type]) extends Throwable( "lub/glb of incompatible types: " + tps.mkString("", " and ", "")) with ControlThrowable /** A throwable signalling a malformed type */ class MalformedType(msg: String) extends TypeError(msg) { def this(pre: Type, tp: String) = this("malformed type: " + pre + "#" + tp) } /** An exception signalling a variance annotation/usage conflict */ class VarianceError(msg: String) extends TypeError(msg) /** The current indentation string for traces */ private var indent: String = "" /** Perform operation `p' on arguments `tp1', * `arg2' and print trace of computation. */ private def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = { Console.println(indent + tp1 + " " + op + " " + arg2 + "?" /* + "("+tp1.getClass+","+arg2.asInstanceOf[AnyRef].getClass+")"*/) indent = indent + " " val result = p(tp1, arg2) indent = indent dropRight 2 Console.println(indent + result) result } /** If option `explaintypes' is set, print a subtype trace for * `found <:< required'. */ def explainTypes(found: Type, required: Type) { if (settings.explaintypes.value) withTypesExplained(found <:< required) } /** If option `explaintypes' is set, print a subtype trace for * `op(found, required)'. */ def explainTypes(op: (Type, Type) => Any, found: Type, required: Type) { if (settings.explaintypes.value) withTypesExplained(op(found, required)) } /** Execute `op' while printing a trace of the operations on types executed. */ def withTypesExplained[A](op: => A): A = { val s = explainSwitch try { explainSwitch = true; op } finally { explainSwitch = s } } def objToAny(tp: Type): Type = if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe else tp val shorthands = Set( "scala.collection.immutable.List", "scala.collection.immutable.Nil", "scala.collection.Seq", "scala.collection.Traversable", "scala.collection.Iterable", "scala.collection.mutable.StringBuilder", "scala.collection.IndexedSeq", "scala.collection.Iterator") }

Other Scala examples (source code examples)

Here is a short list of links related to this Scala Types.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.